@openeryc/pi-coding-agent 0.75.56 → 0.75.58

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (35) hide show
  1. package/CHANGELOG.md +18 -0
  2. package/dist/core/keybindings.d.ts +10 -0
  3. package/dist/core/keybindings.d.ts.map +1 -1
  4. package/dist/core/keybindings.js +8 -0
  5. package/dist/core/keybindings.js.map +1 -1
  6. package/dist/core/model-registry.d.ts +6 -0
  7. package/dist/core/model-registry.d.ts.map +1 -1
  8. package/dist/core/model-registry.js +38 -0
  9. package/dist/core/model-registry.js.map +1 -1
  10. package/dist/modes/interactive/components/login-dialog.d.ts +7 -1
  11. package/dist/modes/interactive/components/login-dialog.d.ts.map +1 -1
  12. package/dist/modes/interactive/components/login-dialog.js +14 -4
  13. package/dist/modes/interactive/components/login-dialog.js.map +1 -1
  14. package/dist/modes/interactive/components/model-hub.d.ts +2 -0
  15. package/dist/modes/interactive/components/model-hub.d.ts.map +1 -1
  16. package/dist/modes/interactive/components/model-hub.js +30 -8
  17. package/dist/modes/interactive/components/model-hub.js.map +1 -1
  18. package/dist/modes/interactive/goal-runner-utils.d.ts +11 -0
  19. package/dist/modes/interactive/goal-runner-utils.d.ts.map +1 -0
  20. package/dist/modes/interactive/goal-runner-utils.js +39 -0
  21. package/dist/modes/interactive/goal-runner-utils.js.map +1 -0
  22. package/dist/modes/interactive/interactive-mode.d.ts +4 -0
  23. package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  24. package/dist/modes/interactive/interactive-mode.js +77 -29
  25. package/dist/modes/interactive/interactive-mode.js.map +1 -1
  26. package/docs/models.md +1 -1
  27. package/examples/extensions/custom-provider-anthropic/package-lock.json +2 -2
  28. package/examples/extensions/custom-provider-anthropic/package.json +1 -1
  29. package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
  30. package/examples/extensions/sandbox/package-lock.json +2 -2
  31. package/examples/extensions/sandbox/package.json +1 -1
  32. package/examples/extensions/with-deps/package-lock.json +2 -2
  33. package/examples/extensions/with-deps/package.json +1 -1
  34. package/npm-shrinkwrap.json +12 -12
  35. package/package.json +4 -4
