bin/ 230 CLI tools (ask-*, br-*, agent-*, roadid, carpool) scripts/ 99 automation scripts fleet/ Node configs and deployment workers/ Cloudflare Worker sources (roadpay, road-search, squad webhooks) roadc/ RoadC programming language roadnet/ Mesh network (5 APs, WireGuard) operator/ Memory system scripts config/ System configs dotfiles/ Shell configs docs/ Documentation BlackRoad OS — Pave Tomorrow. RoadChain-SHA2048: d1a24f55318d338b RoadChain-Identity: alexa@sovereign RoadChain-Full: d1a24f55318d338b24b60bad7be39286379c76ae5470817482100cb0ddbbcb97e147d07ac7243da0a9f0363e4e5c833d612b9c0df3a3cd20802465420278ef74875a5b77f55af6fe42a931b8b635b3d0d0b6bde9abf33dc42eea52bc03c951406d8cbe49f1a3d29b26a94dade05e9477f34a7d4d4c6ec4005c3c2ac54e73a68440c512c8e83fd9b1fe234750b898ef8f4032c23db173961fe225e67a0432b5293a9714f76c5c57ed5fdf35b9fb40fd73c03ebf88b7253c6a0575f5afb6a6b49b3bda310602fb1ef676859962dad2aebbb2875814b30eee0a8ba195e482d4cbc91d8819e7f38f6db53e8063401649c77bb994371473cabfb917fb53e8cbe73d60
202 lines
7.2 KiB
Bash
Executable File
202 lines
7.2 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# ============================================================================
|
|
# BLACKROAD OS, INC. - PROPRIETARY AND CONFIDENTIAL
|
|
# Copyright (c) 2025-2026 BlackRoad OS, Inc. All Rights Reserved.
|
|
# ============================================================================
|
|
# br-models - BlackRoad AI Model Registry
|
|
# Discover, catalog, and manage models across the fleet
|
|
# Usage: br-models <list|scan|pull|remove|info>
|
|
set -eo pipefail
|
|
|
|
source "$HOME/.blackroad/config/nodes.sh" 2>/dev/null || true
|
|
|
|
MODELS_DIR="$HOME/.blackroad/ai"
|
|
MODELS_DB="$MODELS_DIR/models.db"
|
|
mkdir -p "$MODELS_DIR"
|
|
|
|
_sql() { sqlite3 "$MODELS_DB" "$@" 2>/dev/null; }
|
|
_sql_escape() { echo "$1" | sed "s/'/''/g"; }
|
|
|
|
OLLAMA_NODES=(cecilia lucidia alice octavia)
|
|
|
|
init_db() {
|
|
_sql <<'SQL'
|
|
CREATE TABLE IF NOT EXISTS models (
|
|
id TEXT PRIMARY KEY,
|
|
name TEXT,
|
|
node TEXT,
|
|
size TEXT,
|
|
parameter_size TEXT,
|
|
quantization TEXT,
|
|
family TEXT,
|
|
format TEXT,
|
|
modified DATETIME,
|
|
discovered DATETIME DEFAULT CURRENT_TIMESTAMP
|
|
);
|
|
CREATE TABLE IF NOT EXISTS model_nodes (
|
|
model TEXT,
|
|
node TEXT,
|
|
status TEXT DEFAULT 'available',
|
|
last_checked DATETIME DEFAULT CURRENT_TIMESTAMP,
|
|
PRIMARY KEY (model, node)
|
|
);
|
|
CREATE INDEX IF NOT EXISTS idx_model_name ON models(name);
|
|
PRAGMA journal_mode=WAL;
|
|
PRAGMA busy_timeout=5000;
|
|
SQL
|
|
}
|
|
|
|
cmd_scan() {
|
|
printf '%bScanning fleet for AI models...%b\n\n' "$AMBER" "$RESET"
|
|
|
|
local total=0
|
|
for node in "${OLLAMA_NODES[@]}"; do
|
|
local ip="${NODE_IP[$node]:-}"
|
|
[[ -z "$ip" ]] && continue
|
|
|
|
printf ' %-10s (%s): ' "$node" "$ip"
|
|
|
|
local tags
|
|
tags=$(curl -sf --connect-timeout 3 "http://${ip}:11434/api/tags" 2>/dev/null)
|
|
if [[ -z "$tags" ]]; then
|
|
printf '%boffline%b\n' "$RED" "$RESET"
|
|
continue
|
|
fi
|
|
|
|
local count
|
|
count=$(echo "$tags" | jq '.models | length' 2>/dev/null || echo "0")
|
|
printf '%b%s models%b\n' "$GREEN" "$count" "$RESET"
|
|
total=$((total + count))
|
|
|
|
# Store each model
|
|
echo "$tags" | jq -r '.models[] | [.name, .size // 0, .details.parameter_size // "", .details.quantization_level // "", .details.family // "", .details.format // "", .modified_at // ""] | @tsv' 2>/dev/null | \
|
|
while IFS=$'\t' read -r name size param_size quant family format modified; do
|
|
local id="${node}:${name}"
|
|
local size_human
|
|
if [[ "$size" -gt 1073741824 ]]; then
|
|
size_human="$(echo "scale=1; $size/1073741824" | bc 2>/dev/null || echo "?")GB"
|
|
elif [[ "$size" -gt 1048576 ]]; then
|
|
size_human="$(echo "scale=0; $size/1048576" | bc 2>/dev/null || echo "?")MB"
|
|
else
|
|
size_human="${size}B"
|
|
fi
|
|
|
|
_sql "INSERT OR REPLACE INTO models (id, name, node, size, parameter_size, quantization, family, format, modified)
|
|
VALUES ('$(_sql_escape "$id")', '$(_sql_escape "$name")', '$node', '$size_human', '$(_sql_escape "$param_size")', '$(_sql_escape "$quant")', '$(_sql_escape "$family")', '$(_sql_escape "$format")', '$(_sql_escape "$modified")')"
|
|
_sql "INSERT OR REPLACE INTO model_nodes (model, node, status, last_checked)
|
|
VALUES ('$(_sql_escape "$name")', '$node', 'available', datetime('now'))"
|
|
done
|
|
done
|
|
|
|
printf '\n %bTotal: %d models across fleet%b\n' "$PINK" "$total" "$RESET"
|
|
}
|
|
|
|
cmd_list() {
|
|
local filter="${1:-}"
|
|
printf '%b%-30s %-10s %-8s %-10s %-12s%b\n' "$BLUE" "MODEL" "NODE" "SIZE" "PARAMS" "QUANT" "$RESET"
|
|
printf '%-30s %-10s %-8s %-10s %-12s\n' "─────" "────" "────" "──────" "─────"
|
|
|
|
local where=""
|
|
[[ -n "$filter" ]] && where="WHERE name LIKE '%$(_sql_escape "$filter")%'"
|
|
|
|
_sql "SELECT name, node, size, parameter_size, quantization FROM models $where ORDER BY name, node" | \
|
|
while IFS='|' read -r name node size params quant; do
|
|
printf '%-30s %-10s %-8s %-10s %-12s\n' "$name" "$node" "$size" "${params:-—}" "${quant:-—}"
|
|
done
|
|
}
|
|
|
|
cmd_where() {
|
|
local model="${1:?model name required}"
|
|
printf '%bNodes with %s:%b\n' "$BLUE" "$model" "$RESET"
|
|
_sql "SELECT node, status, last_checked FROM model_nodes WHERE model LIKE '%$(_sql_escape "$model")%' ORDER BY node" | \
|
|
while IFS='|' read -r node status checked; do
|
|
local status_color="$GREEN"
|
|
[[ "$status" != "available" ]] && status_color="$RED"
|
|
printf ' %-10s %b%-10s%b (checked: %s)\n' "$node" "$status_color" "$status" "$RESET" "$checked"
|
|
done
|
|
}
|
|
|
|
cmd_pull() {
|
|
local model="${1:?model name required}"
|
|
local node="${2:?node required}"
|
|
local ip="${NODE_IP[$node]:-}"
|
|
[[ -z "$ip" ]] && { echo "Unknown node: $node" >&2; return 1; }
|
|
|
|
printf '%bPulling %s on %s (%s)...%b\n' "$AMBER" "$model" "$node" "$ip" "$RESET"
|
|
curl -sf "http://${ip}:11434/api/pull" \
|
|
-d "{\"name\":\"$model\"}" 2>/dev/null | \
|
|
jq -r '.status // empty' 2>/dev/null | tail -1
|
|
|
|
printf '%bDone. Run: br-models scan%b\n' "$GREEN" "$RESET"
|
|
}
|
|
|
|
cmd_remove() {
|
|
local model="${1:?model name required}"
|
|
local node="${2:?node required}"
|
|
local ip="${NODE_IP[$node]:-}"
|
|
[[ -z "$ip" ]] && { echo "Unknown node: $node" >&2; return 1; }
|
|
|
|
printf '%bRemoving %s from %s...%b\n' "$AMBER" "$model" "$node" "$RESET"
|
|
curl -sf -X DELETE "http://${ip}:11434/api/delete" \
|
|
-d "{\"name\":\"$model\"}" 2>/dev/null
|
|
|
|
_sql "DELETE FROM models WHERE name='$(_sql_escape "$model")' AND node='$node'"
|
|
_sql "DELETE FROM model_nodes WHERE model='$(_sql_escape "$model")' AND node='$node'"
|
|
printf '%bRemoved%b\n' "$GREEN" "$RESET"
|
|
}
|
|
|
|
cmd_summary() {
|
|
printf '%bModel Registry Summary%b\n\n' "$PINK" "$RESET"
|
|
|
|
printf ' Unique models: %s\n' "$(_sql "SELECT COUNT(DISTINCT name) FROM models")"
|
|
printf ' Total instances: %s\n' "$(_sql "SELECT COUNT(*) FROM models")"
|
|
printf ' Fleet nodes: %s\n\n' "$(_sql "SELECT COUNT(DISTINCT node) FROM models")"
|
|
|
|
printf ' %bBy family:%b\n' "$BLUE" "$RESET"
|
|
_sql "SELECT COALESCE(family,'unknown'), COUNT(*) FROM models GROUP BY family ORDER BY COUNT(*) DESC LIMIT 10" | \
|
|
while IFS='|' read -r family cnt; do
|
|
printf ' %-20s %d\n' "$family" "$cnt"
|
|
done
|
|
|
|
echo ""
|
|
printf ' %bBy node:%b\n' "$BLUE" "$RESET"
|
|
_sql "SELECT node, COUNT(*) FROM models GROUP BY node ORDER BY COUNT(*) DESC" | \
|
|
while IFS='|' read -r node cnt; do
|
|
printf ' %-10s %d models\n' "$node" "$cnt"
|
|
done
|
|
}
|
|
|
|
usage() {
|
|
cat <<EOF
|
|
${PINK}br-models${RESET} - BlackRoad AI Model Registry
|
|
|
|
${BLUE}COMMANDS:${RESET}
|
|
scan Discover models across fleet
|
|
list [filter] List all models (optional filter)
|
|
where <model> Show which nodes have a model
|
|
pull <model> <node> Pull model to a node
|
|
remove <model> <node> Remove model from a node
|
|
summary Registry statistics
|
|
|
|
${GREEN}EXAMPLES:${RESET}
|
|
br-models scan Survey all Ollama nodes
|
|
br-models list llama Find all llama models
|
|
br-models where mistral Which nodes have mistral?
|
|
br-models pull phi3 lucidia Pull phi3 to lucidia
|
|
br-models summary Fleet model stats
|
|
EOF
|
|
}
|
|
|
|
[[ -f "$MODELS_DB" ]] || init_db
|
|
|
|
case "${1:-}" in
|
|
scan) cmd_scan ;;
|
|
list|ls) cmd_list "${2:-}" ;;
|
|
where|w) cmd_where "${2:?model name required}" ;;
|
|
pull) cmd_pull "${2:?model}" "${3:?node}" ;;
|
|
remove|rm) cmd_remove "${2:?model}" "${3:?node}" ;;
|
|
summary|s) cmd_summary ;;
|
|
-h|--help|help|"") usage ;;
|
|
*) cmd_list "$1" ;; # default to search
|
|
esac
|