import type { Command } from "commander"; import { modelsAliasesAddCommand, modelsAliasesListCommand, modelsAliasesRemoveCommand, modelsAuthAddCommand, modelsAuthPasteTokenCommand, modelsAuthSetupTokenCommand, modelsFallbacksAddCommand, modelsFallbacksClearCommand, modelsFallbacksListCommand, modelsFallbacksRemoveCommand, modelsImageFallbacksAddCommand, modelsImageFallbacksClearCommand, modelsImageFallbacksListCommand, modelsImageFallbacksRemoveCommand, modelsListCommand, modelsScanCommand, modelsSetCommand, modelsSetImageCommand, modelsStatusCommand, } from "../commands/models.js"; import { defaultRuntime } from "../runtime.js"; export function registerModelsCli(program: Command) { const models = program .command("models") .description("Model discovery, scanning, and configuration") .option( "--status-json", "Output JSON (alias for `models status --json`)", false, ) .option( "--status-plain", "Plain output (alias for `models status --plain`)", false, ); models .command("list") .description("List models (configured by default)") .option("--all", "Show full model catalog", false) .option("--local", "Filter to local models", false) .option("--provider ", "Filter by provider") .option("--json", "Output JSON", false) .option("--plain", "Plain line output", false) .action(async (opts) => { try { await modelsListCommand(opts, defaultRuntime); } catch (err) { defaultRuntime.error(String(err)); defaultRuntime.exit(1); } }); models .command("status") .description("Show configured model state") .option("--json", "Output JSON", false) .option("--plain", "Plain output", false) .option( "--check", "Exit non-zero if auth is expiring/expired (1=expired/missing, 2=expiring)", false, ) .action(async (opts) => { try { await modelsStatusCommand(opts, defaultRuntime); } catch (err) { defaultRuntime.error(String(err)); defaultRuntime.exit(1); } }); models .command("set") .description("Set the default model") .argument("", "Model id or alias") .action(async (model: string) => { try { await modelsSetCommand(model, defaultRuntime); } catch (err) { defaultRuntime.error(String(err)); defaultRuntime.exit(1); } }); models .command("set-image") .description("Set the image model") .argument("", "Model id or alias") .action(async (model: string) => { try { await modelsSetImageCommand(model, defaultRuntime); } catch (err) { defaultRuntime.error(String(err)); defaultRuntime.exit(1); } }); const aliases = models.command("aliases").description("Manage model aliases"); aliases .command("list") .description("List model aliases") .option("--json", "Output JSON", false) .option("--plain", "Plain output", false) .action(async (opts) => { try { await modelsAliasesListCommand(opts, defaultRuntime); } catch (err) { defaultRuntime.error(String(err)); defaultRuntime.exit(1); } }); aliases .command("add") .description("Add or update a model alias") .argument("", "Alias name") .argument("", "Model id or alias") .action(async (alias: string, model: string) => { try { await modelsAliasesAddCommand(alias, model, defaultRuntime); } catch (err) { defaultRuntime.error(String(err)); defaultRuntime.exit(1); } }); aliases .command("remove") .description("Remove a model alias") .argument("", "Alias name") .action(async (alias: string) => { try { await modelsAliasesRemoveCommand(alias, defaultRuntime); } catch (err) { defaultRuntime.error(String(err)); defaultRuntime.exit(1); } }); const fallbacks = models .command("fallbacks") .description("Manage model fallback list"); fallbacks .command("list") .description("List fallback models") .option("--json", "Output JSON", false) .option("--plain", "Plain output", false) .action(async (opts) => { try { await modelsFallbacksListCommand(opts, defaultRuntime); } catch (err) { defaultRuntime.error(String(err)); defaultRuntime.exit(1); } }); fallbacks .command("add") .description("Add a fallback model") .argument("", "Model id or alias") .action(async (model: string) => { try { await modelsFallbacksAddCommand(model, defaultRuntime); } catch (err) { defaultRuntime.error(String(err)); defaultRuntime.exit(1); } }); fallbacks .command("remove") .description("Remove a fallback model") .argument("", "Model id or alias") .action(async (model: string) => { try { await modelsFallbacksRemoveCommand(model, defaultRuntime); } catch (err) { defaultRuntime.error(String(err)); defaultRuntime.exit(1); } }); fallbacks .command("clear") .description("Clear all fallback models") .action(async () => { try { await modelsFallbacksClearCommand(defaultRuntime); } catch (err) { defaultRuntime.error(String(err)); defaultRuntime.exit(1); } }); const imageFallbacks = models .command("image-fallbacks") .description("Manage image model fallback list"); imageFallbacks .command("list") .description("List image fallback models") .option("--json", "Output JSON", false) .option("--plain", "Plain output", false) .action(async (opts) => { try { await modelsImageFallbacksListCommand(opts, defaultRuntime); } catch (err) { defaultRuntime.error(String(err)); defaultRuntime.exit(1); } }); imageFallbacks .command("add") .description("Add an image fallback model") .argument("", "Model id or alias") .action(async (model: string) => { try { await modelsImageFallbacksAddCommand(model, defaultRuntime); } catch (err) { defaultRuntime.error(String(err)); defaultRuntime.exit(1); } }); imageFallbacks .command("remove") .description("Remove an image fallback model") .argument("", "Model id or alias") .action(async (model: string) => { try { await modelsImageFallbacksRemoveCommand(model, defaultRuntime); } catch (err) { defaultRuntime.error(String(err)); defaultRuntime.exit(1); } }); imageFallbacks .command("clear") .description("Clear all image fallback models") .action(async () => { try { await modelsImageFallbacksClearCommand(defaultRuntime); } catch (err) { defaultRuntime.error(String(err)); defaultRuntime.exit(1); } }); models .command("scan") .description("Scan OpenRouter free models for tools + images") .option("--min-params ", "Minimum parameter size (billions)") .option("--max-age-days ", "Skip models older than N days") .option("--provider ", "Filter by provider prefix") .option("--max-candidates ", "Max fallback candidates", "6") .option("--timeout ", "Per-probe timeout in ms") .option("--concurrency ", "Probe concurrency") .option("--no-probe", "Skip live probes; list free candidates only") .option("--yes", "Accept defaults without prompting", false) .option("--no-input", "Disable prompts (use defaults)") .option("--set-default", "Set agent.model to the first selection", false) .option( "--set-image", "Set agent.imageModel to the first image selection", false, ) .option("--json", "Output JSON", false) .action(async (opts) => { try { await modelsScanCommand(opts, defaultRuntime); } catch (err) { defaultRuntime.error(String(err)); defaultRuntime.exit(1); } }); models.action(async (opts) => { try { await modelsStatusCommand( { json: Boolean(opts?.statusJson), plain: Boolean(opts?.statusPlain), }, defaultRuntime, ); } catch (err) { defaultRuntime.error(String(err)); defaultRuntime.exit(1); } }); const auth = models.command("auth").description("Manage model auth profiles"); auth .command("add") .description("Interactive auth helper (setup-token or paste token)") .action(async () => { try { await modelsAuthAddCommand({}, defaultRuntime); } catch (err) { defaultRuntime.error(String(err)); defaultRuntime.exit(1); } }); auth .command("setup-token") .description("Run a provider CLI to create/sync a token (TTY required)") .option("--provider ", "Provider id (default: anthropic)") .option("--yes", "Skip confirmation", false) .action(async (opts) => { try { await modelsAuthSetupTokenCommand( { provider: opts.provider as string | undefined, yes: Boolean(opts.yes), }, defaultRuntime, ); } catch (err) { defaultRuntime.error(String(err)); defaultRuntime.exit(1); } }); auth .command("paste-token") .description("Paste a token into auth-profiles.json and update config") .requiredOption("--provider ", "Provider id (e.g. anthropic)") .option("--profile-id ", "Auth profile id (default: :manual)") .option( "--expires-in ", "Optional expiry duration (e.g. 365d, 12h). Stored as absolute expiresAt.", ) .action(async (opts) => { try { await modelsAuthPasteTokenCommand( { provider: opts.provider as string | undefined, profileId: opts.profileId as string | undefined, expiresIn: opts.expiresIn as string | undefined, }, defaultRuntime, ); } catch (err) { defaultRuntime.error(String(err)); defaultRuntime.exit(1); } }); }