@@ -1 +1 @@
1
- {"version":3,"file":"model-hub.d.ts","sourceRoot":"","sources":["../../../../src/modes/interactive/components/model-hub.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Unified model hub: Select current model, manage cycle whitelist, manage custom providers.\n */\n\nimport { type Model, modelsAreEqual } from \"@openeryc/pi-ai\";\nimport {\n\tContainer,\n\ttype Focusable,\n\tfuzzyFilter,\n\tgetKeybindings,\n\tInput,\n\tKey,\n\tmatchesKey,\n\tSpacer,\n\tText,\n\ttype TUI,\n} from \"@openeryc/pi-tui\";\nimport type { ModelRegistry } from \"../../../core/model-registry.ts\";\nimport type { SettingsManager } from \"../../../core/settings-manager.ts\";\nimport { theme } from \"../theme/theme.ts\";\nimport { DynamicBorder } from \"./dynamic-border.ts\";\nimport { keyHint, keyText } from \"./keybinding-hints.ts\";\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\nexport type ModelHubTab = \"select\" | \"cycle\" | \"manage\";\n\ninterface ModelItem {\n\tprovider: string;\n\tid: string;\n\tmodel: Model<any>;\n}\n\ninterface ScopedModelItem {\n\tmodel: Model<any>;\n\tthinkingLevel?: string;\n}\n\ntype EnabledIds = string[] | null;\n\ntype SelectRow =\n\t| { kind: \"header\"; label: string }\n\t| { kind: \"collapsed\"; provider: string; count: number }\n\t| { kind: \"model\"; item: ModelItem; badges: string };\n\ntype ManageRow =\n\t| {\n\t\t\tkind: \"provider\";\n\t\t\tsource: \"models_json\" | \"openai_compatible\";\n\t\t\tid: string;\n\t\t\tlabel: string;\n\t\t\tdetail: string;\n\t }\n\t| { kind: \"action\"; action: \"add\"; label: string };\n\nexport interface ModelHubCallbacks {\n\tonSelectModel: (model: Model<any>) => void | Promise<void>;\n\tonCancel: () => void;\n\t/** Cycle tab: session-only scope change */\n\tonCycleChange: (enabledModelIds: string[] | null) => void | Promise<void>;\n\t/** Cycle tab: persist to settings */\n\tonCyclePersist: (enabledModelIds: string[] | null) => void | Promise<void>;\n\t/** Manage tab: open add-provider wizard (writes models.json by default) */\n\tonManageAdd: () => void | Promise<void>;\n\t/** Manage tab: edit existing custom/openai_compatible provider */\n\tonManageEdit: (source: \"models_json\" | \"openai_compatible\", providerId: string) => void | Promise<void>;\n\t/** Manage tab: remove provider */\n\tonManageRemove: (source: \"models_json\" | \"openai_compatible\", providerId: string) => void | Promise<void>;\n}\n\n// ---------------------------------------------------------------------------\n// Pure helpers (exported for tests)\n// ---------------------------------------------------------------------------\n\nexport function formatTokenCount(count: number): string {\n\tif (count >= 1_000_000) {\n\t\tconst millions = count / 1_000_000;\n\t\treturn millions % 1 === 0 ? `${millions}M` : `${millions.toFixed(1)}M`;\n\t}\n\tif (count >= 1_000) {\n\t\tconst thousands = count / 1_000;\n\t\treturn thousands % 1 === 0 ? `${thousands}K` : `${thousands.toFixed(1)}K`;\n\t}\n\treturn count.toString();\n}\n\nfunction modelBadges(model: Model<any>): string {\n\tconst parts: string[] = [];\n\tif (model.reasoning) parts.push(\"R\");\n\tparts.push(formatTokenCount(model.contextWindow));\n\treturn parts.join(\" \");\n}\n\nfunction isEnabled(enabledIds: EnabledIds, id: string): boolean {\n\treturn enabledIds === null || enabledIds.includes(id);\n}\n\nfunction toggle(enabledIds: EnabledIds, id: string): EnabledIds {\n\tif (enabledIds === null) return [id];\n\tconst index = enabledIds.indexOf(id);\n\tif (index >= 0) return [...enabledIds.slice(0, index), ...enabledIds.slice(index + 1)];\n\treturn [...enabledIds, id];\n}\n\nfunction enableAll(enabledIds: EnabledIds, allIds: string[], targetIds?: string[]): EnabledIds {\n\tif (enabledIds === null) return null;\n\tconst targets = targetIds ?? allIds;\n\tconst result = [...enabledIds];\n\tfor (const id of targets) {\n\t\tif (!result.includes(id)) result.push(id);\n\t}\n\treturn result.length === allIds.length ? null : result;\n}\n\nfunction clearAll(enabledIds: EnabledIds, allIds: string[], targetIds?: string[]): EnabledIds {\n\tif (enabledIds === null) {\n\t\treturn targetIds ? allIds.filter((id) => !targetIds.includes(id)) : [];\n\t}\n\tconst targets = new Set(targetIds ?? enabledIds);\n\treturn enabledIds.filter((id) => !targets.has(id));\n}\n\nfunction move(enabledIds: EnabledIds, id: string, delta: number): EnabledIds {\n\tif (enabledIds === null) return null;\n\tconst list = [...enabledIds];\n\tconst index = list.indexOf(id);\n\tif (index < 0) return list;\n\tconst newIndex = index + delta;\n\tif (newIndex < 0 || newIndex >= list.length) return list;\n\tconst result = [...list];\n\t[result[index], result[newIndex]] = [result[newIndex], result[index]];\n\treturn result;\n}\n\nfunction getSortedIds(enabledIds: EnabledIds, allIds: string[]): string[] {\n\tif (enabledIds === null) return allIds;\n\tconst enabledSet = new Set(enabledIds);\n\treturn [...enabledIds, ...allIds.filter((id) => !enabledSet.has(id))];\n}\n\nexport function buildSelectRows(options: {\n\tmodels: ModelItem[];\n\tcurrentModel?: Model<any>;\n\trecentKeys: string[];\n\tquery: string;\n\texpandedProviders: Set<string>;\n\tcollapsedLimit?: number;\n}): SelectRow[] {\n\tconst { models, currentModel, recentKeys, query, expandedProviders, collapsedLimit = 12 } = options;\n\tconst rows: SelectRow[] = [];\n\n\tif (query) {\n\t\tconst filtered = fuzzyFilter(\n\t\t\tmodels,\n\t\t\tquery,\n\t\t\t({ id, provider, model }) => `${id} ${provider} ${provider}/${id} ${model.name ?? \"\"} ${provider} ${id}`,\n\t\t);\n\t\tfor (const item of filtered) {\n\t\t\trows.push({ kind: \"model\", item, badges: modelBadges(item.model) });\n\t\t}\n\t\treturn rows;\n\t}\n\n\tconst byKey = new Map(models.map((m) => [`${m.provider}/${m.id}`, m]));\n\tconst seen = new Set<string>();\n\n\t// Current first (if available)\n\tif (currentModel) {\n\t\tconst key = `${currentModel.provider}/${currentModel.id}`;\n\t\tconst item = byKey.get(key);\n\t\tif (item) {\n\t\t\trows.push({ kind: \"header\", label: \"Current\" });\n\t\t\trows.push({ kind: \"model\", item, badges: modelBadges(item.model) });\n\t\t\tseen.add(key);\n\t\t}\n\t}\n\n\t// Recent\n\tconst recentItems: ModelItem[] = [];\n\tfor (const key of recentKeys) {\n\t\tif (seen.has(key)) continue;\n\t\tconst item = byKey.get(key);\n\t\tif (item) {\n\t\t\trecentItems.push(item);\n\t\t\tseen.add(key);\n\t\t}\n\t}\n\tif (recentItems.length > 0) {\n\t\trows.push({ kind: \"header\", label: \"Recent\" });\n\t\tfor (const item of recentItems.slice(0, 8)) {\n\t\t\trows.push({ kind: \"model\", item, badges: modelBadges(item.model) });\n\t\t}\n\t}\n\n\t// Group remaining by provider\n\tconst byProvider = new Map<string, ModelItem[]>();\n\tfor (const item of models) {\n\t\tconst key = `${item.provider}/${item.id}`;\n\t\tif (seen.has(key)) continue;\n\t\tconst list = byProvider.get(item.provider) ?? [];\n\t\tlist.push(item);\n\t\tbyProvider.set(item.provider, list);\n\t}\n\n\tconst providers = [...byProvider.keys()].sort((a, b) => a.localeCompare(b));\n\tconst currentProvider = currentModel?.provider;\n\n\tfor (const provider of providers) {\n\t\tconst list = byProvider.get(provider) ?? [];\n\t\tlist.sort((a, b) => a.id.localeCompare(b.id));\n\t\tconst expand = expandedProviders.has(provider) || provider === currentProvider || list.length <= collapsedLimit;\n\n\t\trows.push({ kind: \"header\", label: provider });\n\t\tif (!expand) {\n\t\t\trows.push({ kind: \"collapsed\", provider, count: list.length });\n\t\t\tcontinue;\n\t\t}\n\t\tfor (const item of list) {\n\t\t\trows.push({ kind: \"model\", item, badges: modelBadges(item.model) });\n\t\t}\n\t}\n\n\treturn rows;\n}\n\n// ---------------------------------------------------------------------------\n// Component\n// ---------------------------------------------------------------------------\n\nexport class ModelHubComponent extends Container implements Focusable {\n\tprivate searchInput: Input;\n\tprivate listContainer: Container;\n\tprivate headerText: Text;\n\tprivate footerText: Text;\n\tprivate hintText: Text;\n\n\tprivate _focused = false;\n\tget focused(): boolean {\n\t\treturn this._focused;\n\t}\n\tset focused(value: boolean) {\n\t\tthis._focused = value;\n\t\tthis.searchInput.focused = value;\n\t}\n\n\tprivate tui: TUI;\n\tprivate currentModel?: Model<any>;\n\tprivate settingsManager: SettingsManager;\n\tprivate modelRegistry: ModelRegistry;\n\tprivate callbacks: ModelHubCallbacks;\n\n\tprivate tab: ModelHubTab;\n\tprivate allModels: ModelItem[] = [];\n\tprivate scopedModels: ReadonlyArray<ScopedModelItem>;\n\n\t// Select state\n\tprivate selectRows: SelectRow[] = [];\n\tprivate selectIndex = 0;\n\tprivate expandedProviders = new Set<string>();\n\n\t// Cycle state\n\tprivate cycleAllIds: string[] = [];\n\tprivate cycleModelsById = new Map<string, Model<any>>();\n\tprivate enabledIds: EnabledIds = null;\n\tprivate cycleItems: Array<{ fullId: string; model: Model<any>; enabled: boolean }> = [];\n\tprivate cycleIndex = 0;\n\tprivate cycleDirty = false;\n\n\t// Manage state\n\tprivate manageRows: ManageRow[] = [];\n\tprivate manageIndex = 0;\n\n\tprivate errorMessage?: string;\n\tprivate maxVisible = 10;\n\tprivate loadGeneration = 0;\n\n\tconstructor(\n\t\ttui: TUI,\n\t\tcurrentModel: Model<any> | undefined,\n\t\tsettingsManager: SettingsManager,\n\t\tmodelRegistry: ModelRegistry,\n\t\tscopedModels: ReadonlyArray<ScopedModelItem>,\n\t\tenabledModelIds: string[] | null,\n\t\tcallbacks: ModelHubCallbacks,\n\t\toptions?: { initialTab?: ModelHubTab; initialSearchInput?: string },\n\t) {\n\t\tsuper();\n\t\tthis.tui = tui;\n\t\tthis.currentModel = currentModel;\n\t\tthis.settingsManager = settingsManager;\n\t\tthis.modelRegistry = modelRegistry;\n\t\tthis.scopedModels = scopedModels;\n\t\tthis.callbacks = callbacks;\n\t\tthis.tab = options?.initialTab ?? \"select\";\n\t\tthis.enabledIds = enabledModelIds === null ? null : [...enabledModelIds];\n\n\t\tthis.addChild(new DynamicBorder());\n\t\tthis.addChild(new Spacer(1));\n\n\t\tthis.headerText = new Text(this.getHeaderText(), 0, 0);\n\t\tthis.addChild(this.headerText);\n\t\tthis.hintText = new Text(this.getHintText(), 0, 0);\n\t\tthis.addChild(this.hintText);\n\t\tthis.addChild(new Spacer(1));\n\n\t\tthis.searchInput = new Input();\n\t\tif (options?.initialSearchInput) {\n\t\t\tthis.searchInput.setValue(options.initialSearchInput);\n\t\t}\n\t\tthis.searchInput.onSubmit = () => this.handleConfirm();\n\t\tthis.addChild(this.searchInput);\n\t\tthis.addChild(new Spacer(1));\n\n\t\tthis.listContainer = new Container();\n\t\tthis.addChild(this.listContainer);\n\t\tthis.addChild(new Spacer(1));\n\n\t\tthis.footerText = new Text(this.getFooterText(), 0, 0);\n\t\tthis.addChild(this.footerText);\n\t\tthis.addChild(new DynamicBorder());\n\n\t\tvoid this.reload().then(() => {\n\t\t\tif (options?.initialSearchInput) {\n\t\t\t\tthis.applySearch();\n\t\t\t}\n\t\t\tthis.tui.requestRender();\n\t\t});\n\t}\n\n\t// ---- public helpers for tests ----\n\n\tgetTab(): ModelHubTab {\n\t\treturn this.tab;\n\t}\n\n\tgetSearchInput(): Input {\n\t\treturn this.searchInput;\n\t}\n\n\t/** Test helper: force reload completion */\n\tasync waitForLoad(): Promise<void> {\n\t\tawait this.reload();\n\t}\n\n\t// ---- load ----\n\n\tprivate async reload(): Promise<void> {\n\t\tconst gen = ++this.loadGeneration;\n\t\tthis.modelRegistry.refresh();\n\t\tconst loadError = this.modelRegistry.getError();\n\t\tif (loadError) {\n\t\t\tthis.errorMessage = loadError;\n\t\t} else {\n\t\t\tthis.errorMessage = undefined;\n\t\t}\n\n\t\ttry {\n\t\t\tconst available = this.modelRegistry.getAvailable();\n\t\t\tif (gen !== this.loadGeneration) return;\n\n\t\t\tthis.allModels = available.map((model) => ({\n\t\t\t\tprovider: model.provider,\n\t\t\t\tid: model.id,\n\t\t\t\tmodel,\n\t\t\t}));\n\n\t\t\t// Refresh scoped models against registry\n\t\t\tthis.scopedModels = this.scopedModels.map((scoped) => {\n\t\t\t\tconst refreshed = this.modelRegistry.find(scoped.model.provider, scoped.model.id);\n\t\t\t\treturn refreshed ? { ...scoped, model: refreshed } : scoped;\n\t\t\t});\n\n\t\t\tthis.cycleModelsById.clear();\n\t\t\tthis.cycleAllIds = [];\n\t\t\tfor (const item of this.allModels) {\n\t\t\t\tconst fullId = `${item.provider}/${item.id}`;\n\t\t\t\tthis.cycleModelsById.set(fullId, item.model);\n\t\t\t\tthis.cycleAllIds.push(fullId);\n\t\t\t}\n\n\t\t\tthis.rebuildManageRows();\n\t\t\tthis.applySearch();\n\t\t} catch (error) {\n\t\t\tthis.allModels = [];\n\t\t\tthis.errorMessage = error instanceof Error ? error.message : String(error);\n\t\t\tthis.applySearch();\n\t\t}\n\t}\n\n\tprivate rebuildManageRows(): void {\n\t\tconst rows: ManageRow[] = [];\n\t\trows.push({ kind: \"action\", action: \"add\", label: \"+ Add custom provider (models.json)\" });\n\n\t\tfor (const p of this.modelRegistry.listModelsJsonProviders()) {\n\t\t\tconst modelLabel =\n\t\t\t\tp.modelIds.length === 0\n\t\t\t\t\t? \"override only\"\n\t\t\t\t\t: `${p.modelIds.length} model${p.modelIds.length === 1 ? \"\" : \"s\"}`;\n\t\t\trows.push({\n\t\t\t\tkind: \"provider\",\n\t\t\t\tsource: \"models_json\",\n\t\t\t\tid: p.name,\n\t\t\t\tlabel: p.name,\n\t\t\t\tdetail: `${p.isBuiltIn ? \"built-in override\" : \"custom\"} · ${modelLabel}${p.baseUrl ? ` · ${p.baseUrl}` : \"\"}`,\n\t\t\t});\n\t\t}\n\n\t\tconst openaiCompat = this.modelRegistry.authStorage.getOpenAICompatibleProviders();\n\t\tfor (const [id, info] of Object.entries(openaiCompat)) {\n\t\t\trows.push({\n\t\t\t\tkind: \"provider\",\n\t\t\t\tsource: \"openai_compatible\",\n\t\t\t\tid,\n\t\t\t\tlabel: id,\n\t\t\t\tdetail: `openai-compatible · ${info.models.length} model${info.models.length === 1 ? \"\" : \"s\"} · ${info.baseUrl}`,\n\t\t\t});\n\t\t}\n\n\t\tthis.manageRows = rows;\n\t\tthis.manageIndex = Math.min(this.manageIndex, Math.max(0, rows.length - 1));\n\t}\n\n\t// ---- header / footer ----\n\n\tprivate getHeaderText(): string {\n\t\tconst tabs: Array<{ id: ModelHubTab; label: string }> = [\n\t\t\t{ id: \"select\", label: \"Select\" },\n\t\t\t{ id: \"cycle\", label: \"Cycle\" },\n\t\t\t{ id: \"manage\", label: \"Manage\" },\n\t\t];\n\t\tconst parts = tabs.map((t) => (t.id === this.tab ? theme.fg(\"accent\", t.label) : theme.fg(\"muted\", t.label)));\n\t\treturn `${theme.fg(\"muted\", \"Models: \")}${parts.join(theme.fg(\"muted\", \" | \"))}`;\n\t}\n\n\tprivate getHintText(): string {\n\t\tif (this.tab === \"select\") {\n\t\t\treturn (\n\t\t\t\tkeyHint(\"tui.input.tab\", \"tabs\") +\n\t\t\t\ttheme.fg(\"muted\", \" · type to search · Enter select · collapsed providers: Enter expand\")\n\t\t\t);\n\t\t}\n\t\tif (this.tab === \"cycle\") {\n\t\t\treturn (\n\t\t\t\tkeyHint(\"tui.input.tab\", \"tabs\") + theme.fg(\"muted\", ` · session-only until ${keyText(\"app.models.save\")}`)\n\t\t\t);\n\t\t}\n\t\treturn keyHint(\"tui.input.tab\", \"tabs\") + theme.fg(\"muted\", \" · Enter edit/add · Backspace/Delete remove\");\n\t}\n\n\tprivate getFooterText(): string {\n\t\tif (this.tab === \"select\") {\n\t\t\tconst modelCount = this.selectRows.filter((r) => r.kind === \"model\").length;\n\t\t\treturn theme.fg(\"dim\", ` ${modelCount} model${modelCount === 1 ? \"\" : \"s\"} · Esc cancel`);\n\t\t}\n\t\tif (this.tab === \"cycle\") {\n\t\t\tconst enabledCount = this.enabledIds?.length ?? this.cycleAllIds.length;\n\t\t\tconst allEnabled = this.enabledIds === null;\n\t\t\tconst countText = allEnabled ? \"all enabled\" : `${enabledCount}/${this.cycleAllIds.length} enabled`;\n\t\t\tconst parts = [\n\t\t\t\t`${keyText(\"tui.select.confirm\")} toggle`,\n\t\t\t\t`${keyText(\"app.models.enableAll\")} all`,\n\t\t\t\t`${keyText(\"app.models.clearAll\")} clear`,\n\t\t\t\t`${keyText(\"app.models.toggleProvider\")} provider`,\n\t\t\t\t`${keyText(\"app.models.reorderUp\")}/${keyText(\"app.models.reorderDown\")} reorder`,\n\t\t\t\t`${keyText(\"app.models.save\")} save`,\n\t\t\t\tcountText,\n\t\t\t];\n\t\t\treturn this.cycleDirty\n\t\t\t\t? theme.fg(\"dim\", ` ${parts.join(\" · \")} `) + theme.fg(\"warning\", \"(unsaved)\")\n\t\t\t\t: theme.fg(\"dim\", ` ${parts.join(\" · \")}`);\n\t\t}\n\t\treturn theme.fg(\"dim\", \" Enter open · Backspace delete · writing models.json drops comments/trailing commas\");\n\t}\n\n\tprivate setTab(tab: ModelHubTab): void {\n\t\tif (this.tab === tab) return;\n\t\tthis.tab = tab;\n\t\tthis.headerText.setText(this.getHeaderText());\n\t\tthis.hintText.setText(this.getHintText());\n\t\tthis.applySearch();\n\t}\n\n\tprivate cycleTab(): void {\n\t\tconst order: ModelHubTab[] = [\"select\", \"cycle\", \"manage\"];\n\t\tconst idx = order.indexOf(this.tab);\n\t\tthis.setTab(order[(idx + 1) % order.length]!);\n\t}\n\n\t// ---- list building ----\n\n\tprivate applySearch(): void {\n\t\tconst query = this.searchInput.getValue();\n\n\t\tif (this.tab === \"select\") {\n\t\t\tthis.selectRows = buildSelectRows({\n\t\t\t\tmodels: this.allModels,\n\t\t\t\tcurrentModel: this.currentModel,\n\t\t\t\trecentKeys: this.settingsManager.getRecentModels(),\n\t\t\t\tquery,\n\t\t\t\texpandedProviders: this.expandedProviders,\n\t\t\t});\n\t\t\t// Prefer current model selection\n\t\t\tconst currentIdx = this.selectRows.findIndex(\n\t\t\t\t(r) => r.kind === \"model\" && modelsAreEqual(this.currentModel, r.item.model),\n\t\t\t);\n\t\t\tthis.selectIndex =\n\t\t\t\tcurrentIdx >= 0 ? currentIdx : Math.min(this.selectIndex, Math.max(0, this.selectRows.length - 1));\n\t\t\t// Snap to first selectable if landing on header\n\t\t\tthis.ensureSelectableIndex(\"select\");\n\t\t} else if (this.tab === \"cycle\") {\n\t\t\tconst items = getSortedIds(this.enabledIds, this.cycleAllIds)\n\t\t\t\t.filter((id) => this.cycleModelsById.has(id))\n\t\t\t\t.map((id) => ({\n\t\t\t\t\tfullId: id,\n\t\t\t\t\tmodel: this.cycleModelsById.get(id)!,\n\t\t\t\t\tenabled: isEnabled(this.enabledIds, id),\n\t\t\t\t}));\n\t\t\tthis.cycleItems = query ? fuzzyFilter(items, query, (i) => `${i.model.id} ${i.model.provider}`) : items;\n\t\t\tthis.cycleIndex = Math.min(this.cycleIndex, Math.max(0, this.cycleItems.length - 1));\n\t\t} else {\n\t\t\tthis.rebuildManageRows();\n\t\t\tif (query) {\n\t\t\t\tthis.manageRows = fuzzyFilter(this.manageRows, query, (r) =>\n\t\t\t\t\tr.kind === \"action\" ? r.label : `${r.label} ${r.detail} ${r.id}`,\n\t\t\t\t);\n\t\t\t}\n\t\t\tthis.manageIndex = Math.min(this.manageIndex, Math.max(0, this.manageRows.length - 1));\n\t\t}\n\n\t\tthis.updateList();\n\t\tthis.footerText.setText(this.getFooterText());\n\t}\n\n\tprivate ensureSelectableIndex(which: \"select\"): void {\n\t\tif (which !== \"select\" || this.selectRows.length === 0) return;\n\t\tif (this.selectRows[this.selectIndex]?.kind === \"header\") {\n\t\t\tconst next = this.selectRows.findIndex((r, i) => i >= this.selectIndex && r.kind !== \"header\");\n\t\t\tif (next >= 0) {\n\t\t\t\tthis.selectIndex = next;\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tconst prev = [...this.selectRows]\n\t\t\t\t.map((r, i) => ({ r, i }))\n\t\t\t\t.reverse()\n\t\t\t\t.find(({ r }) => r.kind !== \"header\");\n\t\t\tif (prev) this.selectIndex = prev.i;\n\t\t}\n\t}\n\n\tprivate updateList(): void {\n\t\tthis.listContainer.clear();\n\n\t\tif (this.errorMessage && this.tab !== \"manage\") {\n\t\t\tfor (const line of this.errorMessage.split(\"\\n\")) {\n\t\t\t\tthis.listContainer.addChild(new Text(theme.fg(\"error\", line), 0, 0));\n\t\t\t}\n\t\t}\n\n\t\tif (this.tab === \"select\") {\n\t\t\tthis.renderSelectList();\n\t\t} else if (this.tab === \"cycle\") {\n\t\t\tthis.renderCycleList();\n\t\t} else {\n\t\t\tthis.renderManageList();\n\t\t}\n\t}\n\n\tprivate renderSelectList(): void {\n\t\tif (this.selectRows.length === 0) {\n\t\t\tthis.listContainer.addChild(new Text(theme.fg(\"muted\", \" No matching models\"), 0, 0));\n\t\t\treturn;\n\t\t}\n\n\t\tconst startIndex = Math.max(\n\t\t\t0,\n\t\t\tMath.min(this.selectIndex - Math.floor(this.maxVisible / 2), this.selectRows.length - this.maxVisible),\n\t\t);\n\t\tconst endIndex = Math.min(startIndex + this.maxVisible, this.selectRows.length);\n\n\t\tfor (let i = startIndex; i < endIndex; i++) {\n\t\t\tconst row = this.selectRows[i]!;\n\t\t\tconst isSelected = i === this.selectIndex;\n\n\t\t\tif (row.kind === \"header\") {\n\t\t\t\tthis.listContainer.addChild(new Text(theme.fg(\"muted\", ` ── ${row.label} ──`), 0, 0));\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif (row.kind === \"collapsed\") {\n\t\t\t\tconst prefix = isSelected ? theme.fg(\"accent\", \"→ \") : \" \";\n\t\t\t\tconst text = isSelected\n\t\t\t\t\t? theme.fg(\"accent\", `▸ ${row.provider} (${row.count})`)\n\t\t\t\t\t: theme.fg(\"muted\", `▸ ${row.provider} (${row.count})`);\n\t\t\t\tthis.listContainer.addChild(new Text(`${prefix}${text}`, 0, 0));\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tconst isCurrent = modelsAreEqual(this.currentModel, row.item.model);\n\t\t\tconst prefix = isSelected ? theme.fg(\"accent\", \"→ \") : \" \";\n\t\t\tconst modelText = isSelected ? theme.fg(\"accent\", row.item.id) : row.item.id;\n\t\t\tconst providerBadge = theme.fg(\"muted\", ` [${row.item.provider}]`);\n\t\t\tconst badges = theme.fg(\"dim\", ` ${row.badges}`);\n\t\t\tconst check = isCurrent ? theme.fg(\"success\", \" ✓\") : \"\";\n\t\t\tthis.listContainer.addChild(new Text(`${prefix}${modelText}${providerBadge}${badges}${check}`, 0, 0));\n\t\t}\n\n\t\tif (startIndex > 0 || endIndex < this.selectRows.length) {\n\t\t\tthis.listContainer.addChild(\n\t\t\t\tnew Text(theme.fg(\"muted\", ` (${this.selectIndex + 1}/${this.selectRows.length})`), 0, 0),\n\t\t\t);\n\t\t}\n\n\t\tconst selected = this.selectRows[this.selectIndex];\n\t\tif (selected?.kind === \"model\") {\n\t\t\tthis.listContainer.addChild(new Spacer(1));\n\t\t\tthis.listContainer.addChild(new Text(theme.fg(\"muted\", ` ${selected.item.model.name}`), 0, 0));\n\t\t}\n\t}\n\n\tprivate renderCycleList(): void {\n\t\tif (this.cycleItems.length === 0) {\n\t\t\tthis.listContainer.addChild(new Text(theme.fg(\"muted\", \" No matching models\"), 0, 0));\n\t\t\treturn;\n\t\t}\n\n\t\tconst startIndex = Math.max(\n\t\t\t0,\n\t\t\tMath.min(this.cycleIndex - Math.floor(this.maxVisible / 2), this.cycleItems.length - this.maxVisible),\n\t\t);\n\t\tconst endIndex = Math.min(startIndex + this.maxVisible, this.cycleItems.length);\n\t\tconst allEnabled = this.enabledIds === null;\n\n\t\tfor (let i = startIndex; i < endIndex; i++) {\n\t\t\tconst item = this.cycleItems[i]!;\n\t\t\tconst isSelected = i === this.cycleIndex;\n\t\t\tconst prefix = isSelected ? theme.fg(\"accent\", \"→ \") : \" \";\n\t\t\tconst modelText = isSelected ? theme.fg(\"accent\", item.model.id) : item.model.id;\n\t\t\tconst providerBadge = theme.fg(\"muted\", ` [${item.model.provider}]`);\n\t\t\tconst status = allEnabled ? \"\" : item.enabled ? theme.fg(\"success\", \" ✓\") : theme.fg(\"dim\", \" ✗\");\n\t\t\tthis.listContainer.addChild(new Text(`${prefix}${modelText}${providerBadge}${status}`, 0, 0));\n\t\t}\n\n\t\tif (startIndex > 0 || endIndex < this.cycleItems.length) {\n\t\t\tthis.listContainer.addChild(\n\t\t\t\tnew Text(theme.fg(\"muted\", ` (${this.cycleIndex + 1}/${this.cycleItems.length})`), 0, 0),\n\t\t\t);\n\t\t}\n\n\t\tif (this.cycleItems.length > 0) {\n\t\t\tconst selected = this.cycleItems[this.cycleIndex];\n\t\t\tthis.listContainer.addChild(new Spacer(1));\n\t\t\tthis.listContainer.addChild(new Text(theme.fg(\"muted\", ` ${selected?.model.name}`), 0, 0));\n\t\t}\n\t}\n\n\tprivate renderManageList(): void {\n\t\tif (this.manageRows.length === 0) {\n\t\t\tthis.listContainer.addChild(new Text(theme.fg(\"muted\", \" No custom providers\"), 0, 0));\n\t\t\treturn;\n\t\t}\n\n\t\tconst startIndex = Math.max(\n\t\t\t0,\n\t\t\tMath.min(this.manageIndex - Math.floor(this.maxVisible / 2), this.manageRows.length - this.maxVisible),\n\t\t);\n\t\tconst endIndex = Math.min(startIndex + this.maxVisible, this.manageRows.length);\n\n\t\tfor (let i = startIndex; i < endIndex; i++) {\n\t\t\tconst row = this.manageRows[i]!;\n\t\t\tconst isSelected = i === this.manageIndex;\n\t\t\tconst prefix = isSelected ? theme.fg(\"accent\", \"→ \") : \" \";\n\t\t\tif (row.kind === \"action\") {\n\t\t\t\tconst text = isSelected ? theme.fg(\"accent\", row.label) : theme.fg(\"success\", row.label);\n\t\t\t\tthis.listContainer.addChild(new Text(`${prefix}${text}`, 0, 0));\n\t\t\t} else {\n\t\t\t\tconst text = isSelected ? theme.fg(\"accent\", row.label) : row.label;\n\t\t\t\tconst detail = theme.fg(\"muted\", ` ${row.detail}`);\n\t\t\t\tthis.listContainer.addChild(new Text(`${prefix}${text}`, 0, 0));\n\t\t\t\tthis.listContainer.addChild(new Text(`${detail}`, 0, 0));\n\t\t\t}\n\t\t}\n\t}\n\n\t// ---- input ----\n\n\thandleInput(keyData: string): void {\n\t\tconst kb = getKeybindings();\n\n\t\tif (kb.matches(keyData, \"tui.input.tab\")) {\n\t\t\tthis.cycleTab();\n\t\t\treturn;\n\t\t}\n\n\t\tif (kb.matches(keyData, \"tui.select.cancel\") || matchesKey(keyData, Key.escape)) {\n\t\t\tthis.callbacks.onCancel();\n\t\t\treturn;\n\t\t}\n\n\t\tif (matchesKey(keyData, Key.ctrl(\"c\"))) {\n\t\t\tif (this.searchInput.getValue()) {\n\t\t\t\tthis.searchInput.setValue(\"\");\n\t\t\t\tthis.applySearch();\n\t\t\t} else {\n\t\t\t\tthis.callbacks.onCancel();\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\n\t\tif (this.tab === \"select\") {\n\t\t\tthis.handleSelectInput(keyData, kb);\n\t\t} else if (this.tab === \"cycle\") {\n\t\t\tthis.handleCycleInput(keyData, kb);\n\t\t} else {\n\t\t\tthis.handleManageInput(keyData, kb);\n\t\t}\n\t}\n\n\tprivate handleSelectInput(keyData: string, kb: ReturnType<typeof getKeybindings>): void {\n\t\tif (kb.matches(keyData, \"tui.select.up\")) {\n\t\t\tif (this.selectRows.length === 0) return;\n\t\t\tlet next = this.selectIndex === 0 ? this.selectRows.length - 1 : this.selectIndex - 1;\n\t\t\t// Skip headers when moving\n\t\t\tfor (let guard = 0; guard < this.selectRows.length; guard++) {\n\t\t\t\tif (this.selectRows[next]?.kind !== \"header\") break;\n\t\t\t\tnext = next === 0 ? this.selectRows.length - 1 : next - 1;\n\t\t\t}\n\t\t\tthis.selectIndex = next;\n\t\t\tthis.updateList();\n\t\t\treturn;\n\t\t}\n\t\tif (kb.matches(keyData, \"tui.select.down\")) {\n\t\t\tif (this.selectRows.length === 0) return;\n\t\t\tlet next = this.selectIndex === this.selectRows.length - 1 ? 0 : this.selectIndex + 1;\n\t\t\tfor (let guard = 0; guard < this.selectRows.length; guard++) {\n\t\t\t\tif (this.selectRows[next]?.kind !== \"header\") break;\n\t\t\t\tnext = next === this.selectRows.length - 1 ? 0 : next + 1;\n\t\t\t}\n\t\t\tthis.selectIndex = next;\n\t\t\tthis.updateList();\n\t\t\treturn;\n\t\t}\n\t\tif (kb.matches(keyData, \"tui.select.confirm\")) {\n\t\t\tthis.handleConfirm();\n\t\t\treturn;\n\t\t}\n\n\t\tthis.searchInput.handleInput(keyData);\n\t\tthis.applySearch();\n\t}\n\n\tprivate handleCycleInput(keyData: string, kb: ReturnType<typeof getKeybindings>): void {\n\t\tif (kb.matches(keyData, \"tui.select.up\")) {\n\t\t\tif (this.cycleItems.length === 0) return;\n\t\t\tthis.cycleIndex = this.cycleIndex === 0 ? this.cycleItems.length - 1 : this.cycleIndex - 1;\n\t\t\tthis.updateList();\n\t\t\treturn;\n\t\t}\n\t\tif (kb.matches(keyData, \"tui.select.down\")) {\n\t\t\tif (this.cycleItems.length === 0) return;\n\t\t\tthis.cycleIndex = this.cycleIndex === this.cycleItems.length - 1 ? 0 : this.cycleIndex + 1;\n\t\t\tthis.updateList();\n\t\t\treturn;\n\t\t}\n\n\t\tconst reorderUp = kb.matches(keyData, \"app.models.reorderUp\");\n\t\tconst reorderDown = kb.matches(keyData, \"app.models.reorderDown\");\n\t\tif (reorderUp || reorderDown) {\n\t\t\tif (this.enabledIds === null) return;\n\t\t\tconst item = this.cycleItems[this.cycleIndex];\n\t\t\tif (item && isEnabled(this.enabledIds, item.fullId)) {\n\t\t\t\tconst delta = reorderUp ? -1 : 1;\n\t\t\t\tconst currentIndex = this.enabledIds.indexOf(item.fullId);\n\t\t\t\tconst newIndex = currentIndex + delta;\n\t\t\t\tif (newIndex >= 0 && newIndex < this.enabledIds.length) {\n\t\t\t\t\tthis.enabledIds = move(this.enabledIds, item.fullId, delta);\n\t\t\t\t\tthis.cycleDirty = true;\n\t\t\t\t\tthis.cycleIndex += delta;\n\t\t\t\t\tthis.applySearch();\n\t\t\t\t\tvoid this.callbacks.onCycleChange(this.enabledIds === null ? null : [...this.enabledIds]);\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\n\t\tif (kb.matches(keyData, \"tui.select.confirm\")) {\n\t\t\tconst item = this.cycleItems[this.cycleIndex];\n\t\t\tif (item) {\n\t\t\t\tthis.enabledIds = toggle(this.enabledIds, item.fullId);\n\t\t\t\tthis.cycleDirty = true;\n\t\t\t\tthis.applySearch();\n\t\t\t\tvoid this.callbacks.onCycleChange(this.enabledIds === null ? null : [...this.enabledIds]);\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\n\t\tif (kb.matches(keyData, \"app.models.enableAll\")) {\n\t\t\tconst targetIds = this.searchInput.getValue() ? this.cycleItems.map((i) => i.fullId) : undefined;\n\t\t\tthis.enabledIds = enableAll(this.enabledIds, this.cycleAllIds, targetIds);\n\t\t\tthis.cycleDirty = true;\n\t\t\tthis.applySearch();\n\t\t\tvoid this.callbacks.onCycleChange(this.enabledIds === null ? null : [...this.enabledIds]);\n\t\t\treturn;\n\t\t}\n\n\t\tif (kb.matches(keyData, \"app.models.clearAll\")) {\n\t\t\tconst targetIds = this.searchInput.getValue() ? this.cycleItems.map((i) => i.fullId) : undefined;\n\t\t\tthis.enabledIds = clearAll(this.enabledIds, this.cycleAllIds, targetIds);\n\t\t\tthis.cycleDirty = true;\n\t\t\tthis.applySearch();\n\t\t\tvoid this.callbacks.onCycleChange(this.enabledIds === null ? null : [...this.enabledIds]);\n\t\t\treturn;\n\t\t}\n\n\t\tif (kb.matches(keyData, \"app.models.toggleProvider\")) {\n\t\t\tconst item = this.cycleItems[this.cycleIndex];\n\t\t\tif (item) {\n\t\t\t\tconst provider = item.model.provider;\n\t\t\t\tconst providerIds = this.cycleAllIds.filter((id) => this.cycleModelsById.get(id)!.provider === provider);\n\t\t\t\tconst allOn = providerIds.every((id) => isEnabled(this.enabledIds, id));\n\t\t\t\tthis.enabledIds = allOn\n\t\t\t\t\t? clearAll(this.enabledIds, this.cycleAllIds, providerIds)\n\t\t\t\t\t: enableAll(this.enabledIds, this.cycleAllIds, providerIds);\n\t\t\t\tthis.cycleDirty = true;\n\t\t\t\tthis.applySearch();\n\t\t\t\tvoid this.callbacks.onCycleChange(this.enabledIds === null ? null : [...this.enabledIds]);\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\n\t\tif (kb.matches(keyData, \"app.models.save\")) {\n\t\t\tvoid this.callbacks.onCyclePersist(this.enabledIds === null ? null : [...this.enabledIds]);\n\t\t\tthis.cycleDirty = false;\n\t\t\tthis.footerText.setText(this.getFooterText());\n\t\t\treturn;\n\t\t}\n\n\t\tthis.searchInput.handleInput(keyData);\n\t\tthis.applySearch();\n\t}\n\n\tprivate handleManageInput(keyData: string, kb: ReturnType<typeof getKeybindings>): void {\n\t\tif (kb.matches(keyData, \"tui.select.up\")) {\n\t\t\tif (this.manageRows.length === 0) return;\n\t\t\tthis.manageIndex = this.manageIndex === 0 ? this.manageRows.length - 1 : this.manageIndex - 1;\n\t\t\tthis.updateList();\n\t\t\treturn;\n\t\t}\n\t\tif (kb.matches(keyData, \"tui.select.down\")) {\n\t\t\tif (this.manageRows.length === 0) return;\n\t\t\tthis.manageIndex = this.manageIndex === this.manageRows.length - 1 ? 0 : this.manageIndex + 1;\n\t\t\tthis.updateList();\n\t\t\treturn;\n\t\t}\n\t\tif (kb.matches(keyData, \"tui.select.confirm\")) {\n\t\t\tthis.handleConfirm();\n\t\t\treturn;\n\t\t}\n\t\t// Backspace / Delete remove selected provider\n\t\tif (matchesKey(keyData, Key.backspace) || matchesKey(keyData, Key.delete)) {\n\t\t\tconst row = this.manageRows[this.manageIndex];\n\t\t\tif (row?.kind === \"provider\") {\n\t\t\t\tvoid this.callbacks.onManageRemove(row.source, row.id);\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\n\t\tthis.searchInput.handleInput(keyData);\n\t\tthis.applySearch();\n\t}\n\n\tprivate handleConfirm(): void {\n\t\tif (this.tab === \"select\") {\n\t\t\tconst row = this.selectRows[this.selectIndex];\n\t\t\tif (!row) return;\n\t\t\tif (row.kind === \"collapsed\") {\n\t\t\t\tthis.expandedProviders.add(row.provider);\n\t\t\t\tthis.applySearch();\n\t\t\t\t// Move selection to first model under that provider\n\t\t\t\tconst idx = this.selectRows.findIndex((r) => r.kind === \"model\" && r.item.provider === row.provider);\n\t\t\t\tif (idx >= 0) this.selectIndex = idx;\n\t\t\t\tthis.updateList();\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif (row.kind === \"model\") {\n\t\t\t\tthis.settingsManager.setDefaultModelAndProvider(row.item.model.provider, row.item.model.id);\n\t\t\t\tvoid this.callbacks.onSelectModel(row.item.model);\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\n\t\tif (this.tab === \"cycle\") {\n\t\t\tconst item = this.cycleItems[this.cycleIndex];\n\t\t\tif (item) {\n\t\t\t\tthis.enabledIds = toggle(this.enabledIds, item.fullId);\n\t\t\t\tthis.cycleDirty = true;\n\t\t\t\tthis.applySearch();\n\t\t\t\tvoid this.callbacks.onCycleChange(this.enabledIds === null ? null : [...this.enabledIds]);\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\n\t\tconst row = this.manageRows[this.manageIndex];\n\t\tif (!row) return;\n\t\tif (row.kind === \"action\" && row.action === \"add\") {\n\t\t\tvoid this.callbacks.onManageAdd();\n\t\t\treturn;\n\t\t}\n\t\tif (row.kind === \"provider\") {\n\t\t\tvoid this.callbacks.onManageEdit(row.source, row.id);\n\t\t}\n\t}\n\n\t/** Called by parent after manage mutation so list refreshes. */\n\tasync refreshAfterManage(): Promise<void> {\n\t\tawait this.reload();\n\t\tthis.tui.requestRender();\n\t}\n}\n\n/** Back-compat alias used by older tests/imports. */\nexport { ModelHubComponent as ModelSelectorComponent };\n"]}
1
+ {"version":3,"file":"model-hub.d.ts","sourceRoot":"","sources":["../../../../src/modes/interactive/components/model-hub.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Unified model hub: Select current model, manage cycle whitelist, manage custom providers.\n */\n\nimport { type Model, modelsAreEqual } from \"@openeryc/pi-ai\";\nimport {\n\tContainer,\n\ttype Focusable,\n\tfuzzyFilter,\n\tgetKeybindings,\n\tInput,\n\tKey,\n\tmatchesKey,\n\tSpacer,\n\tText,\n\ttype TUI,\n} from \"@openeryc/pi-tui\";\nimport type { ModelRegistry } from \"../../../core/model-registry.ts\";\nimport type { SettingsManager } from \"../../../core/settings-manager.ts\";\nimport { theme } from \"../theme/theme.ts\";\nimport { DynamicBorder } from \"./dynamic-border.ts\";\nimport { keyHint, keyText } from \"./keybinding-hints.ts\";\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\nexport type ModelHubTab = \"select\" | \"cycle\" | \"manage\";\n\ninterface ModelItem {\n\tprovider: string;\n\tid: string;\n\tmodel: Model<any>;\n}\n\ninterface ScopedModelItem {\n\tmodel: Model<any>;\n\tthinkingLevel?: string;\n}\n\ntype EnabledIds = string[] | null;\n\ntype SelectRow =\n\t| { kind: \"header\"; label: string }\n\t| { kind: \"collapsed\"; provider: string; count: number }\n\t| { kind: \"model\"; item: ModelItem; badges: string };\n\ntype ManageRow =\n\t| {\n\t\t\tkind: \"provider\";\n\t\t\tsource: \"models_json\" | \"openai_compatible\";\n\t\t\tid: string;\n\t\t\tlabel: string;\n\t\t\tdetail: string;\n\t }\n\t| { kind: \"action\"; action: \"add\"; label: string };\n\nexport interface ModelHubCallbacks {\n\tonSelectModel: (model: Model<any>) => void | Promise<void>;\n\tonCancel: () => void;\n\t/** Cycle tab: session-only scope change */\n\tonCycleChange: (enabledModelIds: string[] | null) => void | Promise<void>;\n\t/** Cycle tab: persist to settings */\n\tonCyclePersist: (enabledModelIds: string[] | null) => void | Promise<void>;\n\t/** Manage tab: open add-provider wizard (writes models.json by default) */\n\tonManageAdd: () => void | Promise<void>;\n\t/** Manage tab: edit existing custom/openai_compatible provider */\n\tonManageEdit: (source: \"models_json\" | \"openai_compatible\", providerId: string) => void | Promise<void>;\n\t/** Manage tab: remove provider */\n\tonManageRemove: (source: \"models_json\" | \"openai_compatible\", providerId: string) => void | Promise<void>;\n}\n\n// ---------------------------------------------------------------------------\n// Pure helpers (exported for tests)\n// ---------------------------------------------------------------------------\n\nexport function formatTokenCount(count: number): string {\n\tif (count >= 1_000_000) {\n\t\tconst millions = count / 1_000_000;\n\t\treturn millions % 1 === 0 ? `${millions}M` : `${millions.toFixed(1)}M`;\n\t}\n\tif (count >= 1_000) {\n\t\tconst thousands = count / 1_000;\n\t\treturn thousands % 1 === 0 ? `${thousands}K` : `${thousands.toFixed(1)}K`;\n\t}\n\treturn count.toString();\n}\n\nfunction modelBadges(model: Model<any>): string {\n\tconst parts: string[] = [];\n\tif (model.reasoning) parts.push(\"R\");\n\tparts.push(formatTokenCount(model.contextWindow));\n\treturn parts.join(\" \");\n}\n\nfunction isEnabled(enabledIds: EnabledIds, id: string): boolean {\n\treturn enabledIds === null || enabledIds.includes(id);\n}\n\nfunction toggle(enabledIds: EnabledIds, id: string): EnabledIds {\n\tif (enabledIds === null) return [id];\n\tconst index = enabledIds.indexOf(id);\n\tif (index >= 0) return [...enabledIds.slice(0, index), ...enabledIds.slice(index + 1)];\n\treturn [...enabledIds, id];\n}\n\nfunction enableAll(enabledIds: EnabledIds, allIds: string[], targetIds?: string[]): EnabledIds {\n\tif (enabledIds === null) return null;\n\tconst targets = targetIds ?? allIds;\n\tconst result = [...enabledIds];\n\tfor (const id of targets) {\n\t\tif (!result.includes(id)) result.push(id);\n\t}\n\treturn result.length === allIds.length ? null : result;\n}\n\nfunction clearAll(enabledIds: EnabledIds, allIds: string[], targetIds?: string[]): EnabledIds {\n\tif (enabledIds === null) {\n\t\treturn targetIds ? allIds.filter((id) => !targetIds.includes(id)) : [];\n\t}\n\tconst targets = new Set(targetIds ?? enabledIds);\n\treturn enabledIds.filter((id) => !targets.has(id));\n}\n\nfunction move(enabledIds: EnabledIds, id: string, delta: number): EnabledIds {\n\tif (enabledIds === null) return null;\n\tconst list = [...enabledIds];\n\tconst index = list.indexOf(id);\n\tif (index < 0) return list;\n\tconst newIndex = index + delta;\n\tif (newIndex < 0 || newIndex >= list.length) return list;\n\tconst result = [...list];\n\t[result[index], result[newIndex]] = [result[newIndex], result[index]];\n\treturn result;\n}\n\nfunction getSortedIds(enabledIds: EnabledIds, allIds: string[]): string[] {\n\tif (enabledIds === null) return allIds;\n\tconst enabledSet = new Set(enabledIds);\n\treturn [...enabledIds, ...allIds.filter((id) => !enabledSet.has(id))];\n}\n\nexport function buildSelectRows(options: {\n\tmodels: ModelItem[];\n\tcurrentModel?: Model<any>;\n\trecentKeys: string[];\n\tquery: string;\n\texpandedProviders: Set<string>;\n\tcollapsedLimit?: number;\n}): SelectRow[] {\n\tconst { models, currentModel, recentKeys, query, expandedProviders, collapsedLimit = 12 } = options;\n\tconst rows: SelectRow[] = [];\n\n\tif (query) {\n\t\tconst filtered = fuzzyFilter(\n\t\t\tmodels,\n\t\t\tquery,\n\t\t\t({ id, provider, model }) => `${id} ${provider} ${provider}/${id} ${model.name ?? \"\"} ${provider} ${id}`,\n\t\t);\n\t\tfor (const item of filtered) {\n\t\t\trows.push({ kind: \"model\", item, badges: modelBadges(item.model) });\n\t\t}\n\t\treturn rows;\n\t}\n\n\tconst byKey = new Map(models.map((m) => [`${m.provider}/${m.id}`, m]));\n\tconst seen = new Set<string>();\n\n\t// Current first (if available)\n\tif (currentModel) {\n\t\tconst key = `${currentModel.provider}/${currentModel.id}`;\n\t\tconst item = byKey.get(key);\n\t\tif (item) {\n\t\t\trows.push({ kind: \"header\", label: \"Current\" });\n\t\t\trows.push({ kind: \"model\", item, badges: modelBadges(item.model) });\n\t\t\tseen.add(key);\n\t\t}\n\t}\n\n\t// Recent\n\tconst recentItems: ModelItem[] = [];\n\tfor (const key of recentKeys) {\n\t\tif (seen.has(key)) continue;\n\t\tconst item = byKey.get(key);\n\t\tif (item) {\n\t\t\trecentItems.push(item);\n\t\t\tseen.add(key);\n\t\t}\n\t}\n\tif (recentItems.length > 0) {\n\t\trows.push({ kind: \"header\", label: \"Recent\" });\n\t\tfor (const item of recentItems.slice(0, 8)) {\n\t\t\trows.push({ kind: \"model\", item, badges: modelBadges(item.model) });\n\t\t}\n\t}\n\n\t// Group remaining by provider\n\tconst byProvider = new Map<string, ModelItem[]>();\n\tfor (const item of models) {\n\t\tconst key = `${item.provider}/${item.id}`;\n\t\tif (seen.has(key)) continue;\n\t\tconst list = byProvider.get(item.provider) ?? [];\n\t\tlist.push(item);\n\t\tbyProvider.set(item.provider, list);\n\t}\n\n\tconst providers = [...byProvider.keys()].sort((a, b) => a.localeCompare(b));\n\tconst currentProvider = currentModel?.provider;\n\n\tfor (const provider of providers) {\n\t\tconst list = byProvider.get(provider) ?? [];\n\t\tlist.sort((a, b) => a.id.localeCompare(b.id));\n\t\tconst expand = expandedProviders.has(provider) || provider === currentProvider || list.length <= collapsedLimit;\n\n\t\trows.push({ kind: \"header\", label: provider });\n\t\tif (!expand) {\n\t\t\trows.push({ kind: \"collapsed\", provider, count: list.length });\n\t\t\tcontinue;\n\t\t}\n\t\tfor (const item of list) {\n\t\t\trows.push({ kind: \"model\", item, badges: modelBadges(item.model) });\n\t\t}\n\t}\n\n\treturn rows;\n}\n\n// ---------------------------------------------------------------------------\n// Component\n// ---------------------------------------------------------------------------\n\nexport class ModelHubComponent extends Container implements Focusable {\n\tprivate searchInput: Input;\n\tprivate listContainer: Container;\n\tprivate headerText: Text;\n\tprivate footerText: Text;\n\tprivate hintText: Text;\n\n\tprivate _focused = false;\n\tget focused(): boolean {\n\t\treturn this._focused;\n\t}\n\tset focused(value: boolean) {\n\t\tthis._focused = value;\n\t\tthis.searchInput.focused = value;\n\t}\n\n\tprivate tui: TUI;\n\tprivate currentModel?: Model<any>;\n\tprivate settingsManager: SettingsManager;\n\tprivate modelRegistry: ModelRegistry;\n\tprivate callbacks: ModelHubCallbacks;\n\n\tprivate tab: ModelHubTab;\n\tprivate allModels: ModelItem[] = [];\n\tprivate scopedModels: ReadonlyArray<ScopedModelItem>;\n\n\t// Select state\n\tprivate selectRows: SelectRow[] = [];\n\tprivate selectIndex = 0;\n\tprivate expandedProviders = new Set<string>();\n\n\t// Cycle state\n\tprivate cycleAllIds: string[] = [];\n\tprivate cycleModelsById = new Map<string, Model<any>>();\n\tprivate enabledIds: EnabledIds = null;\n\tprivate cycleItems: Array<{ fullId: string; model: Model<any>; enabled: boolean }> = [];\n\tprivate cycleIndex = 0;\n\tprivate cycleDirty = false;\n\n\t// Manage state\n\tprivate manageRows: ManageRow[] = [];\n\tprivate manageIndex = 0;\n\n\tprivate errorMessage?: string;\n\tprivate maxVisible = 10;\n\tprivate loadGeneration = 0;\n\n\tconstructor(\n\t\ttui: TUI,\n\t\tcurrentModel: Model<any> | undefined,\n\t\tsettingsManager: SettingsManager,\n\t\tmodelRegistry: ModelRegistry,\n\t\tscopedModels: ReadonlyArray<ScopedModelItem>,\n\t\tenabledModelIds: string[] | null,\n\t\tcallbacks: ModelHubCallbacks,\n\t\toptions?: { initialTab?: ModelHubTab; initialSearchInput?: string },\n\t) {\n\t\tsuper();\n\t\tthis.tui = tui;\n\t\tthis.currentModel = currentModel;\n\t\tthis.settingsManager = settingsManager;\n\t\tthis.modelRegistry = modelRegistry;\n\t\tthis.scopedModels = scopedModels;\n\t\tthis.callbacks = callbacks;\n\t\tthis.tab = options?.initialTab ?? \"select\";\n\t\tthis.enabledIds = enabledModelIds === null ? null : [...enabledModelIds];\n\n\t\tthis.addChild(new DynamicBorder());\n\t\tthis.addChild(new Spacer(1));\n\n\t\tthis.headerText = new Text(this.getHeaderText(), 0, 0);\n\t\tthis.addChild(this.headerText);\n\t\tthis.hintText = new Text(this.getHintText(), 0, 0);\n\t\tthis.addChild(this.hintText);\n\t\tthis.addChild(new Spacer(1));\n\n\t\tthis.searchInput = new Input();\n\t\tif (options?.initialSearchInput) {\n\t\t\tthis.searchInput.setValue(options.initialSearchInput);\n\t\t}\n\t\tthis.searchInput.onSubmit = () => this.handleConfirm();\n\t\tthis.addChild(this.searchInput);\n\t\tthis.addChild(new Spacer(1));\n\n\t\tthis.listContainer = new Container();\n\t\tthis.addChild(this.listContainer);\n\t\tthis.addChild(new Spacer(1));\n\n\t\tthis.footerText = new Text(this.getFooterText(), 0, 0);\n\t\tthis.addChild(this.footerText);\n\t\tthis.addChild(new DynamicBorder());\n\n\t\tvoid this.reload().then(() => {\n\t\t\tif (options?.initialSearchInput) {\n\t\t\t\tthis.applySearch();\n\t\t\t}\n\t\t\tthis.tui.requestRender();\n\t\t});\n\t}\n\n\t// ---- public helpers for tests ----\n\n\tgetTab(): ModelHubTab {\n\t\treturn this.tab;\n\t}\n\n\tgetSearchInput(): Input {\n\t\treturn this.searchInput;\n\t}\n\n\t/** Test helper: force reload completion */\n\tasync waitForLoad(): Promise<void> {\n\t\tawait this.reload();\n\t}\n\n\t// ---- load ----\n\n\tprivate async reload(): Promise<void> {\n\t\tconst gen = ++this.loadGeneration;\n\t\tthis.modelRegistry.refresh();\n\t\tconst loadError = this.modelRegistry.getError();\n\t\tif (loadError) {\n\t\t\tthis.errorMessage = loadError;\n\t\t} else {\n\t\t\tthis.errorMessage = undefined;\n\t\t}\n\n\t\ttry {\n\t\t\tconst available = this.modelRegistry.getAvailable();\n\t\t\tif (gen !== this.loadGeneration) return;\n\n\t\t\tthis.allModels = available.map((model) => ({\n\t\t\t\tprovider: model.provider,\n\t\t\t\tid: model.id,\n\t\t\t\tmodel,\n\t\t\t}));\n\n\t\t\t// Refresh scoped models against registry\n\t\t\tthis.scopedModels = this.scopedModels.map((scoped) => {\n\t\t\t\tconst refreshed = this.modelRegistry.find(scoped.model.provider, scoped.model.id);\n\t\t\t\treturn refreshed ? { ...scoped, model: refreshed } : scoped;\n\t\t\t});\n\n\t\t\tthis.cycleModelsById.clear();\n\t\t\tthis.cycleAllIds = [];\n\t\t\tfor (const item of this.allModels) {\n\t\t\t\tconst fullId = `${item.provider}/${item.id}`;\n\t\t\t\tthis.cycleModelsById.set(fullId, item.model);\n\t\t\t\tthis.cycleAllIds.push(fullId);\n\t\t\t}\n\n\t\t\tthis.rebuildManageRows();\n\t\t\tthis.applySearch();\n\t\t} catch (error) {\n\t\t\tthis.allModels = [];\n\t\t\tthis.errorMessage = error instanceof Error ? error.message : String(error);\n\t\t\tthis.applySearch();\n\t\t}\n\t}\n\n\tprivate rebuildManageRows(): void {\n\t\tconst rows: ManageRow[] = [];\n\t\trows.push({ kind: \"action\", action: \"add\", label: \"+ Add custom provider (models.json)\" });\n\n\t\tfor (const p of this.modelRegistry.listModelsJsonProviders()) {\n\t\t\tconst modelLabel =\n\t\t\t\tp.modelIds.length === 0\n\t\t\t\t\t? \"override only\"\n\t\t\t\t\t: `${p.modelIds.length} model${p.modelIds.length === 1 ? \"\" : \"s\"}`;\n\t\t\trows.push({\n\t\t\t\tkind: \"provider\",\n\t\t\t\tsource: \"models_json\",\n\t\t\t\tid: p.name,\n\t\t\t\tlabel: p.name,\n\t\t\t\tdetail: `${p.isBuiltIn ? \"built-in override\" : \"custom\"} · ${modelLabel}${p.baseUrl ? ` · ${p.baseUrl}` : \"\"}`,\n\t\t\t});\n\t\t}\n\n\t\tconst openaiCompat = this.modelRegistry.authStorage.getOpenAICompatibleProviders();\n\t\tfor (const [id, info] of Object.entries(openaiCompat)) {\n\t\t\trows.push({\n\t\t\t\tkind: \"provider\",\n\t\t\t\tsource: \"openai_compatible\",\n\t\t\t\tid,\n\t\t\t\tlabel: id,\n\t\t\t\tdetail: `openai-compatible · ${info.models.length} model${info.models.length === 1 ? \"\" : \"s\"} · ${info.baseUrl}`,\n\t\t\t});\n\t\t}\n\n\t\tthis.manageRows = rows;\n\t\tthis.manageIndex = Math.min(this.manageIndex, Math.max(0, rows.length - 1));\n\t}\n\n\t// ---- header / footer ----\n\n\tprivate getHeaderText(): string {\n\t\tconst tabs: Array<{ id: ModelHubTab; label: string }> = [\n\t\t\t{ id: \"select\", label: \"Select\" },\n\t\t\t{ id: \"cycle\", label: \"Cycle\" },\n\t\t\t{ id: \"manage\", label: \"Manage\" },\n\t\t];\n\t\tconst parts = tabs.map((t) => (t.id === this.tab ? theme.fg(\"accent\", t.label) : theme.fg(\"muted\", t.label)));\n\t\treturn `${theme.fg(\"muted\", \"Models: \")}${parts.join(theme.fg(\"muted\", \" | \"))}`;\n\t}\n\n\tprivate getHintText(): string {\n\t\tconst tabHint =\n\t\t\tkeyHint(\"tui.input.tab\", \"tabs\") +\n\t\t\ttheme.fg(\"muted\", \"/\") +\n\t\t\tkeyHint(\"app.model.hubTabPrev\", \"←\") +\n\t\t\ttheme.fg(\"muted\", \"/\") +\n\t\t\tkeyHint(\"app.model.hubTabNext\", \"→\");\n\t\tif (this.tab === \"select\") {\n\t\t\treturn tabHint + theme.fg(\"muted\", \" · type to search · Enter select · collapsed providers: Enter expand\");\n\t\t}\n\t\tif (this.tab === \"cycle\") {\n\t\t\treturn tabHint + theme.fg(\"muted\", ` · session-only until ${keyText(\"app.models.save\")}`);\n\t\t}\n\t\treturn tabHint + theme.fg(\"muted\", \" · Enter edit name/url/key/models · Backspace/Delete remove\");\n\t}\n\n\tprivate getFooterText(): string {\n\t\tif (this.tab === \"select\") {\n\t\t\tconst modelCount = this.selectRows.filter((r) => r.kind === \"model\").length;\n\t\t\treturn theme.fg(\"dim\", ` ${modelCount} model${modelCount === 1 ? \"\" : \"s\"} · Esc cancel`);\n\t\t}\n\t\tif (this.tab === \"cycle\") {\n\t\t\tconst enabledCount = this.enabledIds?.length ?? this.cycleAllIds.length;\n\t\t\tconst allEnabled = this.enabledIds === null;\n\t\t\tconst countText = allEnabled ? \"all enabled\" : `${enabledCount}/${this.cycleAllIds.length} enabled`;\n\t\t\tconst parts = [\n\t\t\t\t`${keyText(\"tui.select.confirm\")} toggle`,\n\t\t\t\t`${keyText(\"app.models.enableAll\")} all`,\n\t\t\t\t`${keyText(\"app.models.clearAll\")} clear`,\n\t\t\t\t`${keyText(\"app.models.toggleProvider\")} provider`,\n\t\t\t\t`${keyText(\"app.models.reorderUp\")}/${keyText(\"app.models.reorderDown\")} reorder`,\n\t\t\t\t`${keyText(\"app.models.save\")} save`,\n\t\t\t\tcountText,\n\t\t\t];\n\t\t\treturn this.cycleDirty\n\t\t\t\t? theme.fg(\"dim\", ` ${parts.join(\" · \")} `) + theme.fg(\"warning\", \"(unsaved)\")\n\t\t\t\t: theme.fg(\"dim\", ` ${parts.join(\" · \")}`);\n\t\t}\n\t\treturn theme.fg(\n\t\t\t\"dim\",\n\t\t\t\" Enter edit name/url/key/models · Backspace delete · writing models.json drops comments/trailing commas\",\n\t\t);\n\t}\n\n\tprivate setTab(tab: ModelHubTab): void {\n\t\tif (this.tab === tab) return;\n\t\tthis.tab = tab;\n\t\tthis.headerText.setText(this.getHeaderText());\n\t\tthis.hintText.setText(this.getHintText());\n\t\tthis.applySearch();\n\t}\n\n\tprivate cycleTab(delta: number = 1): void {\n\t\tconst order: ModelHubTab[] = [\"select\", \"cycle\", \"manage\"];\n\t\tconst idx = order.indexOf(this.tab);\n\t\tconst next = (idx + delta + order.length * 10) % order.length;\n\t\tthis.setTab(order[next]!);\n\t}\n\n\t/** Left/right switch tabs only when the search box is empty, so typing is unaffected. */\n\tprivate trySwitchTabWithArrows(keyData: string, kb: ReturnType<typeof getKeybindings>): boolean {\n\t\tif (this.searchInput.getValue()) return false;\n\t\tif (kb.matches(keyData, \"app.model.hubTabNext\") || matchesKey(keyData, Key.right)) {\n\t\t\tthis.cycleTab(1);\n\t\t\treturn true;\n\t\t}\n\t\tif (kb.matches(keyData, \"app.model.hubTabPrev\") || matchesKey(keyData, Key.left)) {\n\t\t\tthis.cycleTab(-1);\n\t\t\treturn true;\n\t\t}\n\t\treturn false;\n\t}\n\n\t// ---- list building ----\n\n\tprivate applySearch(): void {\n\t\tconst query = this.searchInput.getValue();\n\n\t\tif (this.tab === \"select\") {\n\t\t\tthis.selectRows = buildSelectRows({\n\t\t\t\tmodels: this.allModels,\n\t\t\t\tcurrentModel: this.currentModel,\n\t\t\t\trecentKeys: this.settingsManager.getRecentModels(),\n\t\t\t\tquery,\n\t\t\t\texpandedProviders: this.expandedProviders,\n\t\t\t});\n\t\t\t// Prefer current model selection\n\t\t\tconst currentIdx = this.selectRows.findIndex(\n\t\t\t\t(r) => r.kind === \"model\" && modelsAreEqual(this.currentModel, r.item.model),\n\t\t\t);\n\t\t\tthis.selectIndex =\n\t\t\t\tcurrentIdx >= 0 ? currentIdx : Math.min(this.selectIndex, Math.max(0, this.selectRows.length - 1));\n\t\t\t// Snap to first selectable if landing on header\n\t\t\tthis.ensureSelectableIndex(\"select\");\n\t\t} else if (this.tab === \"cycle\") {\n\t\t\tconst items = getSortedIds(this.enabledIds, this.cycleAllIds)\n\t\t\t\t.filter((id) => this.cycleModelsById.has(id))\n\t\t\t\t.map((id) => ({\n\t\t\t\t\tfullId: id,\n\t\t\t\t\tmodel: this.cycleModelsById.get(id)!,\n\t\t\t\t\tenabled: isEnabled(this.enabledIds, id),\n\t\t\t\t}));\n\t\t\tthis.cycleItems = query ? fuzzyFilter(items, query, (i) => `${i.model.id} ${i.model.provider}`) : items;\n\t\t\tthis.cycleIndex = Math.min(this.cycleIndex, Math.max(0, this.cycleItems.length - 1));\n\t\t} else {\n\t\t\tthis.rebuildManageRows();\n\t\t\tif (query) {\n\t\t\t\tthis.manageRows = fuzzyFilter(this.manageRows, query, (r) =>\n\t\t\t\t\tr.kind === \"action\" ? r.label : `${r.label} ${r.detail} ${r.id}`,\n\t\t\t\t);\n\t\t\t}\n\t\t\tthis.manageIndex = Math.min(this.manageIndex, Math.max(0, this.manageRows.length - 1));\n\t\t}\n\n\t\tthis.updateList();\n\t\tthis.footerText.setText(this.getFooterText());\n\t}\n\n\tprivate ensureSelectableIndex(which: \"select\"): void {\n\t\tif (which !== \"select\" || this.selectRows.length === 0) return;\n\t\tif (this.selectRows[this.selectIndex]?.kind === \"header\") {\n\t\t\tconst next = this.selectRows.findIndex((r, i) => i >= this.selectIndex && r.kind !== \"header\");\n\t\t\tif (next >= 0) {\n\t\t\t\tthis.selectIndex = next;\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tconst prev = [...this.selectRows]\n\t\t\t\t.map((r, i) => ({ r, i }))\n\t\t\t\t.reverse()\n\t\t\t\t.find(({ r }) => r.kind !== \"header\");\n\t\t\tif (prev) this.selectIndex = prev.i;\n\t\t}\n\t}\n\n\tprivate updateList(): void {\n\t\tthis.listContainer.clear();\n\n\t\tif (this.errorMessage && this.tab !== \"manage\") {\n\t\t\tfor (const line of this.errorMessage.split(\"\\n\")) {\n\t\t\t\tthis.listContainer.addChild(new Text(theme.fg(\"error\", line), 0, 0));\n\t\t\t}\n\t\t}\n\n\t\tif (this.tab === \"select\") {\n\t\t\tthis.renderSelectList();\n\t\t} else if (this.tab === \"cycle\") {\n\t\t\tthis.renderCycleList();\n\t\t} else {\n\t\t\tthis.renderManageList();\n\t\t}\n\t}\n\n\tprivate renderSelectList(): void {\n\t\tif (this.selectRows.length === 0) {\n\t\t\tthis.listContainer.addChild(new Text(theme.fg(\"muted\", \" No matching models\"), 0, 0));\n\t\t\treturn;\n\t\t}\n\n\t\tconst startIndex = Math.max(\n\t\t\t0,\n\t\t\tMath.min(this.selectIndex - Math.floor(this.maxVisible / 2), this.selectRows.length - this.maxVisible),\n\t\t);\n\t\tconst endIndex = Math.min(startIndex + this.maxVisible, this.selectRows.length);\n\n\t\tfor (let i = startIndex; i < endIndex; i++) {\n\t\t\tconst row = this.selectRows[i]!;\n\t\t\tconst isSelected = i === this.selectIndex;\n\n\t\t\tif (row.kind === \"header\") {\n\t\t\t\tthis.listContainer.addChild(new Text(theme.fg(\"muted\", ` ── ${row.label} ──`), 0, 0));\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif (row.kind === \"collapsed\") {\n\t\t\t\tconst prefix = isSelected ? theme.fg(\"accent\", \"→ \") : \" \";\n\t\t\t\tconst text = isSelected\n\t\t\t\t\t? theme.fg(\"accent\", `▸ ${row.provider} (${row.count})`)\n\t\t\t\t\t: theme.fg(\"muted\", `▸ ${row.provider} (${row.count})`);\n\t\t\t\tthis.listContainer.addChild(new Text(`${prefix}${text}`, 0, 0));\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tconst isCurrent = modelsAreEqual(this.currentModel, row.item.model);\n\t\t\tconst prefix = isSelected ? theme.fg(\"accent\", \"→ \") : \" \";\n\t\t\tconst modelText = isSelected ? theme.fg(\"accent\", row.item.id) : row.item.id;\n\t\t\tconst providerBadge = theme.fg(\"muted\", ` [${row.item.provider}]`);\n\t\t\tconst badges = theme.fg(\"dim\", ` ${row.badges}`);\n\t\t\tconst check = isCurrent ? theme.fg(\"success\", \" ✓\") : \"\";\n\t\t\tthis.listContainer.addChild(new Text(`${prefix}${modelText}${providerBadge}${badges}${check}`, 0, 0));\n\t\t}\n\n\t\tif (startIndex > 0 || endIndex < this.selectRows.length) {\n\t\t\tthis.listContainer.addChild(\n\t\t\t\tnew Text(theme.fg(\"muted\", ` (${this.selectIndex + 1}/${this.selectRows.length})`), 0, 0),\n\t\t\t);\n\t\t}\n\n\t\tconst selected = this.selectRows[this.selectIndex];\n\t\tif (selected?.kind === \"model\") {\n\t\t\tthis.listContainer.addChild(new Spacer(1));\n\t\t\tthis.listContainer.addChild(new Text(theme.fg(\"muted\", ` ${selected.item.model.name}`), 0, 0));\n\t\t}\n\t}\n\n\tprivate renderCycleList(): void {\n\t\tif (this.cycleItems.length === 0) {\n\t\t\tthis.listContainer.addChild(new Text(theme.fg(\"muted\", \" No matching models\"), 0, 0));\n\t\t\treturn;\n\t\t}\n\n\t\tconst startIndex = Math.max(\n\t\t\t0,\n\t\t\tMath.min(this.cycleIndex - Math.floor(this.maxVisible / 2), this.cycleItems.length - this.maxVisible),\n\t\t);\n\t\tconst endIndex = Math.min(startIndex + this.maxVisible, this.cycleItems.length);\n\t\tconst allEnabled = this.enabledIds === null;\n\n\t\tfor (let i = startIndex; i < endIndex; i++) {\n\t\t\tconst item = this.cycleItems[i]!;\n\t\t\tconst isSelected = i === this.cycleIndex;\n\t\t\tconst prefix = isSelected ? theme.fg(\"accent\", \"→ \") : \" \";\n\t\t\tconst modelText = isSelected ? theme.fg(\"accent\", item.model.id) : item.model.id;\n\t\t\tconst providerBadge = theme.fg(\"muted\", ` [${item.model.provider}]`);\n\t\t\tconst status = allEnabled ? \"\" : item.enabled ? theme.fg(\"success\", \" ✓\") : theme.fg(\"dim\", \" ✗\");\n\t\t\tthis.listContainer.addChild(new Text(`${prefix}${modelText}${providerBadge}${status}`, 0, 0));\n\t\t}\n\n\t\tif (startIndex > 0 || endIndex < this.cycleItems.length) {\n\t\t\tthis.listContainer.addChild(\n\t\t\t\tnew Text(theme.fg(\"muted\", ` (${this.cycleIndex + 1}/${this.cycleItems.length})`), 0, 0),\n\t\t\t);\n\t\t}\n\n\t\tif (this.cycleItems.length > 0) {\n\t\t\tconst selected = this.cycleItems[this.cycleIndex];\n\t\t\tthis.listContainer.addChild(new Spacer(1));\n\t\t\tthis.listContainer.addChild(new Text(theme.fg(\"muted\", ` ${selected?.model.name}`), 0, 0));\n\t\t}\n\t}\n\n\tprivate renderManageList(): void {\n\t\tif (this.manageRows.length === 0) {\n\t\t\tthis.listContainer.addChild(new Text(theme.fg(\"muted\", \" No custom providers\"), 0, 0));\n\t\t\treturn;\n\t\t}\n\n\t\tconst startIndex = Math.max(\n\t\t\t0,\n\t\t\tMath.min(this.manageIndex - Math.floor(this.maxVisible / 2), this.manageRows.length - this.maxVisible),\n\t\t);\n\t\tconst endIndex = Math.min(startIndex + this.maxVisible, this.manageRows.length);\n\n\t\tfor (let i = startIndex; i < endIndex; i++) {\n\t\t\tconst row = this.manageRows[i]!;\n\t\t\tconst isSelected = i === this.manageIndex;\n\t\t\tconst prefix = isSelected ? theme.fg(\"accent\", \"→ \") : \" \";\n\t\t\tif (row.kind === \"action\") {\n\t\t\t\tconst text = isSelected ? theme.fg(\"accent\", row.label) : theme.fg(\"success\", row.label);\n\t\t\t\tthis.listContainer.addChild(new Text(`${prefix}${text}`, 0, 0));\n\t\t\t} else {\n\t\t\t\tconst text = isSelected ? theme.fg(\"accent\", row.label) : row.label;\n\t\t\t\tconst detail = theme.fg(\"muted\", ` ${row.detail}`);\n\t\t\t\tthis.listContainer.addChild(new Text(`${prefix}${text}`, 0, 0));\n\t\t\t\tthis.listContainer.addChild(new Text(`${detail}`, 0, 0));\n\t\t\t}\n\t\t}\n\t}\n\n\t// ---- input ----\n\n\thandleInput(keyData: string): void {\n\t\tconst kb = getKeybindings();\n\n\t\tif (kb.matches(keyData, \"tui.input.tab\")) {\n\t\t\tthis.cycleTab(1);\n\t\t\treturn;\n\t\t}\n\n\t\tif (this.trySwitchTabWithArrows(keyData, kb)) {\n\t\t\treturn;\n\t\t}\n\n\t\tif (kb.matches(keyData, \"tui.select.cancel\") || matchesKey(keyData, Key.escape)) {\n\t\t\tthis.callbacks.onCancel();\n\t\t\treturn;\n\t\t}\n\n\t\tif (matchesKey(keyData, Key.ctrl(\"c\"))) {\n\t\t\tif (this.searchInput.getValue()) {\n\t\t\t\tthis.searchInput.setValue(\"\");\n\t\t\t\tthis.applySearch();\n\t\t\t} else {\n\t\t\t\tthis.callbacks.onCancel();\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\n\t\tif (this.tab === \"select\") {\n\t\t\tthis.handleSelectInput(keyData, kb);\n\t\t} else if (this.tab === \"cycle\") {\n\t\t\tthis.handleCycleInput(keyData, kb);\n\t\t} else {\n\t\t\tthis.handleManageInput(keyData, kb);\n\t\t}\n\t}\n\n\tprivate handleSelectInput(keyData: string, kb: ReturnType<typeof getKeybindings>): void {\n\t\tif (kb.matches(keyData, \"tui.select.up\")) {\n\t\t\tif (this.selectRows.length === 0) return;\n\t\t\tlet next = this.selectIndex === 0 ? this.selectRows.length - 1 : this.selectIndex - 1;\n\t\t\t// Skip headers when moving\n\t\t\tfor (let guard = 0; guard < this.selectRows.length; guard++) {\n\t\t\t\tif (this.selectRows[next]?.kind !== \"header\") break;\n\t\t\t\tnext = next === 0 ? this.selectRows.length - 1 : next - 1;\n\t\t\t}\n\t\t\tthis.selectIndex = next;\n\t\t\tthis.updateList();\n\t\t\treturn;\n\t\t}\n\t\tif (kb.matches(keyData, \"tui.select.down\")) {\n\t\t\tif (this.selectRows.length === 0) return;\n\t\t\tlet next = this.selectIndex === this.selectRows.length - 1 ? 0 : this.selectIndex + 1;\n\t\t\tfor (let guard = 0; guard < this.selectRows.length; guard++) {\n\t\t\t\tif (this.selectRows[next]?.kind !== \"header\") break;\n\t\t\t\tnext = next === this.selectRows.length - 1 ? 0 : next + 1;\n\t\t\t}\n\t\t\tthis.selectIndex = next;\n\t\t\tthis.updateList();\n\t\t\treturn;\n\t\t}\n\t\tif (kb.matches(keyData, \"tui.select.confirm\")) {\n\t\t\tthis.handleConfirm();\n\t\t\treturn;\n\t\t}\n\n\t\tthis.searchInput.handleInput(keyData);\n\t\tthis.applySearch();\n\t}\n\n\tprivate handleCycleInput(keyData: string, kb: ReturnType<typeof getKeybindings>): void {\n\t\tif (kb.matches(keyData, \"tui.select.up\")) {\n\t\t\tif (this.cycleItems.length === 0) return;\n\t\t\tthis.cycleIndex = this.cycleIndex === 0 ? this.cycleItems.length - 1 : this.cycleIndex - 1;\n\t\t\tthis.updateList();\n\t\t\treturn;\n\t\t}\n\t\tif (kb.matches(keyData, \"tui.select.down\")) {\n\t\t\tif (this.cycleItems.length === 0) return;\n\t\t\tthis.cycleIndex = this.cycleIndex === this.cycleItems.length - 1 ? 0 : this.cycleIndex + 1;\n\t\t\tthis.updateList();\n\t\t\treturn;\n\t\t}\n\n\t\tconst reorderUp = kb.matches(keyData, \"app.models.reorderUp\");\n\t\tconst reorderDown = kb.matches(keyData, \"app.models.reorderDown\");\n\t\tif (reorderUp || reorderDown) {\n\t\t\tif (this.enabledIds === null) return;\n\t\t\tconst item = this.cycleItems[this.cycleIndex];\n\t\t\tif (item && isEnabled(this.enabledIds, item.fullId)) {\n\t\t\t\tconst delta = reorderUp ? -1 : 1;\n\t\t\t\tconst currentIndex = this.enabledIds.indexOf(item.fullId);\n\t\t\t\tconst newIndex = currentIndex + delta;\n\t\t\t\tif (newIndex >= 0 && newIndex < this.enabledIds.length) {\n\t\t\t\t\tthis.enabledIds = move(this.enabledIds, item.fullId, delta);\n\t\t\t\t\tthis.cycleDirty = true;\n\t\t\t\t\tthis.cycleIndex += delta;\n\t\t\t\t\tthis.applySearch();\n\t\t\t\t\tvoid this.callbacks.onCycleChange(this.enabledIds === null ? null : [...this.enabledIds]);\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\n\t\tif (kb.matches(keyData, \"tui.select.confirm\")) {\n\t\t\tconst item = this.cycleItems[this.cycleIndex];\n\t\t\tif (item) {\n\t\t\t\tthis.enabledIds = toggle(this.enabledIds, item.fullId);\n\t\t\t\tthis.cycleDirty = true;\n\t\t\t\tthis.applySearch();\n\t\t\t\tvoid this.callbacks.onCycleChange(this.enabledIds === null ? null : [...this.enabledIds]);\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\n\t\tif (kb.matches(keyData, \"app.models.enableAll\")) {\n\t\t\tconst targetIds = this.searchInput.getValue() ? this.cycleItems.map((i) => i.fullId) : undefined;\n\t\t\tthis.enabledIds = enableAll(this.enabledIds, this.cycleAllIds, targetIds);\n\t\t\tthis.cycleDirty = true;\n\t\t\tthis.applySearch();\n\t\t\tvoid this.callbacks.onCycleChange(this.enabledIds === null ? null : [...this.enabledIds]);\n\t\t\treturn;\n\t\t}\n\n\t\tif (kb.matches(keyData, \"app.models.clearAll\")) {\n\t\t\tconst targetIds = this.searchInput.getValue() ? this.cycleItems.map((i) => i.fullId) : undefined;\n\t\t\tthis.enabledIds = clearAll(this.enabledIds, this.cycleAllIds, targetIds);\n\t\t\tthis.cycleDirty = true;\n\t\t\tthis.applySearch();\n\t\t\tvoid this.callbacks.onCycleChange(this.enabledIds === null ? null : [...this.enabledIds]);\n\t\t\treturn;\n\t\t}\n\n\t\tif (kb.matches(keyData, \"app.models.toggleProvider\")) {\n\t\t\tconst item = this.cycleItems[this.cycleIndex];\n\t\t\tif (item) {\n\t\t\t\tconst provider = item.model.provider;\n\t\t\t\tconst providerIds = this.cycleAllIds.filter((id) => this.cycleModelsById.get(id)!.provider === provider);\n\t\t\t\tconst allOn = providerIds.every((id) => isEnabled(this.enabledIds, id));\n\t\t\t\tthis.enabledIds = allOn\n\t\t\t\t\t? clearAll(this.enabledIds, this.cycleAllIds, providerIds)\n\t\t\t\t\t: enableAll(this.enabledIds, this.cycleAllIds, providerIds);\n\t\t\t\tthis.cycleDirty = true;\n\t\t\t\tthis.applySearch();\n\t\t\t\tvoid this.callbacks.onCycleChange(this.enabledIds === null ? null : [...this.enabledIds]);\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\n\t\tif (kb.matches(keyData, \"app.models.save\")) {\n\t\t\tvoid this.callbacks.onCyclePersist(this.enabledIds === null ? null : [...this.enabledIds]);\n\t\t\tthis.cycleDirty = false;\n\t\t\tthis.footerText.setText(this.getFooterText());\n\t\t\treturn;\n\t\t}\n\n\t\tthis.searchInput.handleInput(keyData);\n\t\tthis.applySearch();\n\t}\n\n\tprivate handleManageInput(keyData: string, kb: ReturnType<typeof getKeybindings>): void {\n\t\tif (kb.matches(keyData, \"tui.select.up\")) {\n\t\t\tif (this.manageRows.length === 0) return;\n\t\t\tthis.manageIndex = this.manageIndex === 0 ? this.manageRows.length - 1 : this.manageIndex - 1;\n\t\t\tthis.updateList();\n\t\t\treturn;\n\t\t}\n\t\tif (kb.matches(keyData, \"tui.select.down\")) {\n\t\t\tif (this.manageRows.length === 0) return;\n\t\t\tthis.manageIndex = this.manageIndex === this.manageRows.length - 1 ? 0 : this.manageIndex + 1;\n\t\t\tthis.updateList();\n\t\t\treturn;\n\t\t}\n\t\tif (kb.matches(keyData, \"tui.select.confirm\")) {\n\t\t\tthis.handleConfirm();\n\t\t\treturn;\n\t\t}\n\t\t// Backspace / Delete remove selected provider\n\t\tif (matchesKey(keyData, Key.backspace) || matchesKey(keyData, Key.delete)) {\n\t\t\tconst row = this.manageRows[this.manageIndex];\n\t\t\tif (row?.kind === \"provider\") {\n\t\t\t\tvoid this.callbacks.onManageRemove(row.source, row.id);\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\n\t\tthis.searchInput.handleInput(keyData);\n\t\tthis.applySearch();\n\t}\n\n\tprivate handleConfirm(): void {\n\t\tif (this.tab === \"select\") {\n\t\t\tconst row = this.selectRows[this.selectIndex];\n\t\t\tif (!row) return;\n\t\t\tif (row.kind === \"collapsed\") {\n\t\t\t\tthis.expandedProviders.add(row.provider);\n\t\t\t\tthis.applySearch();\n\t\t\t\t// Move selection to first model under that provider\n\t\t\t\tconst idx = this.selectRows.findIndex((r) => r.kind === \"model\" && r.item.provider === row.provider);\n\t\t\t\tif (idx >= 0) this.selectIndex = idx;\n\t\t\t\tthis.updateList();\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif (row.kind === \"model\") {\n\t\t\t\tthis.settingsManager.setDefaultModelAndProvider(row.item.model.provider, row.item.model.id);\n\t\t\t\tvoid this.callbacks.onSelectModel(row.item.model);\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\n\t\tif (this.tab === \"cycle\") {\n\t\t\tconst item = this.cycleItems[this.cycleIndex];\n\t\t\tif (item) {\n\t\t\t\tthis.enabledIds = toggle(this.enabledIds, item.fullId);\n\t\t\t\tthis.cycleDirty = true;\n\t\t\t\tthis.applySearch();\n\t\t\t\tvoid this.callbacks.onCycleChange(this.enabledIds === null ? null : [...this.enabledIds]);\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\n\t\tconst row = this.manageRows[this.manageIndex];\n\t\tif (!row) return;\n\t\tif (row.kind === \"action\" && row.action === \"add\") {\n\t\t\tvoid this.callbacks.onManageAdd();\n\t\t\treturn;\n\t\t}\n\t\tif (row.kind === \"provider\") {\n\t\t\tvoid this.callbacks.onManageEdit(row.source, row.id);\n\t\t}\n\t}\n\n\t/** Called by parent after manage mutation so list refreshes. */\n\tasync refreshAfterManage(): Promise<void> {\n\t\tawait this.reload();\n\t\tthis.tui.requestRender();\n\t}\n}\n\n/** Back-compat alias used by older tests/imports. */\nexport { ModelHubComponent as ModelSelectorComponent };\n"]}
@@ -312,14 +312,18 @@ export class ModelHubComponent extends Container {
312
312
  return `${theme.fg("muted", "Models: ")}${parts.join(theme.fg("muted", " | "))}`;
313
313
  }
