scripts: add opencode model listing sync helper
Queries lmstudio and ollama /v1/models endpoints to keep opencode.json model entries up to date, preserving manual overrides. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -174,6 +174,7 @@ Format: `path | goal | usage`. This section is intentionally compact so `what` c
|
||||
- `scripts/setup/mount_container` | goal: mount or unmount LUKS container files listed in `.containers` manifests | usage: `scripts/setup/mount_container mount`
|
||||
- `scripts/setup/share.sh` | goal: run a local sharing workflow | usage: `scripts/setup/share.sh`
|
||||
- `scripts/setup/terminal-logs.sh` | goal: configure or collect terminal logging | usage: `scripts/setup/terminal-logs.sh`
|
||||
- `scripts/setup/update-models.sh` | goal: sync lmstudio and ollama model listings into opencode.json | usage: `scripts/setup/update-models.sh [lmstudio|ollama]`
|
||||
- `scripts/windows/Get-ZimmermanTools.ps1` | goal: download Zimmerman forensic tools on Windows | usage: `powershell -File scripts/windows/Get-ZimmermanTools.ps1`
|
||||
- `scripts/windows/getscreen.psm1` | goal: provide PowerShell screen-capture helpers | usage: `Import-Module scripts/windows/getscreen.psm1`
|
||||
- `scripts/windows/sbom.ps1` | goal: generate or inspect SBOM-related data in PowerShell | usage: `powershell -File scripts/windows/sbom.ps1`
|
||||
@@ -298,7 +299,7 @@ Format: `path | goal | usage`. This section is intentionally compact so `what` c
|
||||
|
||||
- `scripts/proxy/`: proxy environment propagation for apt, bash, and services.
|
||||
- `scripts/display/`: display and touchpad toggles, including named `xrandr` screen-layout presets.
|
||||
- `scripts/setup/`: host setup helpers such as automounting, sharing, terminal logging, encrypted container mounting, and Ubuntu telemetry disabling.
|
||||
- `scripts/setup/`: host setup helpers such as automounting, sharing, terminal logging, encrypted container mounting, Ubuntu telemetry disabling, and model listing sync for opencode.
|
||||
- `scripts/windows/`: PowerShell helpers, including Zimmerman tools bootstrap and SBOM-related work.
|
||||
|
||||
## `archive/`: Reference Material
|
||||
|
||||
151
scripts/setup/update-models.sh
Executable file
151
scripts/setup/update-models.sh
Executable file
@@ -0,0 +1,151 @@
|
||||
#!/usr/bin/env bash
|
||||
# Updates lmstudio and/or ollama model listings in opencode.json
|
||||
# by querying their /v1/models endpoints.
|
||||
#
|
||||
# Usage:
|
||||
# ./update-models.sh # update both
|
||||
# ./update-models.sh lmstudio # update only lmstudio
|
||||
# ./update-models.sh ollama # update only ollama
|
||||
#
|
||||
# Requires: jq, curl
|
||||
|
||||
set -uo pipefail
|
||||
|
||||
CONFIG="${OPENCODE_CONFIG:-${HOME}/.config/opencode/opencode.json}"
|
||||
|
||||
if [[ ! -f "$CONFIG" ]]; then
|
||||
echo "Error: config not found at $CONFIG" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if ! command -v jq &>/dev/null; then
|
||||
echo "Error: jq is required. Install with: brew install jq" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Map provider name -> base URL (read from config)
|
||||
get_base_url() {
|
||||
jq -r ".provider.${1}.options.baseURL // empty" "$CONFIG"
|
||||
}
|
||||
|
||||
# Map provider name -> display label (read from config)
|
||||
get_display_name() {
|
||||
jq -r ".provider.${1}.name // \"${1}\"" "$CONFIG"
|
||||
}
|
||||
|
||||
# Fetch models from API endpoint and build the opencode models object.
|
||||
# Preserves any existing entries that have extra metadata (limits, modalities, variants)
|
||||
# beyond just a name — so your manual overrides aren't lost.
|
||||
build_models_json() {
|
||||
local provider="$1"
|
||||
local base_url="$2"
|
||||
local display_name="$3"
|
||||
|
||||
local api_response
|
||||
api_response=$(curl -sf --connect-timeout 5 "${base_url}/models" 2>/dev/null) || {
|
||||
echo "Error: could not reach ${base_url}/models — is ${provider} running?" >&2
|
||||
return 1
|
||||
}
|
||||
|
||||
# Get list of model IDs from API
|
||||
local model_ids
|
||||
model_ids=$(echo "$api_response" | jq -r '.data[].id' | sort)
|
||||
|
||||
if [[ -z "$model_ids" ]]; then
|
||||
echo "Warning: no models returned from ${provider}" >&2
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Get existing models object (to preserve manual overrides)
|
||||
local existing
|
||||
existing=$(jq ".provider.${provider}.models // {}" "$CONFIG")
|
||||
|
||||
# Build new models object
|
||||
local new_models="{}"
|
||||
while IFS= read -r model_id; do
|
||||
[[ -z "$model_id" ]] && continue
|
||||
|
||||
# Check if this model has extra config beyond just "name"
|
||||
local existing_entry
|
||||
existing_entry=$(echo "$existing" | jq -r --arg id "$model_id" '.[$id] // empty')
|
||||
|
||||
local has_extras="false"
|
||||
if [[ -n "$existing_entry" ]]; then
|
||||
local key_count
|
||||
key_count=$(echo "$existing_entry" | jq 'keys | length')
|
||||
if [[ "$key_count" -gt 1 ]]; then
|
||||
has_extras="true"
|
||||
fi
|
||||
fi
|
||||
|
||||
if [[ "$has_extras" == "true" ]]; then
|
||||
# Preserve existing entry with overrides, just update the name
|
||||
new_models=$(echo "$new_models" | jq \
|
||||
--arg id "$model_id" \
|
||||
--argjson entry "$existing_entry" \
|
||||
--arg name "${model_id} (${display_name})" \
|
||||
'.[$id] = ($entry | .name = $name)')
|
||||
else
|
||||
# Simple entry with just a name
|
||||
new_models=$(echo "$new_models" | jq \
|
||||
--arg id "$model_id" \
|
||||
--arg name "${model_id} (${display_name})" \
|
||||
'.[$id] = { "name": $name }')
|
||||
fi
|
||||
done <<< "$model_ids"
|
||||
|
||||
echo "$new_models"
|
||||
}
|
||||
|
||||
update_provider() {
|
||||
local provider="$1"
|
||||
|
||||
# Check provider exists in config
|
||||
if ! jq -e ".provider.${provider}" "$CONFIG" &>/dev/null; then
|
||||
echo "Skipping ${provider}: not configured in opencode.json" >&2
|
||||
return 0
|
||||
fi
|
||||
|
||||
local base_url
|
||||
base_url=$(get_base_url "$provider")
|
||||
if [[ -z "$base_url" ]]; then
|
||||
echo "Skipping ${provider}: no baseURL configured" >&2
|
||||
return 0
|
||||
fi
|
||||
|
||||
local display_name
|
||||
display_name=$(get_display_name "$provider")
|
||||
|
||||
echo "Updating ${provider} models from ${base_url}..."
|
||||
|
||||
local new_models
|
||||
new_models=$(build_models_json "$provider" "$base_url" "$display_name") || return 1
|
||||
|
||||
local count
|
||||
count=$(echo "$new_models" | jq 'keys | length')
|
||||
|
||||
# Update config in-place
|
||||
local tmp
|
||||
tmp=$(mktemp)
|
||||
jq --argjson models "$new_models" \
|
||||
".provider.${provider}.models = \$models" \
|
||||
"$CONFIG" > "$tmp" && mv "$tmp" "$CONFIG"
|
||||
|
||||
echo " ✓ ${provider}: ${count} models synced"
|
||||
}
|
||||
|
||||
# --- Main ---
|
||||
|
||||
targets=("${@:-lmstudio ollama}")
|
||||
errors=0
|
||||
|
||||
for target in $targets; do
|
||||
update_provider "$target" || ((errors++))
|
||||
done
|
||||
|
||||
if [[ "$errors" -gt 0 ]]; then
|
||||
echo "Done with ${errors} error(s). Run 'opencode models' to verify."
|
||||
exit 1
|
||||
else
|
||||
echo "Done. Run 'opencode models' to verify."
|
||||
fi
|
||||
Reference in New Issue
Block a user