314
314
  getHintText() {
315
+ const tabHint = keyHint("tui.input.tab", "tabs") +
316
+ theme.fg("muted", "/") +
317
+ keyHint("app.model.hubTabPrev", "←") +
318
+ theme.fg("muted", "/") +
319
+ keyHint("app.model.hubTabNext", "→");
315
320
  if (this.tab === "select") {
316
- return (keyHint("tui.input.tab", "tabs") +
317
- theme.fg("muted", " · type to search · Enter select · collapsed providers: Enter expand"));
321
+ return tabHint + theme.fg("muted", " · type to search · Enter select · collapsed providers: Enter expand");
318
322
  }
319
323
  if (this.tab === "cycle") {
320
- return (keyHint("tui.input.tab", "tabs") + theme.fg("muted", ` · session-only until ${keyText("app.models.save")}`));
324
+ return tabHint + theme.fg("muted", ` · session-only until ${keyText("app.models.save")}`);
321
325
  }
322
- return keyHint("tui.input.tab", "tabs") + theme.fg("muted", " · Enter edit/add · Backspace/Delete remove");
326
+ return tabHint + theme.fg("muted", " · Enter edit name/url/key/models · Backspace/Delete remove");
323
327
  }
324
328
  getFooterText() {
325
329
  if (this.tab === "select") {
@@ -343,7 +347,7 @@ export class ModelHubComponent extends Container {
343
347
  ? theme.fg("dim", ` ${parts.join(" · ")} `) + theme.fg("warning", "(unsaved)")
344
348
  : theme.fg("dim", ` ${parts.join(" · ")}`);
345
349
  }
346
- return theme.fg("dim", " Enter open · Backspace delete · writing models.json drops comments/trailing commas");
350
+ return theme.fg("dim", " Enter edit name/url/key/models · Backspace delete · writing models.json drops comments/trailing commas");
347
351
  }
348
352
  setTab(tab) {
349
353
  if (this.tab === tab)
@@ -353,10 +357,25 @@ export class ModelHubComponent extends Container {
353
357
  this.hintText.setText(this.getHintText());
354
358
  this.applySearch();
355
359
  }
356
- cycleTab() {
360
+ cycleTab(delta = 1) {
357
361
  const order = ["select", "cycle", "manage"];
358
362
  const idx = order.indexOf(this.tab);
359
- this.setTab(order[(idx + 1) % order.length]);
363
+ const next = (idx + delta + order.length * 10) % order.length;
364
+ this.setTab(order[next]);
365
+ }
366
+ /** Left/right switch tabs only when the search box is empty, so typing is unaffected. */
367
+ trySwitchTabWithArrows(keyData, kb) {
368
+ if (this.searchInput.getValue())
369
+ return false;
370
+ if (kb.matches(keyData, "app.model.hubTabNext") || matchesKey(keyData, Key.right)) {
371
+ this.cycleTab(1);
372
+ return true;
373
+ }
374
+ if (kb.matches(keyData, "app.model.hubTabPrev") || matchesKey(keyData, Key.left)) {
375
+ this.cycleTab(-1);
376
+ return true;
377
+ }
378
+ return false;
360
379
  }
361
380
  // ---- list building ----
362
381
  applySearch() {
@@ -523,7 +542,10 @@ export class ModelHubComponent extends Container {
523
542
  handleInput(keyData) {
524
543
  const kb = getKeybindings();
525
544
  if (kb.matches(keyData, "tui.input.tab")) {
526
- this.cycleTab();
545
+ this.cycleTab(1);
546
+ return;
547
+ }
548
+ if (this.trySwitchTabWithArrows(keyData, kb)) {
527
549
  return;
528
550
  }
529
551
  if (kb.matches(keyData, "tui.select.cancel") || matchesKey(keyData, Key.escape)) {
@@ -1 +1 @@
1
- {"version":3,"file":"model-hub.js","sourceRoot":"","sources":["../../../../src/modes/interactive/components/model-hub.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Unified model hub: Select current model, manage cycle whitelist, manage custom providers.\n */\n\nimport { type Model, modelsAreEqual } from \"@openeryc/pi-ai\";\nimport {\n\tContainer,\n\ttype Focusable,\n\tfuzzyFilter,\n\tgetKeybindings,\n\tInput,\n\tKey,\n\tmatchesKey,\n\tSpacer,\n\tText,\n\ttype TUI,\n} from \"@openeryc/pi-tui\";\nimport type { ModelRegistry } from \"../../../core/model-registry.ts\";\nimport type { SettingsManager } from \"../../../core/settings-manager.ts\";\nimport { theme } from \"../theme/theme.ts\";\nimport { DynamicBorder } from \"./dynamic-border.ts\";\nimport { keyHint, keyText } from \"./keybinding-hints.ts\";\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\nexport type ModelHubTab = \"select\" | \"cycle\" | \"manage\";\n\ninterface ModelItem {\n\tprovider: string;\n\tid: string;\n\tmodel: Model<any>;\n}\n\ninterface ScopedModelItem {\n\tmodel: Model<any>;\n\tthinkingLevel?: string;\n}\n\ntype EnabledIds = string[] | null;\n\ntype SelectRow =\n\t| { kind: \"header\"; label: string }\n\t| { kind: \"collapsed\"; provider: string; count: number }\n\t| { kind: \"model\"; item: ModelItem; badges: string };\n\ntype ManageRow =\n\t| {\n\t\t\tkind: \"provider\";\n\t\t\tsource: \"models_json\" | \"openai_compatible\";\n\t\t\tid: string;\n\t\t\tlabel: string;\n\t\t\tdetail: string;\n\t }\n\t| { kind: \"action\"; action: \"add\"; label: string };\n\nexport interface ModelHubCallbacks {\n\tonSelectModel: (model: Model<any>) => void | Promise<void>;\n\tonCancel: () => void;\n\t/** Cycle tab: session-only scope change */\n\tonCycleChange: (enabledModelIds: string[] | null) => void | Promise<void>;\n\t/** Cycle tab: persist to settings */\n\tonCyclePersist: (enabledModelIds: string[] | null) => void | Promise<void>;\n\t/** Manage tab: open add-provider wizard (writes models.json by default) */\n\tonManageAdd: () => void | Promise<void>;\n\t/** Manage tab: edit existing custom/openai_compatible provider */\n\tonManageEdit: (source: \"models_json\" | \"openai_compatible\", providerId: string) => void | Promise<void>;\n\t/** Manage tab: remove provider */\n\tonManageRemove: (source: \"models_json\" | \"openai_compatible\", providerId: string) => void | Promise<void>;\n}\n\n// ---------------------------------------------------------------------------\n// Pure helpers (exported for tests)\n// ---------------------------------------------------------------------------\n\nexport function formatTokenCount(count: number): string {\n\tif (count >= 1_000_000) {\n\t\tconst millions = count / 1_000_000;\n\t\treturn millions % 1 === 0 ? `${millions}M` : `${millions.toFixed(1)}M`;\n\t}\n\tif (count >= 1_000) {\n\t\tconst thousands = count / 1_000;\n\t\treturn thousands % 1 === 0 ? `${thousands}K` : `${thousands.toFixed(1)}K`;\n\t}\n\treturn count.toString();\n}\n\nfunction modelBadges(model: Model<any>): string {\n\tconst parts: string[] = [];\n\tif (model.reasoning) parts.push(\"R\");\n\tparts.push(formatTokenCount(model.contextWindow));\n\treturn parts.join(\" \");\n}\n\nfunction isEnabled(enabledIds: EnabledIds, id: string): boolean {\n\treturn enabledIds === null || enabledIds.includes(id);\n}\n\nfunction toggle(enabledIds: EnabledIds, id: string): EnabledIds {\n\tif (enabledIds === null) return [id];\n\tconst index = enabledIds.indexOf(id);\n\tif (index >= 0) return [...enabledIds.slice(0, index), ...enabledIds.slice(index + 1)];\n\treturn [...enabledIds, id];\n}\n\nfunction enableAll(enabledIds: EnabledIds, allIds: string[], targetIds?: string[]): EnabledIds {\n\tif (enabledIds === null) return null;\n\tconst targets = targetIds ?? allIds;\n\tconst result = [...enabledIds];\n\tfor (const id of targets) {\n\t\tif (!result.includes(id)) result.push(id);\n\t}\n\treturn result.length === allIds.length ? null : result;\n}\n\nfunction clearAll(enabledIds: EnabledIds, allIds: string[], targetIds?: string[]): EnabledIds {\n\tif (enabledIds === null) {\n\t\treturn targetIds ? allIds.filter((id) => !targetIds.includes(id)) : [];\n\t}\n\tconst targets = new Set(targetIds ?? enabledIds);\n\treturn enabledIds.filter((id) => !targets.has(id));\n}\n\nfunction move(enabledIds: EnabledIds, id: string, delta: number): EnabledIds {\n\tif (enabledIds === null) return null;\n\tconst list = [...enabledIds];\n\tconst index = list.indexOf(id);\n\tif (index < 0) return list;\n\tconst newIndex = index + delta;\n\tif (newIndex < 0 || newIndex >= list.length) return list;\n\tconst result = [...list];\n\t[result[index], result[newIndex]] = [result[newIndex], result[index]];\n\treturn result;\n}\n\nfunction getSortedIds(enabledIds: EnabledIds, allIds: string[]): string[] {\n\tif (enabledIds === null) return allIds;\n\tconst enabledSet = new Set(enabledIds);\n\treturn [...enabledIds, ...allIds.filter((id) => !enabledSet.has(id))];\n}\n\nexport function buildSelectRows(options: {\n\tmodels: ModelItem[];\n\tcurrentModel?: Model<any>;\n\trecentKeys: string[];\n\tquery: string;\n\texpandedProviders: Set<string>;\n\tcollapsedLimit?: number;\n}): SelectRow[] {\n\tconst { models, currentModel, recentKeys, query, expandedProviders, collapsedLimit = 12 } = options;\n\tconst rows: SelectRow[] = [];\n\n\tif (query) {\n\t\tconst filtered = fuzzyFilter(\n\t\t\tmodels,\n\t\t\tquery,\n\t\t\t({ id, provider, model }) => `${id} ${provider} ${provider}/${id} ${model.name ?? \"\"} ${provider} ${id}`,\n\t\t);\n\t\tfor (const item of filtered) {\n\t\t\trows.push({ kind: \"model\", item, badges: modelBadges(item.model) });\n\t\t}\n\t\treturn rows;\n\t}\n\n\tconst byKey = new Map(models.map((m) => [`${m.provider}/${m.id}`, m]));\n\tconst seen = new Set<string>();\n\n\t// Current first (if available)\n\tif (currentModel) {\n\t\tconst key = `${currentModel.provider}/${currentModel.id}`;\n\t\tconst item = byKey.get(key);\n\t\tif (item) {\n\t\t\trows.push({ kind: \"header\", label: \"Current\" });\n\t\t\trows.push({ kind: \"model\", item, badges: modelBadges(item.model) });\n\t\t\tseen.add(key);\n\t\t}\n\t}\n\n\t// Recent\n\tconst recentItems: ModelItem[] = [];\n\tfor (const key of recentKeys) {\n\t\tif (seen.has(key)) continue;\n\t\tconst item = byKey.get(key);\n\t\tif (item) {\n\t\t\trecentItems.push(item);\n\t\t\tseen.add(key);\n\t\t}\n\t}\n\tif (recentItems.length > 0) {\n\t\trows.push({ kind: \"header\", label: \"Recent\" });\n\t\tfor (const item of recentItems.slice(0, 8)) {\n\t\t\trows.push({ kind: \"model\", item, badges: modelBadges(item.model) });\n\t\t}\n\t}\n\n\t// Group remaining by provider\n\tconst byProvider = new Map<string, ModelItem[]>();\n\tfor (const item of models) {\n\t\tconst key = `${item.provider}/${item.id}`;\n\t\tif (seen.has(key)) continue;\n\t\tconst list = byProvider.get(item.provider) ?? [];\n\t\tlist.push(item);\n\t\tbyProvider.set(item.provider, list);\n\t}\n\n\tconst providers = [...byProvider.keys()].sort((a, b) => a.localeCompare(b));\n\tconst currentProvider = currentModel?.provider;\n\n\tfor (const provider of providers) {\n\t\tconst list = byProvider.get(provider) ?? [];\n\t\tlist.sort((a, b) => a.id.localeCompare(b.id));\n\t\tconst expand = expandedProviders.has(provider) || provider === currentProvider || list.length <= collapsedLimit;\n\n\t\trows.push({ kind: \"header\", label: provider });\n\t\tif (!expand) {\n\t\t\trows.push({ kind: \"collapsed\", provider, count: list.length });\n\t\t\tcontinue;\n\t\t}\n\t\tfor (const item of list) {\n\t\t\trows.push({ kind: \"model\", item, badges: modelBadges(item.model) });\n\t\t}\n\t}\n\n\treturn rows;\n}\n\n// ---------------------------------------------------------------------------\n// Component\n// ---------------------------------------------------------------------------\n\nexport class ModelHubComponent extends Container implements Focusable {\n\tprivate searchInput: Input;\n\tprivate listContainer: Container;\n\tprivate headerText: Text;\n\tprivate footerText: Text;\n\tprivate hintText: Text;\n\n\tprivate _focused = false;\n\tget focused(): boolean {\n\t\treturn this._focused;\n\t}\n\tset focused(value: boolean) {\n\t\tthis._focused = value;\n\t\tthis.searchInput.focused = value;\n\t}\n\n\tprivate tui: TUI;\n\tprivate currentModel?: Model<any>;\n\tprivate settingsManager: SettingsManager;\n\tprivate modelRegistry: ModelRegistry;\n\tprivate callbacks: ModelHubCallbacks;\n\n\tprivate tab: ModelHubTab;\n\tprivate allModels: ModelItem[] = [];\n\tprivate scopedModels: ReadonlyArray<ScopedModelItem>;\n\n\t// Select state\n\tprivate selectRows: SelectRow[] = [];\n\tprivate selectIndex = 0;\n\tprivate expandedProviders = new Set<string>();\n\n\t// Cycle state\n\tprivate cycleAllIds: string[] = [];\n\tprivate cycleModelsById = new Map<string, Model<any>>();\n\tprivate enabledIds: EnabledIds = null;\n\tprivate cycleItems: Array<{ fullId: string; model: Model<any>; enabled: boolean }> = [];\n\tprivate cycleIndex = 0;\n\tprivate cycleDirty = false;\n\n\t// Manage state\n\tprivate manageRows: ManageRow[] = [];\n\tprivate manageIndex = 0;\n\n\tprivate errorMessage?: string;\n\tprivate maxVisible = 10;\n\tprivate loadGeneration = 0;\n\n\tconstructor(\n\t\ttui: TUI,\n\t\tcurrentModel: Model<any> | undefined,\n\t\tsettingsManager: SettingsManager,\n\t\tmodelRegistry: ModelRegistry,\n\t\tscopedModels: ReadonlyArray<ScopedModelItem>,\n\t\tenabledModelIds: string[] | null,\n\t\tcallbacks: ModelHubCallbacks,\n\t\toptions?: { initialTab?: ModelHubTab; initialSearchInput?: string },\n\t) {\n\t\tsuper();\n\t\tthis.tui = tui;\n\t\tthis.currentModel = currentModel;\n\t\tthis.settingsManager = settingsManager;\n\t\tthis.modelRegistry = modelRegistry;\n\t\tthis.scopedModels = scopedModels;\n\t\tthis.callbacks = callbacks;\n\t\tthis.tab = options?.initialTab ?? \"select\";\n\t\tthis.enabledIds = enabledModelIds === null ? null : [...enabledModelIds];\n\n\t\tthis.addChild(new DynamicBorder());\n\t\tthis.addChild(new Spacer(1));\n\n\t\tthis.headerText = new Text(this.getHeaderText(), 0, 0);\n\t\tthis.addChild(this.headerText);\n\t\tthis.hintText = new Text(this.getHintText(), 0, 0);\n\t\tthis.addChild(this.hintText);\n\t\tthis.addChild(new Spacer(1));\n\n\t\tthis.searchInput = new Input();\n\t\tif (options?.initialSearchInput) {\n\t\t\tthis.searchInput.setValue(options.initialSearchInput);\n\t\t}\n\t\tthis.searchInput.onSubmit = () => this.handleConfirm();\n\t\tthis.addChild(this.searchInput);\n\t\tthis.addChild(new Spacer(1));\n\n\t\tthis.listContainer = new Container();\n\t\tthis.addChild(this.listContainer);\n\t\tthis.addChild(new Spacer(1));\n\n\t\tthis.footerText = new Text(this.getFooterText(), 0, 0);\n\t\tthis.addChild(this.footerText);\n\t\tthis.addChild(new DynamicBorder());\n\n\t\tvoid this.reload().then(() => {\n\t\t\tif (options?.initialSearchInput) {\n\t\t\t\tthis.applySearch();\n\t\t\t}\n\t\t\tthis.tui.requestRender();\n\t\t});\n\t}\n\n\t// ---- public helpers for tests ----\n\n\tgetTab(): ModelHubTab {\n\t\treturn this.tab;\n\t}\n\n\tgetSearchInput(): Input {\n\t\treturn this.searchInput;\n\t}\n\n\t/** Test helper: force reload completion */\n\tasync waitForLoad(): Promise<void> {\n\t\tawait this.reload();\n\t}\n\n\t// ---- load ----\n\n\tprivate async reload(): Promise<void> {\n\t\tconst gen = ++this.loadGeneration;\n\t\tthis.modelRegistry.refresh();\n\t\tconst loadError = this.modelRegistry.getError();\n\t\tif (loadError) {\n\t\t\tthis.errorMessage = loadError;\n\t\t} else {\n\t\t\tthis.errorMessage = undefined;\n\t\t}\n\n\t\ttry {\n\t\t\tconst available = this.modelRegistry.getAvailable();\n\t\t\tif (gen !== this.loadGeneration) return;\n\n\t\t\tthis.allModels = available.map((model) => ({\n\t\t\t\tprovider: model.provider,\n\t\t\t\tid: model.id,\n\t\t\t\tmodel,\n\t\t\t}));\n\n\t\t\t// Refresh scoped models against registry\n\t\t\tthis.scopedModels = this.scopedModels.map((scoped) => {\n\t\t\t\tconst refreshed = this.modelRegistry.find(scoped.model.provider, scoped.model.id);\n\t\t\t\treturn refreshed ? { ...scoped, model: refreshed } : scoped;\n\t\t\t});\n\n\t\t\tthis.cycleModelsById.clear();\n\t\t\tthis.cycleAllIds = [];\n\t\t\tfor (const item of this.allModels) {\n\t\t\t\tconst fullId = `${item.provider}/${item.id}`;\n\t\t\t\tthis.cycleModelsById.set(fullId, item.model);\n\t\t\t\tthis.cycleAllIds.push(fullId);\n\t\t\t}\n\n\t\t\tthis.rebuildManageRows();\n\t\t\tthis.applySearch();\n\t\t} catch (error) {\n\t\t\tthis.allModels = [];\n\t\t\tthis.errorMessage = error instanceof Error ? error.message : String(error);\n\t\t\tthis.applySearch();\n\t\t}\n\t}\n\n\tprivate rebuildManageRows(): void {\n\t\tconst rows: ManageRow[] = [];\n\t\trows.push({ kind: \"action\", action: \"add\", label: \"+ Add custom provider (models.json)\" });\n\n\t\tfor (const p of this.modelRegistry.listModelsJsonProviders()) {\n\t\t\tconst modelLabel =\n\t\t\t\tp.modelIds.length === 0\n\t\t\t\t\t? \"override only\"\n\t\t\t\t\t: `${p.modelIds.length} model${p.modelIds.length === 1 ? \"\" : \"s\"}`;\n\t\t\trows.push({\n\t\t\t\tkind: \"provider\",\n\t\t\t\tsource: \"models_json\",\n\t\t\t\tid: p.name,\n\t\t\t\tlabel: p.name,\n\t\t\t\tdetail: `${p.isBuiltIn ? \"built-in override\" : \"custom\"} · ${modelLabel}${p.baseUrl ? ` · ${p.baseUrl}` : \"\"}`,\n\t\t\t});\n\t\t}\n\n\t\tconst openaiCompat = this.modelRegistry.authStorage.getOpenAICompatibleProviders();\n\t\tfor (const [id, info] of Object.entries(openaiCompat)) {\n\t\t\trows.push({\n\t\t\t\tkind: \"provider\",\n\t\t\t\tsource: \"openai_compatible\",\n\t\t\t\tid,\n\t\t\t\tlabel: id,\n\t\t\t\tdetail: `openai-compatible · ${info.models.length} model${info.models.length === 1 ? \"\" : \"s\"} · ${info.baseUrl}`,\n\t\t\t});\n\t\t}\n\n\t\tthis.manageRows = rows;\n\t\tthis.manageIndex = Math.min(this.manageIndex, Math.max(0, rows.length - 1));\n\t}\n\n\t// ---- header / footer ----\n\n\tprivate getHeaderText(): string {\n\t\tconst tabs: Array<{ id: ModelHubTab; label: string }> = [\n\t\t\t{ id: \"select\", label: \"Select\" },\n\t\t\t{ id: \"cycle\", label: \"Cycle\" },\n\t\t\t{ id: \"manage\", label: \"Manage\" },\n\t\t];\n\t\tconst parts = tabs.map((t) => (t.id === this.tab ? theme.fg(\"accent\", t.label) : theme.fg(\"muted\", t.label)));\n\t\treturn `${theme.fg(\"muted\", \"Models: \")}${parts.join(theme.fg(\"muted\", \" | \"))}`;\n\t}\n\n\tprivate getHintText(): string {\n\t\tif (this.tab === \"select\") {\n\t\t\treturn (\n\t\t\t\tkeyHint(\"tui.input.tab\", \"tabs\") +\n\t\t\t\ttheme.fg(\"muted\", \" · type to search · Enter select · collapsed providers: Enter expand\")\n\t\t\t);\n\t\t}\n\t\tif (this.tab === \"cycle\") {\n\t\t\treturn (\n\t\t\t\tkeyHint(\"tui.input.tab\", \"tabs\") + theme.fg(\"muted\", ` · session-only until ${keyText(\"app.models.save\")}`)\n\t\t\t);\n\t\t}\n\t\treturn keyHint(\"tui.input.tab\", \"tabs\") + theme.fg(\"muted\", \" · Enter edit/add · Backspace/Delete remove\");\n\t}\n\n\tprivate getFooterText(): string {\n\t\tif (this.tab === \"select\") {\n\t\t\tconst modelCount = this.selectRows.filter((r) => r.kind === \"model\").length;\n\t\t\treturn theme.fg(\"dim\", ` ${modelCount} model${modelCount === 1 ? \"\" : \"s\"} · Esc cancel`);\n\t\t}\n\t\tif (this.tab === \"cycle\") {\n\t\t\tconst enabledCount = this.enabledIds?.length ?? this.cycleAllIds.length;\n\t\t\tconst allEnabled = this.enabledIds === null;\n\t\t\tconst countText = allEnabled ? \"all enabled\" : `${enabledCount}/${this.cycleAllIds.length} enabled`;\n\t\t\tconst parts = [\n\t\t\t\t`${keyText(\"tui.select.confirm\")} toggle`,\n\t\t\t\t`${keyText(\"app.models.enableAll\")} all`,\n\t\t\t\t`${keyText(\"app.models.clearAll\")} clear`,\n\t\t\t\t`${keyText(\"app.models.toggleProvider\")} provider`,\n\t\t\t\t`${keyText(\"app.models.reorderUp\")}/${keyText(\"app.models.reorderDown\")} reorder`,\n\t\t\t\t`${keyText(\"app.models.save\")} save`,\n\t\t\t\tcountText,\n\t\t\t];\n\t\t\treturn this.cycleDirty\n\t\t\t\t? theme.fg(\"dim\", ` ${parts.join(\" · \")} `) + theme.fg(\"warning\", \"(unsaved)\")\n\t\t\t\t: theme.fg(\"dim\", ` ${parts.join(\" · \")}`);\n\t\t}\n\t\treturn theme.fg(\"dim\", \" Enter open · Backspace delete · writing models.json drops comments/trailing commas\");\n\t}\n\n\tprivate setTab(tab: ModelHubTab): void {\n\t\tif (this.tab === tab) return;\n\t\tthis.tab = tab;\n\t\tthis.headerText.setText(this.getHeaderText());\n\t\tthis.hintText.setText(this.getHintText());\n\t\tthis.applySearch();\n\t}\n\n\tprivate cycleTab(): void {\n\t\tconst order: ModelHubTab[] = [\"select\", \"cycle\", \"manage\"];\n\t\tconst idx = order.indexOf(this.tab);\n\t\tthis.setTab(order[(idx + 1) % order.length]!);\n\t}\n\n\t// ---- list building ----\n\n\tprivate applySearch(): void {\n\t\tconst query = this.searchInput.getValue();\n\n\t\tif (this.tab === \"select\") {\n\t\t\tthis.selectRows = buildSelectRows({\n\t\t\t\tmodels: this.allModels,\n\t\t\t\tcurrentModel: this.currentModel,\n\t\t\t\trecentKeys: this.settingsManager.getRecentModels(),\n\t\t\t\tquery,\n\t\t\t\texpandedProviders: this.expandedProviders,\n\t\t\t});\n\t\t\t// Prefer current model selection\n\t\t\tconst currentIdx = this.selectRows.findIndex(\n\t\t\t\t(r) => r.kind === \"model\" && modelsAreEqual(this.currentModel, r.item.model),\n\t\t\t);\n\t\t\tthis.selectIndex =\n\t\t\t\tcurrentIdx >= 0 ? currentIdx : Math.min(this.selectIndex, Math.max(0, this.selectRows.length - 1));\n\t\t\t// Snap to first selectable if landing on header\n\t\t\tthis.ensureSelectableIndex(\"select\");\n\t\t} else if (this.tab === \"cycle\") {\n\t\t\tconst items = getSortedIds(this.enabledIds, this.cycleAllIds)\n\t\t\t\t.filter((id) => this.cycleModelsById.has(id))\n\t\t\t\t.map((id) => ({\n\t\t\t\t\tfullId: id,\n\t\t\t\t\tmodel: this.cycleModelsById.get(id)!,\n\t\t\t\t\tenabled: isEnabled(this.enabledIds, id),\n\t\t\t\t}));\n\t\t\tthis.cycleItems = query ? fuzzyFilter(items, query, (i) => `${i.model.id} ${i.model.provider}`) : items;\n\t\t\tthis.cycleIndex = Math.min(this.cycleIndex, Math.max(0, this.cycleItems.length - 1));\n\t\t} else {\n\t\t\tthis.rebuildManageRows();\n\t\t\tif (query) {\n\t\t\t\tthis.manageRows = fuzzyFilter(this.manageRows, query, (r) =>\n\t\t\t\t\tr.kind === \"action\" ? r.label : `${r.label} ${r.detail} ${r.id}`,\n\t\t\t\t);\n\t\t\t}\n\t\t\tthis.manageIndex = Math.min(this.manageIndex, Math.max(0, this.manageRows.length - 1));\n\t\t}\n\n\t\tthis.updateList();\n\t\tthis.footerText.setText(this.getFooterText());\n\t}\n\n\tprivate ensureSelectableIndex(which: \"select\"): void {\n\t\tif (which !== \"select\" || this.selectRows.length === 0) return;\n\t\tif (this.selectRows[this.selectIndex]?.kind === \"header\") {\n\t\t\tconst next = this.selectRows.findIndex((r, i) => i >= this.selectIndex && r.kind !== \"header\");\n\t\t\tif (next >= 0) {\n\t\t\t\tthis.selectIndex = next;\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tconst prev = [...this.selectRows]\n\t\t\t\t.map((r, i) => ({ r, i }))\n\t\t\t\t.reverse()\n\t\t\t\t.find(({ r }) => r.kind !== \"header\");\n\t\t\tif (prev) this.selectIndex = prev.i;\n\t\t}\n\t}\n\n\tprivate updateList(): void {\n\t\tthis.listContainer.clear();\n\n\t\tif (this.errorMessage && this.tab !== \"manage\") {\n\t\t\tfor (const line of this.errorMessage.split(\"\\n\")) {\n\t\t\t\tthis.listContainer.addChild(new Text(theme.fg(\"error\", line), 0, 0));\n\t\t\t}\n\t\t}\n\n\t\tif (this.tab === \"select\") {\n\t\t\tthis.renderSelectList();\n\t\t} else if (this.tab === \"cycle\") {\n\t\t\tthis.renderCycleList();\n\t\t} else {\n\t\t\tthis.renderManageList();\n\t\t}\n\t}\n\n\tprivate renderSelectList(): void {\n\t\tif (this.selectRows.length === 0) {\n\t\t\tthis.listContainer.addChild(new Text(theme.fg(\"muted\", \" No matching models\"), 0, 0));\n\t\t\treturn;\n\t\t}\n\n\t\tconst startIndex = Math.max(\n\t\t\t0,\n\t\t\tMath.min(this.selectIndex - Math.floor(this.maxVisible / 2), this.selectRows.length - this.maxVisible),\n\t\t);\n\t\tconst endIndex = Math.min(startIndex + this.maxVisible, this.selectRows.length);\n\n\t\tfor (let i = startIndex; i < endIndex; i++) {\n\t\t\tconst row = this.selectRows[i]!;\n\t\t\tconst isSelected = i === this.selectIndex;\n\n\t\t\tif (row.kind === \"header\") {\n\t\t\t\tthis.listContainer.addChild(new Text(theme.fg(\"muted\", ` ── ${row.label} ──`), 0, 0));\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif (row.kind === \"collapsed\") {\n\t\t\t\tconst prefix = isSelected ? theme.fg(\"accent\", \"→ \") : \" \";\n\t\t\t\tconst text = isSelected\n\t\t\t\t\t? theme.fg(\"accent\", `▸ ${row.provider} (${row.count})`)\n\t\t\t\t\t: theme.fg(\"muted\", `▸ ${row.provider} (${row.count})`);\n\t\t\t\tthis.listContainer.addChild(new Text(`${prefix}${text}`, 0, 0));\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tconst isCurrent = modelsAreEqual(this.currentModel, row.item.model);\n\t\t\tconst prefix = isSelected ? theme.fg(\"accent\", \"→ \") : \" \";\n\t\t\tconst modelText = isSelected ? theme.fg(\"accent\", row.item.id) : row.item.id;\n\t\t\tconst providerBadge = theme.fg(\"muted\", ` [${row.item.provider}]`);\n\t\t\tconst badges = theme.fg(\"dim\", ` ${row.badges}`);\n\t\t\tconst check = isCurrent ? theme.fg(\"success\", \" ✓\") : \"\";\n\t\t\tthis.listContainer.addChild(new Text(`${prefix}${modelText}${providerBadge}${badges}${check}`, 0, 0));\n\t\t}\n\n\t\tif (startIndex > 0 || endIndex < this.selectRows.length) {\n\t\t\tthis.listContainer.addChild(\n\t\t\t\tnew Text(theme.fg(\"muted\", ` (${this.selectIndex + 1}/${this.selectRows.length})`), 0, 0),\n\t\t\t);\n\t\t}\n\n\t\tconst selected = this.selectRows[this.selectIndex];\n\t\tif (selected?.kind === \"model\") {\n\t\t\tthis.listContainer.addChild(new Spacer(1));\n\t\t\tthis.listContainer.addChild(new Text(theme.fg(\"muted\", ` ${selected.item.model.name}`), 0, 0));\n\t\t}\n\t}\n\n\tprivate renderCycleList(): void {\n\t\tif (this.cycleItems.length === 0) {\n\t\t\tthis.listContainer.addChild(new Text(theme.fg(\"muted\", \" No matching models\"), 0, 0));\n\t\t\treturn;\n\t\t}\n\n\t\tconst startIndex = Math.max(\n\t\t\t0,\n\t\t\tMath.min(this.cycleIndex - Math.floor(this.maxVisible / 2), this.cycleItems.length - this.maxVisible),\n\t\t);\n\t\tconst endIndex = Math.min(startIndex + this.maxVisible, this.cycleItems.length);\n\t\tconst allEnabled = this.enabledIds === null;\n\n\t\tfor (let i = startIndex; i < endIndex; i++) {\n\t\t\tconst item = this.cycleItems[i]!;\n\t\t\tconst isSelected = i === this.cycleIndex;\n\t\t\tconst prefix = isSelected ? theme.fg(\"accent\", \"→ \") : \" \";\n\t\t\tconst modelText = isSelected ? theme.fg(\"accent\", item.model.id) : item.model.id;\n\t\t\tconst providerBadge = theme.fg(\"muted\", ` [${item.model.provider}]`);\n\t\t\tconst status = allEnabled ? \"\" : item.enabled ? theme.fg(\"success\", \" ✓\") : theme.fg(\"dim\", \" ✗\");\n\t\t\tthis.listContainer.addChild(new Text(`${prefix}${modelText}${providerBadge}${status}`, 0, 0));\n\t\t}\n\n\t\tif (startIndex > 0 || endIndex < this.cycleItems.length) {\n\t\t\tthis.listContainer.addChild(\n\t\t\t\tnew Text(theme.fg(\"muted\", ` (${this.cycleIndex + 1}/${this.cycleItems.length})`), 0, 0),\n\t\t\t);\n\t\t}\n\n\t\tif (this.cycleItems.length > 0) {\n\t\t\tconst selected = this.cycleItems[this.cycleIndex];\n\t\t\tthis.listContainer.addChild(new Spacer(1));\n\t\t\tthis.listContainer.addChild(new Text(theme.fg(\"muted\", ` ${selected?.model.name}`), 0, 0));\n\t\t}\n\t}\n\n\tprivate renderManageList(): void {\n\t\tif (this.manageRows.length === 0) {\n\t\t\tthis.listContainer.addChild(new Text(theme.fg(\"muted\", \" No custom providers\"), 0, 0));\n\t\t\treturn;\n\t\t}\n\n\t\tconst startIndex = Math.max(\n\t\t\t0,\n\t\t\tMath.min(this.manageIndex - Math.floor(this.maxVisible / 2), this.manageRows.length - this.maxVisible),\n\t\t);\n\t\tconst endIndex = Math.min(startIndex + this.maxVisible, this.manageRows.length);\n\n\t\tfor (let i = startIndex; i < endIndex; i++) {\n\t\t\tconst row = this.manageRows[i]!;\n\t\t\tconst isSelected = i === this.manageIndex;\n\t\t\tconst prefix = isSelected ? theme.fg(\"accent\", \"→ \") : \" \";\n\t\t\tif (row.kind === \"action\") {\n\t\t\t\tconst text = isSelected ? theme.fg(\"accent\", row.label) : theme.fg(\"success\", row.label);\n\t\t\t\tthis.listContainer.addChild(new Text(`${prefix}${text}`, 0, 0));\n\t\t\t} else {\n\t\t\t\tconst text = isSelected ? theme.fg(\"accent\", row.label) : row.label;\n\t\t\t\tconst detail = theme.fg(\"muted\", ` ${row.detail}`);\n\t\t\t\tthis.listContainer.addChild(new Text(`${prefix}${text}`, 0, 0));\n\t\t\t\tthis.listContainer.addChild(new Text(`${detail}`, 0, 0));\n\t\t\t}\n\t\t}\n\t}\n\n\t// ---- input ----\n\n\thandleInput(keyData: string): void {\n\t\tconst kb = getKeybindings();\n\n\t\tif (kb.matches(keyData, \"tui.input.tab\")) {\n\t\t\tthis.cycleTab();\n\t\t\treturn;\n\t\t}\n\n\t\tif (kb.matches(keyData, \"tui.select.cancel\") || matchesKey(keyData, Key.escape)) {\n\t\t\tthis.callbacks.onCancel();\n\t\t\treturn;\n\t\t}\n\n\t\tif (matchesKey(keyData, Key.ctrl(\"c\"))) {\n\t\t\tif (this.searchInput.getValue()) {\n\t\t\t\tthis.searchInput.setValue(\"\");\n\t\t\t\tthis.applySearch();\n\t\t\t} else {\n\t\t\t\tthis.callbacks.onCancel();\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\n\t\tif (this.tab === \"select\") {\n\t\t\tthis.handleSelectInput(keyData, kb);\n\t\t} else if (this.tab === \"cycle\") {\n\t\t\tthis.handleCycleInput(keyData, kb);\n\t\t} else {\n\t\t\tthis.handleManageInput(keyData, kb);\n\t\t}\n\t}\n\n\tprivate handleSelectInput(keyData: string, kb: ReturnType<typeof getKeybindings>): void {\n\t\tif (kb.matches(keyData, \"tui.select.up\")) {\n\t\t\tif (this.selectRows.length === 0) return;\n\t\t\tlet next = this.selectIndex === 0 ? this.selectRows.length - 1 : this.selectIndex - 1;\n\t\t\t// Skip headers when moving\n\t\t\tfor (let guard = 0; guard < this.selectRows.length; guard++) {\n\t\t\t\tif (this.selectRows[next]?.kind !== \"header\") break;\n\t\t\t\tnext = next === 0 ? this.selectRows.length - 1 : next - 1;\n\t\t\t}\n\t\t\tthis.selectIndex = next;\n\t\t\tthis.updateList();\n\t\t\treturn;\n\t\t}\n\t\tif (kb.matches(keyData, \"tui.select.down\")) {\n\t\t\tif (this.selectRows.length === 0) return;\n\t\t\tlet next = this.selectIndex === this.selectRows.length - 1 ? 0 : this.selectIndex + 1;\n\t\t\tfor (let guard = 0; guard < this.selectRows.length; guard++) {\n\t\t\t\tif (this.selectRows[next]?.kind !== \"header\") break;\n\t\t\t\tnext = next === this.selectRows.length - 1 ? 0 : next + 1;\n\t\t\t}\n\t\t\tthis.selectIndex = next;\n\t\t\tthis.updateList();\n\t\t\treturn;\n\t\t}\n\t\tif (kb.matches(keyData, \"tui.select.confirm\")) {\n\t\t\tthis.handleConfirm();\n\t\t\treturn;\n\t\t}\n\n\t\tthis.searchInput.handleInput(keyData);\n\t\tthis.applySearch();\n\t}\n\n\tprivate handleCycleInput(keyData: string, kb: ReturnType<typeof getKeybindings>): void {\n\t\tif (kb.matches(keyData, \"tui.select.up\")) {\n\t\t\tif (this.cycleItems.length === 0) return;\n\t\t\tthis.cycleIndex = this.cycleIndex === 0 ? this.cycleItems.length - 1 : this.cycleIndex - 1;\n\t\t\tthis.updateList();\n\t\t\treturn;\n\t\t}\n\t\tif (kb.matches(keyData, \"tui.select.down\")) {\n\t\t\tif (this.cycleItems.length === 0) return;\n\t\t\tthis.cycleIndex = this.cycleIndex === this.cycleItems.length - 1 ? 0 : this.cycleIndex + 1;\n\t\t\tthis.updateList();\n\t\t\treturn;\n\t\t}\n\n\t\tconst reorderUp = kb.matches(keyData, \"app.models.reorderUp\");\n\t\tconst reorderDown = kb.matches(keyData, \"app.models.reorderDown\");\n\t\tif (reorderUp || reorderDown) {\n\t\t\tif (this.enabledIds === null) return;\n\t\t\tconst item = this.cycleItems[this.cycleIndex];\n\t\t\tif (item && isEnabled(this.enabledIds, item.fullId)) {\n\t\t\t\tconst delta = reorderUp ? -1 : 1;\n\t\t\t\tconst currentIndex = this.enabledIds.indexOf(item.fullId);\n\t\t\t\tconst newIndex = currentIndex + delta;\n\t\t\t\tif (newIndex >= 0 && newIndex < this.enabledIds.length) {\n\t\t\t\t\tthis.enabledIds = move(this.enabledIds, item.fullId, delta);\n\t\t\t\t\tthis.cycleDirty = true;\n\t\t\t\t\tthis.cycleIndex += delta;\n\t\t\t\t\tthis.applySearch();\n\t\t\t\t\tvoid this.callbacks.onCycleChange(this.enabledIds === null ? null : [...this.enabledIds]);\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\n\t\tif (kb.matches(keyData, \"tui.select.confirm\")) {\n\t\t\tconst item = this.cycleItems[this.cycleIndex];\n\t\t\tif (item) {\n\t\t\t\tthis.enabledIds = toggle(this.enabledIds, item.fullId);\n\t\t\t\tthis.cycleDirty = true;\n\t\t\t\tthis.applySearch();\n\t\t\t\tvoid this.callbacks.onCycleChange(this.enabledIds === null ? null : [...this.enabledIds]);\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\n\t\tif (kb.matches(keyData, \"app.models.enableAll\")) {\n\t\t\tconst targetIds = this.searchInput.getValue() ? this.cycleItems.map((i) => i.fullId) : undefined;\n\t\t\tthis.enabledIds = enableAll(this.enabledIds, this.cycleAllIds, targetIds);\n\t\t\tthis.cycleDirty = true;\n\t\t\tthis.applySearch();\n\t\t\tvoid this.callbacks.onCycleChange(this.enabledIds === null ? null : [...this.enabledIds]);\n\t\t\treturn;\n\t\t}\n\n\t\tif (kb.matches(keyData, \"app.models.clearAll\")) {\n\t\t\tconst targetIds = this.searchInput.getValue() ? this.cycleItems.map((i) => i.fullId) : undefined;\n\t\t\tthis.enabledIds = clearAll(this.enabledIds, this.cycleAllIds, targetIds);\n\t\t\tthis.cycleDirty = true;\n\t\t\tthis.applySearch();\n\t\t\tvoid this.callbacks.onCycleChange(this.enabledIds === null ? null : [...this.enabledIds]);\n\t\t\treturn;\n\t\t}\n\n\t\tif (kb.matches(keyData, \"app.models.toggleProvider\")) {\n\t\t\tconst item = this.cycleItems[this.cycleIndex];\n\t\t\tif (item) {\n\t\t\t\tconst provider = item.model.provider;\n\t\t\t\tconst providerIds = this.cycleAllIds.filter((id) => this.cycleModelsById.get(id)!.provider === provider);\n\t\t\t\tconst allOn = providerIds.every((id) => isEnabled(this.enabledIds, id));\n\t\t\t\tthis.enabledIds = allOn\n\t\t\t\t\t? clearAll(this.enabledIds, this.cycleAllIds, providerIds)\n\t\t\t\t\t: enableAll(this.enabledIds, this.cycleAllIds, providerIds);\n\t\t\t\tthis.cycleDirty = true;\n\t\t\t\tthis.applySearch();\n\t\t\t\tvoid this.callbacks.onCycleChange(this.enabledIds === null ? null : [...this.enabledIds]);\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\n\t\tif (kb.matches(keyData, \"app.models.save\")) {\n\t\t\tvoid this.callbacks.onCyclePersist(this.enabledIds === null ? null : [...this.enabledIds]);\n\t\t\tthis.cycleDirty = false;\n\t\t\tthis.footerText.setText(this.getFooterText());\n\t\t\treturn;\n\t\t}\n\n\t\tthis.searchInput.handleInput(keyData);\n\t\tthis.applySearch();\n\t}\n\n\tprivate handleManageInput(keyData: string, kb: ReturnType<typeof getKeybindings>): void {\n\t\tif (kb.matches(keyData, \"tui.select.up\")) {\n\t\t\tif (this.manageRows.length === 0) return;\n\t\t\tthis.manageIndex = this.manageIndex === 0 ? this.manageRows.length - 1 : this.manageIndex - 1;\n\t\t\tthis.updateList();\n\t\t\treturn;\n\t\t}\n\t\tif (kb.matches(keyData, \"tui.select.down\")) {\n\t\t\tif (this.manageRows.length === 0) return;\n\t\t\tthis.manageIndex = this.manageIndex === this.manageRows.length - 1 ? 0 : this.manageIndex + 1;\n\t\t\tthis.updateList();\n\t\t\treturn;\n\t\t}\n\t\tif (kb.matches(keyData, \"tui.select.confirm\")) {\n\t\t\tthis.handleConfirm();\n\t\t\treturn;\n\t\t}\n\t\t// Backspace / Delete remove selected provider\n\t\tif (matchesKey(keyData, Key.backspace) || matchesKey(keyData, Key.delete)) {\n\t\t\tconst row = this.manageRows[this.manageIndex];\n\t\t\tif (row?.kind === \"provider\") {\n\t\t\t\tvoid this.callbacks.onManageRemove(row.source, row.id);\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\n\t\tthis.searchInput.handleInput(keyData);\n\t\tthis.applySearch();\n\t}\n\n\tprivate handleConfirm(): void {\n\t\tif (this.tab === \"select\") {\n\t\t\tconst row = this.selectRows[this.selectIndex];\n\t\t\tif (!row) return;\n\t\t\tif (row.kind === \"collapsed\") {\n\t\t\t\tthis.expandedProviders.add(row.provider);\n\t\t\t\tthis.applySearch();\n\t\t\t\t// Move selection to first model under that provider\n\t\t\t\tconst idx = this.selectRows.findIndex((r) => r.kind === \"model\" && r.item.provider === row.provider);\n\t\t\t\tif (idx >= 0) this.selectIndex = idx;\n\t\t\t\tthis.updateList();\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif (row.kind === \"model\") {\n\t\t\t\tthis.settingsManager.setDefaultModelAndProvider(row.item.model.provider, row.item.model.id);\n\t\t\t\tvoid this.callbacks.onSelectModel(row.item.model);\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\n\t\tif (this.tab === \"cycle\") {\n\t\t\tconst item = this.cycleItems[this.cycleIndex];\n\t\t\tif (item) {\n\t\t\t\tthis.enabledIds = toggle(this.enabledIds, item.fullId);\n\t\t\t\tthis.cycleDirty = true;\n\t\t\t\tthis.applySearch();\n\t\t\t\tvoid this.callbacks.onCycleChange(this.enabledIds === null ? null : [...this.enabledIds]);\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\n\t\tconst row = this.manageRows[this.manageIndex];\n\t\tif (!row) return;\n\t\tif (row.kind === \"action\" && row.action === \"add\") {\n\t\t\tvoid this.callbacks.onManageAdd();\n\t\t\treturn;\n\t\t}\n\t\tif (row.kind === \"provider\") {\n\t\t\tvoid this.callbacks.onManageEdit(row.source, row.id);\n\t\t}\n\t}\n\n\t/** Called by parent after manage mutation so list refreshes. */\n\tasync refreshAfterManage(): Promise<void> {\n\t\tawait this.reload();\n\t\tthis.tui.requestRender();\n\t}\n}\n\n/** Back-compat alias used by older tests/imports. */\nexport { ModelHubComponent as ModelSelectorComponent };\n"]}
1
+ {"version":3,"file":"model-hub.js","sourceRoot":"","sources":["../../../../src/modes/interactive/components/model-hub.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Unified model hub: Select current model, manage cycle whitelist, manage custom providers.\n */\n\nimport { type Model, modelsAreEqual } from \"@openeryc/pi-ai\";\nimport {\n\tContainer,\n\ttype Focusable,\n\tfuzzyFilter,\n\tgetKeybindings,\n\tInput,\n\tKey,\n\tmatchesKey,\n\tSpacer,\n\tText,\n\ttype TUI,\n} from \"@openeryc/pi-tui\";\nimport type { ModelRegistry } from \"../../../core/model-registry.ts\";\nimport type { SettingsManager } from \"../../../core/settings-manager.ts\";\nimport { theme } from \"../theme/theme.ts\";\nimport { DynamicBorder } from \"./dynamic-border.ts\";\nimport { keyHint, keyText } from \"./keybinding-hints.ts\";\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\nexport type ModelHubTab = \"select\" | \"cycle\" | \"manage\";\n\ninterface ModelItem {\n\tprovider: string;\n\tid: string;\n\tmodel: Model<any>;\n}\n\ninterface ScopedModelItem {\n\tmodel: Model<any>;\n\tthinkingLevel?: string;\n}\n\ntype EnabledIds = string[] | null;\n\ntype SelectRow =\n\t| { kind: \"header\"; label: string }\n\t| { kind: \"collapsed\"; provider: string; count: number }\n\t| { kind: \"model\"; item: ModelItem; badges: string };\n\ntype ManageRow =\n\t| {\n\t\t\tkind: \"provider\";\n\t\t\tsource: \"models_json\" | \"openai_compatible\";\n\t\t\tid: string;\n\t\t\tlabel: string;\n\t\t\tdetail: string;\n\t }\n\t| { kind: \"action\"; action: \"add\"; label: string };\n\nexport interface ModelHubCallbacks {\n\tonSelectModel: (model: Model<any>) => void | Promise<void>;\n\tonCancel: () => void;\n\t/** Cycle tab: session-only scope change */\n\tonCycleChange: (enabledModelIds: string[] | null) => void | Promise<void>;\n\t/** Cycle tab: persist to settings */\n\tonCyclePersist: (enabledModelIds: string[] | null) => void | Promise<void>;\n\t/** Manage tab: open add-provider wizard (writes models.json by default) */\n\tonManageAdd: () => void | Promise<void>;\n\t/** Manage tab: edit existing custom/openai_compatible provider */\n\tonManageEdit: (source: \"models_json\" | \"openai_compatible\", providerId: string) => void | Promise<void>;\n\t/** Manage tab: remove provider */\n\tonManageRemove: (source: \"models_json\" | \"openai_compatible\", providerId: string) => void | Promise<void>;\n}\n\n// ---------------------------------------------------------------------------\n// Pure helpers (exported for tests)\n// ---------------------------------------------------------------------------\n\nexport function formatTokenCount(count: number): string {\n\tif (count >= 1_000_000) {\n\t\tconst millions = count / 1_000_000;\n\t\treturn millions % 1 === 0 ? `${millions}M` : `${millions.toFixed(1)}M`;\n\t}\n\tif (count >= 1_000) {\n\t\tconst thousands = count / 1_000;\n\t\treturn thousands % 1 === 0 ? `${thousands}K` : `${thousands.toFixed(1)}K`;\n\t}\n\treturn count.toString();\n}\n\nfunction modelBadges(model: Model<any>): string {\n\tconst parts: string[] = [];\n\tif (model.reasoning) parts.push(\"R\");\n\tparts.push(formatTokenCount(model.contextWindow));\n\treturn parts.join(\" \");\n}\n\nfunction isEnabled(enabledIds: EnabledIds, id: string): boolean {\n\treturn enabledIds === null || enabledIds.includes(id);\n}\n\nfunction toggle(enabledIds: EnabledIds, id: string): EnabledIds {\n\tif (enabledIds === null) return [id];\n\tconst index = enabledIds.indexOf(id);\n\tif (index >= 0) return [...enabledIds.slice(0, index), ...enabledIds.slice(index + 1)];\n\treturn [...enabledIds, id];\n}\n\nfunction enableAll(enabledIds: EnabledIds, allIds: string[], targetIds?: string[]): EnabledIds {\n\tif (enabledIds === null) return null;\n\tconst targets = targetIds ?? allIds;\n\tconst result = [...enabledIds];\n\tfor (const id of targets) {\n\t\tif (!result.includes(id)) result.push(id);\n\t}\n\treturn result.length === allIds.length ? null : result;\n}\n\nfunction clearAll(enabledIds: EnabledIds, allIds: string[], targetIds?: string[]): EnabledIds {\n\tif (enabledIds === null) {\n\t\treturn targetIds ? allIds.filter((id) => !targetIds.includes(id)) : [];\n\t}\n\tconst targets = new Set(targetIds ?? enabledIds);\n\treturn enabledIds.filter((id) => !targets.has(id));\n}\n\nfunction move(enabledIds: EnabledIds, id: string, delta: number): EnabledIds {\n\tif (enabledIds === null) return null;\n\tconst list = [...enabledIds];\n\tconst index = list.indexOf(id);\n\tif (index < 0) return list;\n\tconst newIndex = index + delta;\n\tif (newIndex < 0 || newIndex >= list.length) return list;\n\tconst result = [...list];\n\t[result[index], result[newIndex]] = [result[newIndex], result[index]];\n\treturn result;\n}\n\nfunction getSortedIds(enabledIds: EnabledIds, allIds: string[]): string[] {\n\tif (enabledIds === null) return allIds;\n\tconst enabledSet = new Set(enabledIds);\n\treturn [...enabledIds, ...allIds.filter((id) => !enabledSet.has(id))];\n}\n\nexport function buildSelectRows(options: {\n\tmodels: ModelItem[];\n\tcurrentModel?: Model<any>;\n\trecentKeys: string[];\n\tquery: string;\n\texpandedProviders: Set<string>;\n\tcollapsedLimit?: number;\n}): SelectRow[] {\n\tconst { models, currentModel, recentKeys, query, expandedProviders, collapsedLimit = 12 } = options;\n\tconst rows: SelectRow[] = [];\n\n\tif (query) {\n\t\tconst filtered = fuzzyFilter(\n\t\t\tmodels,\n\t\t\tquery,\n\t\t\t({ id, provider, model }) => `${id} ${provider} ${provider}/${id} ${model.name ?? \"\"} ${provider} ${id}`,\n\t\t);\n\t\tfor (const item of filtered) {\n\t\t\trows.push({ kind: \"model\", item, badges: modelBadges(item.model) });\n\t\t}\n\t\treturn rows;\n\t}\n\n\tconst byKey = new Map(models.map((m) => [`${m.provider}/${m.id}`, m]));\n\tconst seen = new Set<string>();\n\n\t// Current first (if available)\n\tif (currentModel) {\n\t\tconst key = `${currentModel.provider}/${currentModel.id}`;\n\t\tconst item = byKey.get(key);\n\t\tif (item) {\n\t\t\trows.push({ kind: \"header\", label: \"Current\" });\n\t\t\trows.push({ kind: \"model\", item, badges: modelBadges(item.model) });\n\t\t\tseen.add(key);\n\t\t}\n\t}\n\n\t// Recent\n\tconst recentItems: ModelItem[] = [];\n\tfor (const key of recentKeys) {\n\t\tif (seen.has(key)) continue;\n\t\tconst item = byKey.get(key);\n\t\tif (item) {\n\t\t\trecentItems.push(item);\n\t\t\tseen.add(key);\n\t\t}\n\t}\n\tif (recentItems.length > 0) {\n\t\trows.push({ kind: \"header\", label: \"Recent\" });\n\t\tfor (const item of recentItems.slice(0, 8)) {\n\t\t\trows.push({ kind: \"model\", item, badges: modelBadges(item.model) });\n\t\t}\n\t}\n\n\t// Group remaining by provider\n\tconst byProvider = new Map<string, ModelItem[]>();\n\tfor (const item of models) {\n\t\tconst key = `${item.provider}/${item.id}`;\n\t\tif (seen.has(key)) continue;\n\t\tconst list = byProvider.get(item.provider) ?? [];\n\t\tlist.push(item);\n\t\tbyProvider.set(item.provider, list);\n\t}\n\n\tconst providers = [...byProvider.keys()].sort((a, b) => a.localeCompare(b));\n\tconst currentProvider = currentModel?.provider;\n\n\tfor (const provider of providers) {\n\t\tconst list = byProvider.get(provider) ?? [];\n\t\tlist.sort((a, b) => a.id.localeCompare(b.id));\n\t\tconst expand = expandedProviders.has(provider) || provider === currentProvider || list.length <= collapsedLimit;\n\n\t\trows.push({ kind: \"header\", label: provider });\n\t\tif (!expand) {\n\t\t\trows.push({ kind: \"collapsed\", provider, count: list.length });\n\t\t\tcontinue;\n\t\t}\n\t\tfor (const item of list) {\n\t\t\trows.push({ kind: \"model\", item, badges: modelBadges(item.model) });\n\t\t}\n\t}\n\n\treturn rows;\n}\n\n// ---------------------------------------------------------------------------\n// Component\n// ---------------------------------------------------------------------------\n\nexport class ModelHubComponent extends Container implements Focusable {\n\tprivate searchInput: Input;\n\tprivate listContainer: Container;\n\tprivate headerText: Text;\n\tprivate footerText: Text;\n\tprivate hintText: Text;\n\n\tprivate _focused = false;\n\tget focused(): boolean {\n\t\treturn this._focused;\n\t}\n\tset focused(value: boolean) {\n\t\tthis._focused = value;\n\t\tthis.searchInput.focused = value;\n\t}\n\n\tprivate tui: TUI;\n\tprivate currentModel?: Model<any>;\n\tprivate settingsManager: SettingsManager;\n\tprivate modelRegistry: ModelRegistry;\n\tprivate callbacks: ModelHubCallbacks;\n\n\tprivate tab: ModelHubTab;\n\tprivate allModels: ModelItem[] = [];\n\tprivate scopedModels: ReadonlyArray<ScopedModelItem>;\n\n\t// Select state\n\tprivate selectRows: SelectRow[] = [];\n\tprivate selectIndex = 0;\n\tprivate expandedProviders = new Set<string>();\n\n\t// Cycle state\n\tprivate cycleAllIds: string[] = [];\n\tprivate cycleModelsById = new Map<string, Model<any>>();\n\tprivate enabledIds: EnabledIds = null;\n\tprivate cycleItems: Array<{ fullId: string; model: Model<any>; enabled: boolean }> = [];\n\tprivate cycleIndex = 0;\n\tprivate cycleDirty = false;\n\n\t// Manage state\n\tprivate manageRows: ManageRow[] = [];\n\tprivate manageIndex = 0;\n\n\tprivate errorMessage?: string;\n\tprivate maxVisible = 10;\n\tprivate loadGeneration = 0;\n\n\tconstructor(\n\t\ttui: TUI,\n\t\tcurrentModel: Model<any> | undefined,\n\t\tsettingsManager: SettingsManager,\n\t\tmodelRegistry: ModelRegistry,\n\t\tscopedModels: ReadonlyArray<ScopedModelItem>,\n\t\tenabledModelIds: string[] | null,\n\t\tcallbacks: ModelHubCallbacks,\n\t\toptions?: { initialTab?: ModelHubTab; initialSearchInput?: string },\n\t) {\n\t\tsuper();\n\t\tthis.tui = tui;\n\t\tthis.currentModel = currentModel;\n\t\tthis.settingsManager = settingsManager;\n\t\tthis.modelRegistry = modelRegistry;\n\t\tthis.scopedModels = scopedModels;\n\t\tthis.callbacks = callbacks;\n\t\tthis.tab = options?.initialTab ?? \"select\";\n\t\tthis.enabledIds = enabledModelIds === null ? null : [...enabledModelIds];\n\n\t\tthis.addChild(new DynamicBorder());\n\t\tthis.addChild(new Spacer(1));\n\n\t\tthis.headerText = new Text(this.getHeaderText(), 0, 0);\n\t\tthis.addChild(this.headerText);\n\t\tthis.hintText = new Text(this.getHintText(), 0, 0);\n\t\tthis.addChild(this.hintText);\n\t\tthis.addChild(new Spacer(1));\n\n\t\tthis.searchInput = new Input();\n\t\tif (options?.initialSearchInput) {\n\t\t\tthis.searchInput.setValue(options.initialSearchInput);\n\t\t}\n\t\tthis.searchInput.onSubmit = () => this.handleConfirm();\n\t\tthis.addChild(this.searchInput);\n\t\tthis.addChild(new Spacer(1));\n\n\t\tthis.listContainer = new Container();\n\t\tthis.addChild(this.listContainer);\n\t\tthis.addChild(new Spacer(1));\n\n\t\tthis.footerText = new Text(this.getFooterText(), 0, 0);\n\t\tthis.addChild(this.footerText);\n\t\tthis.addChild(new DynamicBorder());\n\n\t\tvoid this.reload().then(() => {\n\t\t\tif (options?.initialSearchInput) {\n\t\t\t\tthis.applySearch();\n\t\t\t}\n\t\t\tthis.tui.requestRender();\n\t\t});\n\t}\n\n\t// ---- public helpers for tests ----\n\n\tgetTab(): ModelHubTab {\n\t\treturn this.tab;\n\t}\n\n\tgetSearchInput(): Input {\n\t\treturn this.searchInput;\n\t}\n\n\t/** Test helper: force reload completion */\n\tasync waitForLoad(): Promise<void> {\n\t\tawait this.reload();\n\t}\n\n\t// ---- load ----\n\n\tprivate async reload(): Promise<void> {\n\t\tconst gen = ++this.loadGeneration;\n\t\tthis.modelRegistry.refresh();\n\t\tconst loadError = this.modelRegistry.getError();\n\t\tif (loadError) {\n\t\t\tthis.errorMessage = loadError;\n\t\t} else {\n\t\t\tthis.errorMessage = undefined;\n\t\t}\n\n\t\ttry {\n\t\t\tconst available = this.modelRegistry.getAvailable();\n\t\t\tif (gen !== this.loadGeneration) return;\n\n\t\t\tthis.allModels = available.map((model) => ({\n\t\t\t\tprovider: model.provider,\n\t\t\t\tid: model.id,\n\t\t\t\tmodel,\n\t\t\t}));\n\n\t\t\t// Refresh scoped models against registry\n\t\t\tthis.scopedModels = this.scopedModels.map((scoped) => {\n\t\t\t\tconst refreshed = this.modelRegistry.find(scoped.model.provider, scoped.model.id);\n\t\t\t\treturn refreshed ? { ...scoped, model: refreshed } : scoped;\n\t\t\t});\n\n\t\t\tthis.cycleModelsById.clear();\n\t\t\tthis.cycleAllIds = [];\n\t\t\tfor (const item of this.allModels) {\n\t\t\t\tconst fullId = `${item.provider}/${item.id}`;\n\t\t\t\tthis.cycleModelsById.set(fullId, item.model);\n\t\t\t\tthis.cycleAllIds.push(fullId);\n\t\t\t}\n\n\t\t\tthis.rebuildManageRows();\n\t\t\tthis.applySearch();\n\t\t} catch (error) {\n\t\t\tthis.allModels = [];\n\t\t\tthis.errorMessage = error instanceof Error ? error.message : String(error);\n\t\t\tthis.applySearch();\n\t\t}\n\t}\n\n\tprivate rebuildManageRows(): void {\n\t\tconst rows: ManageRow[] = [];\n\t\trows.push({ kind: \"action\", action: \"add\", label: \"+ Add custom provider (models.json)\" });\n\n\t\tfor (const p of this.modelRegistry.listModelsJsonProviders()) {\n\t\t\tconst modelLabel =\n\t\t\t\tp.modelIds.length === 0\n\t\t\t\t\t? \"override only\"\n\t\t\t\t\t: `${p.modelIds.length} model${p.modelIds.length === 1 ? \"\" : \"s\"}`;\n\t\t\trows.push({\n\t\t\t\tkind: \"provider\",\n\t\t\t\tsource: \"models_json\",\n\t\t\t\tid: p.name,\n\t\t\t\tlabel: p.name,\n\t\t\t\tdetail: `${p.isBuiltIn ? \"built-in override\" : \"custom\"} · ${modelLabel}${p.baseUrl ? ` · ${p.baseUrl}` : \"\"}`,\n\t\t\t});\n\t\t}\n\n\t\tconst openaiCompat = this.modelRegistry.authStorage.getOpenAICompatibleProviders();\n\t\tfor (const [id, info] of Object.entries(openaiCompat)) {\n\t\t\trows.push({\n\t\t\t\tkind: \"provider\",\n\t\t\t\tsource: \"openai_compatible\",\n\t\t\t\tid,\n\t\t\t\tlabel: id,\n\t\t\t\tdetail: `openai-compatible · ${info.models.length} model${info.models.length === 1 ? \"\" : \"s\"} · ${info.baseUrl}`,\n\t\t\t});\n\t\t}\n\n\t\tthis.manageRows = rows;\n\t\tthis.manageIndex = Math.min(this.manageIndex, Math.max(0, rows.length - 1));\n\t}\n\n\t// ---- header / footer ----\n\n\tprivate getHeaderText(): string {\n\t\tconst tabs: Array<{ id: ModelHubTab; label: string }> = [\n\t\t\t{ id: \"select\", label: \"Select\" },\n\t\t\t{ id: \"cycle\", label: \"Cycle\" },\n\t\t\t{ id: \"manage\", label: \"Manage\" },\n\t\t];\n\t\tconst parts = tabs.map((t) => (t.id === this.tab ? theme.fg(\"accent\", t.label) : theme.fg(\"muted\", t.label)));\n\t\treturn `${theme.fg(\"muted\", \"Models: \")}${parts.join(theme.fg(\"muted\", \" | \"))}`;\n\t}\n\n\tprivate getHintText(): string {\n\t\tconst tabHint =\n\t\t\tkeyHint(\"tui.input.tab\", \"tabs\") +\n\t\t\ttheme.fg(\"muted\", \"/\") +\n\t\t\tkeyHint(\"app.model.hubTabPrev\", \"←\") +\n\t\t\ttheme.fg(\"muted\", \"/\") +\n\t\t\tkeyHint(\"app.model.hubTabNext\", \"→\");\n\t\tif (this.tab === \"select\") {\n\t\t\treturn tabHint + theme.fg(\"muted\", \" · type to search · Enter select · collapsed providers: Enter expand\");\n\t\t}\n\t\tif (this.tab === \"cycle\") {\n\t\t\treturn tabHint + theme.fg(\"muted\", ` · session-only until ${keyText(\"app.models.save\")}`);\n\t\t}\n\t\treturn tabHint + theme.fg(\"muted\", \" · Enter edit name/url/key/models · Backspace/Delete remove\");\n\t}\n\n\tprivate getFooterText(): string {\n\t\tif (this.tab === \"select\") {\n\t\t\tconst modelCount = this.selectRows.filter((r) => r.kind === \"model\").length;\n\t\t\treturn theme.fg(\"dim\", ` ${modelCount} model${modelCount === 1 ? \"\" : \"s\"} · Esc cancel`);\n\t\t}\n\t\tif (this.tab === \"cycle\") {\n\t\t\tconst enabledCount = this.enabledIds?.length ?? this.cycleAllIds.length;\n\t\t\tconst allEnabled = this.enabledIds === null;\n\t\t\tconst countText = allEnabled ? \"all enabled\" : `${enabledCount}/${this.cycleAllIds.length} enabled`;\n\t\t\tconst parts = [\n\t\t\t\t`${keyText(\"tui.select.confirm\")} toggle`,\n\t\t\t\t`${keyText(\"app.models.enableAll\")} all`,\n\t\t\t\t`${keyText(\"app.models.clearAll\")} clear`,\n\t\t\t\t`${keyText(\"app.models.toggleProvider\")} provider`,\n\t\t\t\t`${keyText(\"app.models.reorderUp\")}/${keyText(\"app.models.reorderDown\")} reorder`,\n\t\t\t\t`${keyText(\"app.models.save\")} save`,\n\t\t\t\tcountText,\n\t\t\t];\n\t\t\treturn this.cycleDirty\n\t\t\t\t? theme.fg(\"dim\", ` ${parts.join(\" · \")} `) + theme.fg(\"warning\", \"(unsaved)\")\n\t\t\t\t: theme.fg(\"dim\", ` ${parts.join(\" · \")}`);\n\t\t}\n\t\treturn theme.fg(\n\t\t\t\"dim\",\n\t\t\t\" Enter edit name/url/key/models · Backspace delete · writing models.json drops comments/trailing commas\",\n\t\t);\n\t}\n\n\tprivate setTab(tab: ModelHubTab): void {\n\t\tif (this.tab === tab) return;\n\t\tthis.tab = tab;\n\t\tthis.headerText.setText(this.getHeaderText());\n\t\tthis.hintText.setText(this.getHintText());\n\t\tthis.applySearch();\n\t}\n\n\tprivate cycleTab(delta: number = 1): void {\n\t\tconst order: ModelHubTab[] = [\"select\", \"cycle\", \"manage\"];\n\t\tconst idx = order.indexOf(this.tab);\n\t\tconst next = (idx + delta + order.length * 10) % order.length;\n\t\tthis.setTab(order[next]!);\n\t}\n\n\t/** Left/right switch tabs only when the search box is empty, so typing is unaffected. */\n\tprivate trySwitchTabWithArrows(keyData: string, kb: ReturnType<typeof getKeybindings>): boolean {\n\t\tif (this.searchInput.getValue()) return false;\n\t\tif (kb.matches(keyData, \"app.model.hubTabNext\") || matchesKey(keyData, Key.right)) {\n\t\t\tthis.cycleTab(1);\n\t\t\treturn true;\n\t\t}\n\t\tif (kb.matches(keyData, \"app.model.hubTabPrev\") || matchesKey(keyData, Key.left)) {\n\t\t\tthis.cycleTab(-1);\n\t\t\treturn true;\n\t\t}\n\t\treturn false;\n\t}\n\n\t// ---- list building ----\n\n\tprivate applySearch(): void {\n\t\tconst query = this.searchInput.getValue();\n\n\t\tif (this.tab === \"select\") {\n\t\t\tthis.selectRows = buildSelectRows({\n\t\t\t\tmodels: this.allModels,\n\t\t\t\tcurrentModel: this.currentModel,\n\t\t\t\trecentKeys: this.settingsManager.getRecentModels(),\n\t\t\t\tquery,\n\t\t\t\texpandedProviders: this.expandedProviders,\n\t\t\t});\n\t\t\t// Prefer current model selection\n\t\t\tconst currentIdx = this.selectRows.findIndex(\n\t\t\t\t(r) => r.kind === \"model\" && modelsAreEqual(this.currentModel, r.item.model),\n\t\t\t);\n\t\t\tthis.selectIndex =\n\t\t\t\tcurrentIdx >= 0 ? currentIdx : Math.min(this.selectIndex, Math.max(0, this.selectRows.length - 1));\n\t\t\t// Snap to first selectable if landing on header\n\t\t\tthis.ensureSelectableIndex(\"select\");\n\t\t} else if (this.tab === \"cycle\") {\n\t\t\tconst items = getSortedIds(this.enabledIds, this.cycleAllIds)\n\t\t\t\t.filter((id) => this.cycleModelsById.has(id))\n\t\t\t\t.map((id) => ({\n\t\t\t\t\tfullId: id,\n\t\t\t\t\tmodel: this.cycleModelsById.get(id)!,\n\t\t\t\t\tenabled: isEnabled(this.enabledIds, id),\n\t\t\t\t}));\n\t\t\tthis.cycleItems = query ? fuzzyFilter(items, query, (i) => `${i.model.id} ${i.model.provider}`) : items;\n\t\t\tthis.cycleIndex = Math.min(this.cycleIndex, Math.max(0, this.cycleItems.length - 1));\n\t\t} else {\n\t\t\tthis.rebuildManageRows();\n\t\t\tif (query) {\n\t\t\t\tthis.manageRows = fuzzyFilter(this.manageRows, query, (r) =>\n\t\t\t\t\tr.kind === \"action\" ? r.label : `${r.label} ${r.detail} ${r.id}`,\n\t\t\t\t);\n\t\t\t}\n\t\t\tthis.manageIndex = Math.min(this.manageIndex, Math.max(0, this.manageRows.length - 1));\n\t\t}\n\n\t\tthis.updateList();\n\t\tthis.footerText.setText(this.getFooterText());\n\t}\n\n\tprivate ensureSelectableIndex(which: \"select\"): void {\n\t\tif (which !== \"select\" || this.selectRows.length === 0) return;\n\t\tif (this.selectRows[this.selectIndex]?.kind === \"header\") {\n\t\t\tconst next = this.selectRows.findIndex((r, i) => i >= this.selectIndex && r.kind !== \"header\");\n\t\t\tif (next >= 0) {\n\t\t\t\tthis.selectIndex = next;\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tconst prev = [...this.selectRows]\n\t\t\t\t.map((r, i) => ({ r, i }))\n\t\t\t\t.reverse()\n\t\t\t\t.find(({ r }) => r.kind !== \"header\");\n\t\t\tif (prev) this.selectIndex = prev.i;\n\t\t}\n\t}\n\n\tprivate updateList(): void {\n\t\tthis.listContainer.clear();\n\n\t\tif (this.errorMessage && this.tab !== \"manage\") {\n\t\t\tfor (const line of this.errorMessage.split(\"\\n\")) {\n\t\t\t\tthis.listContainer.addChild(new Text(theme.fg(\"error\", line), 0, 0));\n\t\t\t}\n\t\t}\n\n\t\tif (this.tab === \"select\") {\n\t\t\tthis.renderSelectList();\n\t\t} else if (this.tab === \"cycle\") {\n\t\t\tthis.renderCycleList();\n\t\t} else {\n\t\t\tthis.renderManageList();\n\t\t}\n\t}\n\n\tprivate renderSelectList(): void {\n\t\tif (this.selectRows.length === 0) {\n\t\t\tthis.listContainer.addChild(new Text(theme.fg(\"muted\", \" No matching models\"), 0, 0));\n\t\t\treturn;\n\t\t}\n\n\t\tconst startIndex = Math.max(\n\t\t\t0,\n\t\t\tMath.min(this.selectIndex - Math.floor(this.maxVisible / 2), this.selectRows.length - this.maxVisible),\n\t\t);\n\t\tconst endIndex = Math.min(startIndex + this.maxVisible, this.selectRows.length);\n\n\t\tfor (let i = startIndex; i < endIndex; i++) {\n\t\t\tconst row = this.selectRows[i]!;\n\t\t\tconst isSelected = i === this.selectIndex;\n\n\t\t\tif (row.kind === \"header\") {\n\t\t\t\tthis.listContainer.addChild(new Text(theme.fg(\"muted\", ` ── ${row.label} ──`), 0, 0));\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif (row.kind === \"collapsed\") {\n\t\t\t\tconst prefix = isSelected ? theme.fg(\"accent\", \"→ \") : \" \";\n\t\t\t\tconst text = isSelected\n\t\t\t\t\t? theme.fg(\"accent\", `▸ ${row.provider} (${row.count})`)\n\t\t\t\t\t: theme.fg(\"muted\", `▸ ${row.provider} (${row.count})`);\n\t\t\t\tthis.listContainer.addChild(new Text(`${prefix}${text}`, 0, 0));\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tconst isCurrent = modelsAreEqual(this.currentModel, row.item.model);\n\t\t\tconst prefix = isSelected ? theme.fg(\"accent\", \"→ \") : \" \";\n\t\t\tconst modelText = isSelected ? theme.fg(\"accent\", row.item.id) : row.item.id;\n\t\t\tconst providerBadge = theme.fg(\"muted\", ` [${row.item.provider}]`);\n\t\t\tconst badges = theme.fg(\"dim\", ` ${row.badges}`);\n\t\t\tconst check = isCurrent ? theme.fg(\"success\", \" ✓\") : \"\";\n\t\t\tthis.listContainer.addChild(new Text(`${prefix}${modelText}${providerBadge}${badges}${check}`, 0, 0));\n\t\t}\n\n\t\tif (startIndex > 0 || endIndex < this.selectRows.length) {\n\t\t\tthis.listContainer.addChild(\n\t\t\t\tnew Text(theme.fg(\"muted\", ` (${this.selectIndex + 1}/${this.selectRows.length})`), 0, 0),\n\t\t\t);\n\t\t}\n\n\t\tconst selected = this.selectRows[this.selectIndex];\n\t\tif (selected?.kind === \"model\") {\n\t\t\tthis.listContainer.addChild(new Spacer(1));\n\t\t\tthis.listContainer.addChild(new Text(theme.fg(\"muted\", ` ${selected.item.model.name}`), 0, 0));\n\t\t}\n\t}\n\n\tprivate renderCycleList(): void {\n\t\tif (this.cycleItems.length === 0) {\n\t\t\tthis.listContainer.addChild(new Text(theme.fg(\"muted\", \" No matching models\"), 0, 0));\n\t\t\treturn;\n\t\t}\n\n\t\tconst startIndex = Math.max(\n\t\t\t0,\n\t\t\tMath.min(this.cycleIndex - Math.floor(this.maxVisible / 2), this.cycleItems.length - this.maxVisible),\n\t\t);\n\t\tconst endIndex = Math.min(startIndex + this.maxVisible, this.cycleItems.length);\n\t\tconst allEnabled = this.enabledIds === null;\n\n\t\tfor (let i = startIndex; i < endIndex; i++) {\n\t\t\tconst item = this.cycleItems[i]!;\n\t\t\tconst isSelected = i === this.cycleIndex;\n\t\t\tconst prefix = isSelected ? theme.fg(\"accent\", \"→ \") : \" \";\n\t\t\tconst modelText = isSelected ? theme.fg(\"accent\", item.model.id) : item.model.id;\n\t\t\tconst providerBadge = theme.fg(\"muted\", ` [${item.model.provider}]`);\n\t\t\tconst status = allEnabled ? \"\" : item.enabled ? theme.fg(\"success\", \" ✓\") : theme.fg(\"dim\", \" ✗\");\n\t\t\tthis.listContainer.addChild(new Text(`${prefix}${modelText}${providerBadge}${status}`, 0, 0));\n\t\t}\n\n\t\tif (startIndex > 0 || endIndex < this.cycleItems.length) {\n\t\t\tthis.listContainer.addChild(\n\t\t\t\tnew Text(theme.fg(\"muted\", ` (${this.cycleIndex + 1}/${this.cycleItems.length})`), 0, 0),\n\t\t\t);\n\t\t}\n\n\t\tif (this.cycleItems.length > 0) {\n\t\t\tconst selected = this.cycleItems[this.cycleIndex];\n\t\t\tthis.listContainer.addChild(new Spacer(1));\n\t\t\tthis.listContainer.addChild(new Text(theme.fg(\"muted\", ` ${selected?.model.name}`), 0, 0));\n\t\t}\n\t}\n\n\tprivate renderManageList(): void {\n\t\tif (this.manageRows.length === 0) {\n\t\t\tthis.listContainer.addChild(new Text(theme.fg(\"muted\", \" No custom providers\"), 0, 0));\n\t\t\treturn;\n\t\t}\n\n\t\tconst startIndex = Math.max(\n\t\t\t0,\n\t\t\tMath.min(this.manageIndex - Math.floor(this.maxVisible / 2), this.manageRows.length - this.maxVisible),\n\t\t);\n\t\tconst endIndex = Math.min(startIndex + this.maxVisible, this.manageRows.length);\n\n\t\tfor (let i = startIndex; i < endIndex; i++) {\n\t\t\tconst row = this.manageRows[i]!;\n\t\t\tconst isSelected = i === this.manageIndex;\n\t\t\tconst prefix = isSelected ? theme.fg(\"accent\", \"→ \") : \" \";\n\t\t\tif (row.kind === \"action\") {\n\t\t\t\tconst text = isSelected ? theme.fg(\"accent\", row.label) : theme.fg(\"success\", row.label);\n\t\t\t\tthis.listContainer.addChild(new Text(`${prefix}${text}`, 0, 0));\n\t\t\t} else {\n\t\t\t\tconst text = isSelected ? theme.fg(\"accent\", row.label) : row.label;\n\t\t\t\tconst detail = theme.fg(\"muted\", ` ${row.detail}`);\n\t\t\t\tthis.listContainer.addChild(new Text(`${prefix}${text}`, 0, 0));\n\t\t\t\tthis.listContainer.addChild(new Text(`${detail}`, 0, 0));\n\t\t\t}\n\t\t}\n\t}\n\n\t// ---- input ----\n\n\thandleInput(keyData: string): void {\n\t\tconst kb = getKeybindings();\n\n\t\tif (kb.matches(keyData, \"tui.input.tab\")) {\n\t\t\tthis.cycleTab(1);\n\t\t\treturn;\n\t\t}\n\n\t\tif (this.trySwitchTabWithArrows(keyData, kb)) {\n\t\t\treturn;\n\t\t}\n\n\t\tif (kb.matches(keyData, \"tui.select.cancel\") || matchesKey(keyData, Key.escape)) {\n\t\t\tthis.callbacks.onCancel();\n\t\t\treturn;\n\t\t}\n\n\t\tif (matchesKey(keyData, Key.ctrl(\"c\"))) {\n\t\t\tif (this.searchInput.getValue()) {\n\t\t\t\tthis.searchInput.setValue(\"\");\n\t\t\t\tthis.applySearch();\n\t\t\t} else {\n\t\t\t\tthis.callbacks.onCancel();\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\n\t\tif (this.tab === \"select\") {\n\t\t\tthis.handleSelectInput(keyData, kb);\n\t\t} else if (this.tab === \"cycle\") {\n\t\t\tthis.handleCycleInput(keyData, kb);\n\t\t} else {\n\t\t\tthis.handleManageInput(keyData, kb);\n\t\t}\n\t}\n\n\tprivate handleSelectInput(keyData: string, kb: ReturnType<typeof getKeybindings>): void {\n\t\tif (kb.matches(keyData, \"tui.select.up\")) {\n\t\t\tif (this.selectRows.length === 0) return;\n\t\t\tlet next = this.selectIndex === 0 ? this.selectRows.length - 1 : this.selectIndex - 1;\n\t\t\t// Skip headers when moving\n\t\t\tfor (let guard = 0; guard < this.selectRows.length; guard++) {\n\t\t\t\tif (this.selectRows[next]?.kind !== \"header\") break;\n\t\t\t\tnext = next === 0 ? this.selectRows.length - 1 : next - 1;\n\t\t\t}\n\t\t\tthis.selectIndex = next;\n\t\t\tthis.updateList();\n\t\t\treturn;\n\t\t}\n\t\tif (kb.matches(keyData, \"tui.select.down\")) {\n\t\t\tif (this.selectRows.length === 0) return;\n\t\t\tlet next = this.selectIndex === this.selectRows.length - 1 ? 0 : this.selectIndex + 1;\n\t\t\tfor (let guard = 0; guard < this.selectRows.length; guard++) {\n\t\t\t\tif (this.selectRows[next]?.kind !== \"header\") break;\n\t\t\t\tnext = next === this.selectRows.length - 1 ? 0 : next + 1;\n\t\t\t}\n\t\t\tthis.selectIndex = next;\n\t\t\tthis.updateList();\n\t\t\treturn;\n\t\t}\n\t\tif (kb.matches(keyData, \"tui.select.confirm\")) {\n\t\t\tthis.handleConfirm();\n\t\t\treturn;\n\t\t}\n\n\t\tthis.searchInput.handleInput(keyData);\n\t\tthis.applySearch();\n\t}\n\n\tprivate handleCycleInput(keyData: string, kb: ReturnType<typeof getKeybindings>): void {\n\t\tif (kb.matches(keyData, \"tui.select.up\")) {\n\t\t\tif (this.cycleItems.length === 0) return;\n\t\t\tthis.cycleIndex = this.cycleIndex === 0 ? this.cycleItems.length - 1 : this.cycleIndex - 1;\n\t\t\tthis.updateList();\n\t\t\treturn;\n\t\t}\n\t\tif (kb.matches(keyData, \"tui.select.down\")) {\n\t\t\tif (this.cycleItems.length === 0) return;\n\t\t\tthis.cycleIndex = this.cycleIndex === this.cycleItems.length - 1 ? 0 : this.cycleIndex + 1;\n\t\t\tthis.updateList();\n\t\t\treturn;\n\t\t}\n\n\t\tconst reorderUp = kb.matches(keyData, \"app.models.reorderUp\");\n\t\tconst reorderDown = kb.matches(keyData, \"app.models.reorderDown\");\n\t\tif (reorderUp || reorderDown) {\n\t\t\tif (this.enabledIds === null) return;\n\t\t\tconst item = this.cycleItems[this.cycleIndex];\n\t\t\tif (item && isEnabled(this.enabledIds, item.fullId)) {\n\t\t\t\tconst delta = reorderUp ? -1 : 1;\n\t\t\t\tconst currentIndex = this.enabledIds.indexOf(item.fullId);\n\t\t\t\tconst newIndex = currentIndex + delta;\n\t\t\t\tif (newIndex >= 0 && newIndex < this.enabledIds.length) {\n\t\t\t\t\tthis.enabledIds = move(this.enabledIds, item.fullId, delta);\n\t\t\t\t\tthis.cycleDirty = true;\n\t\t\t\t\tthis.cycleIndex += delta;\n\t\t\t\t\tthis.applySearch();\n\t\t\t\t\tvoid this.callbacks.onCycleChange(this.enabledIds === null ? null : [...this.enabledIds]);\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\n\t\tif (kb.matches(keyData, \"tui.select.confirm\")) {\n\t\t\tconst item = this.cycleItems[this.cycleIndex];\n\t\t\tif (item) {\n\t\t\t\tthis.enabledIds = toggle(this.enabledIds, item.fullId);\n\t\t\t\tthis.cycleDirty = true;\n\t\t\t\tthis.applySearch();\n\t\t\t\tvoid this.callbacks.onCycleChange(this.enabledIds === null ? null : [...this.enabledIds]);\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\n\t\tif (kb.matches(keyData, \"app.models.enableAll\")) {\n\t\t\tconst targetIds = this.searchInput.getValue() ? this.cycleItems.map((i) => i.fullId) : undefined;\n\t\t\tthis.enabledIds = enableAll(this.enabledIds, this.cycleAllIds, targetIds);\n\t\t\tthis.cycleDirty = true;\n\t\t\tthis.applySearch();\n\t\t\tvoid this.callbacks.onCycleChange(this.enabledIds === null ? null : [...this.enabledIds]);\n\t\t\treturn;\n\t\t}\n\n\t\tif (kb.matches(keyData, \"app.models.clearAll\")) {\n\t\t\tconst targetIds = this.searchInput.getValue() ? this.cycleItems.map((i) => i.fullId) : undefined;\n\t\t\tthis.enabledIds = clearAll(this.enabledIds, this.cycleAllIds, targetIds);\n\t\t\tthis.cycleDirty = true;\n\t\t\tthis.applySearch();\n\t\t\tvoid this.callbacks.onCycleChange(this.enabledIds === null ? null : [...this.enabledIds]);\n\t\t\treturn;\n\t\t}\n\n\t\tif (kb.matches(keyData, \"app.models.toggleProvider\")) {\n\t\t\tconst item = this.cycleItems[this.cycleIndex];\n\t\t\tif (item) {\n\t\t\t\tconst provider = item.model.provider;\n\t\t\t\tconst providerIds = this.cycleAllIds.filter((id) => this.cycleModelsById.get(id)!.provider === provider);\n\t\t\t\tconst allOn = providerIds.every((id) => isEnabled(this.enabledIds, id));\n\t\t\t\tthis.enabledIds = allOn\n\t\t\t\t\t? clearAll(this.enabledIds, this.cycleAllIds, providerIds)\n\t\t\t\t\t: enableAll(this.enabledIds, this.cycleAllIds, providerIds);\n\t\t\t\tthis.cycleDirty = true;\n\t\t\t\tthis.applySearch();\n\t\t\t\tvoid this.callbacks.onCycleChange(this.enabledIds === null ? null : [...this.enabledIds]);\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\n\t\tif (kb.matches(keyData, \"app.models.save\")) {\n\t\t\tvoid this.callbacks.onCyclePersist(this.enabledIds === null ? null : [...this.enabledIds]);\n\t\t\tthis.cycleDirty = false;\n\t\t\tthis.footerText.setText(this.getFooterText());\n\t\t\treturn;\n\t\t}\n\n\t\tthis.searchInput.handleInput(keyData);\n\t\tthis.applySearch();\n\t}\n\n\tprivate handleManageInput(keyData: string, kb: ReturnType<typeof getKeybindings>): void {\n\t\tif (kb.matches(keyData, \"tui.select.up\")) {\n\t\t\tif (this.manageRows.length === 0) return;\n\t\t\tthis.manageIndex = this.manageIndex === 0 ? this.manageRows.length - 1 : this.manageIndex - 1;\n\t\t\tthis.updateList();\n\t\t\treturn;\n\t\t}\n\t\tif (kb.matches(keyData, \"tui.select.down\")) {\n\t\t\tif (this.manageRows.length === 0) return;\n\t\t\tthis.manageIndex = this.manageIndex === this.manageRows.length - 1 ? 0 : this.manageIndex + 1;\n\t\t\tthis.updateList();\n\t\t\treturn;\n\t\t}\n\t\tif (kb.matches(keyData, \"tui.select.confirm\")) {\n\t\t\tthis.handleConfirm();\n\t\t\treturn;\n\t\t}\n\t\t// Backspace / Delete remove selected provider\n\t\tif (matchesKey(keyData, Key.backspace) || matchesKey(keyData, Key.delete)) {\n\t\t\tconst row = this.manageRows[this.manageIndex];\n\t\t\tif (row?.kind === \"provider\") {\n\t\t\t\tvoid this.callbacks.onManageRemove(row.source, row.id);\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\n\t\tthis.searchInput.handleInput(keyData);\n\t\tthis.applySearch();\n\t}\n\n\tprivate handleConfirm(): void {\n\t\tif (this.tab === \"select\") {\n\t\t\tconst row = this.selectRows[this.selectIndex];\n\t\t\tif (!row) return;\n\t\t\tif (row.kind === \"collapsed\") {\n\t\t\t\tthis.expandedProviders.add(row.provider);\n\t\t\t\tthis.applySearch();\n\t\t\t\t// Move selection to first model under that provider\n\t\t\t\tconst idx = this.selectRows.findIndex((r) => r.kind === \"model\" && r.item.provider === row.provider);\n\t\t\t\tif (idx >= 0) this.selectIndex = idx;\n\t\t\t\tthis.updateList();\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif (row.kind === \"model\") {\n\t\t\t\tthis.settingsManager.setDefaultModelAndProvider(row.item.model.provider, row.item.model.id);\n\t\t\t\tvoid this.callbacks.onSelectModel(row.item.model);\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\n\t\tif (this.tab === \"cycle\") {\n\t\t\tconst item = this.cycleItems[this.cycleIndex];\n\t\t\tif (item) {\n\t\t\t\tthis.enabledIds = toggle(this.enabledIds, item.fullId);\n\t\t\t\tthis.cycleDirty = true;\n\t\t\t\tthis.applySearch();\n\t\t\t\tvoid this.callbacks.onCycleChange(this.enabledIds === null ? null : [...this.enabledIds]);\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\n\t\tconst row = this.manageRows[this.manageIndex];\n\t\tif (!row) return;\n\t\tif (row.kind === \"action\" && row.action === \"add\") {\n\t\t\tvoid this.callbacks.onManageAdd();\n\t\t\treturn;\n\t\t}\n\t\tif (row.kind === \"provider\") {\n\t\t\tvoid this.callbacks.onManageEdit(row.source, row.id);\n\t\t}\n\t}\n\n\t/** Called by parent after manage mutation so list refreshes. */\n\tasync refreshAfterManage(): Promise<void> {\n\t\tawait this.reload();\n\t\tthis.tui.requestRender();\n\t}\n}\n\n/** Back-compat alias used by older tests/imports. */\nexport { ModelHubComponent as ModelSelectorComponent };\n"]}