@ashx-j/lunr 0.2.3 → 0.2.4
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.
- package/dist/builtin-extensions/ashxj-thinking.d.ts +1 -0
- package/dist/builtin-extensions/ashxj-thinking.d.ts.map +1 -1
- package/dist/builtin-extensions/ashxj-thinking.js +19 -7
- package/dist/builtin-extensions/ashxj-thinking.js.map +1 -1
- package/dist/gateway/commands.d.ts.map +1 -1
- package/dist/gateway/commands.js +1 -0
- package/dist/gateway/commands.js.map +1 -1
- package/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/settings-selector.js +5 -5
- package/dist/modes/interactive/components/settings-selector.js.map +1 -1
- package/dist/modes/interactive/components/thinking-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/thinking-selector.js +5 -5
- package/dist/modes/interactive/components/thinking-selector.js.map +1 -1
- package/docs/keybindings.md +1 -1
- package/docs/quickstart.md +1 -1
- package/examples/extensions/custom-provider-anthropic/package-lock.json +2 -2
- package/examples/extensions/custom-provider-anthropic/package.json +1 -1
- package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
- package/examples/extensions/gondolin/package-lock.json +2 -2
- package/examples/extensions/gondolin/package.json +1 -1
- package/examples/extensions/sandbox/package-lock.json +2 -2
- package/examples/extensions/sandbox/package.json +1 -1
- package/examples/extensions/with-deps/package-lock.json +2 -2
- package/examples/extensions/with-deps/package.json +1 -1
- package/package.json +4 -4
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"commands.js","sourceRoot":"","sources":["../../src/gateway/commands.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * lunR: gateway chat command registry.\n *\n * Every command is a small headless handler over AgentSession. Router.ts keeps\n * platform gating/authorization and delegates to runChatCommand for busy/session\n * guards, error wrapping, and /help generation.\n */\n\nimport type { ThinkingLevel } from \"@ashx-j/lunr-agent\";\nimport type { Model } from \"@ashx-j/lunr-ai/compat\";\nimport { computeContextBreakdown } from \"../core/context-breakdown.ts\";\nimport type { ToolDefinition } from \"../core/extensions/types.ts\";\nimport { findExactModelReferenceMatch } from \"../core/model-resolver.ts\";\nimport type { ModelRuntime } from \"../core/model-runtime.ts\";\nimport type { SessionInfo } from \"../core/session-manager.ts\";\nimport { SessionManager } from \"../core/session-manager.ts\";\nimport { buildSwarmPrompt } from \"../core/swarm.ts\";\nimport type { BridgeSession } from \"./agent-bridge.ts\";\nimport { createPicker, type PickerItem } from \"./buttons.ts\";\nimport type { BridgeLike } from \"./router.ts\";\nimport type { MessageEvent, PlatformAdapter } from \"./types.ts\";\n\nconst MODEL_CACHE_TTL_MS = 5 * 60 * 1000;\nconst SESSIONS_CACHE_TTL_MS = 5 * 60 * 1000;\nconst MAX_MODEL_LIST_LINES = 15;\nconst PROVIDER_PER_PAGE = 10;\nconst _MODEL_PER_PAGE = 8;\nconst MAX_MODELS_PER_PROVIDER = 50;\nconst MODEL_ID_MAX = 38;\nconst MODEL_CACHE_CAP = 100;\nconst SESSIONS_CACHE_CAP = 100;\n\ninterface ModelCacheEntry {\n\tmodels: Model<any>[];\n\texpires: number;\n}\n\ninterface SessionsCacheEntry {\n\tsessions: SessionInfo[];\n\texpires: number;\n}\n\nconst modelCache = new Map<string, ModelCacheEntry>();\nconst sessionsCache = new Map<string, SessionsCacheEntry>();\n\nfunction evictLRU<K, V>(map: Map<K, V>, cap: number): void {\n\twhile (map.size > cap) {\n\t\tconst first = map.keys().next().value;\n\t\tif (first !== undefined) map.delete(first);\n\t}\n}\n\nfunction getCachedModels(key: string): Model<any>[] | undefined {\n\tconst cached = modelCache.get(key);\n\tif (!cached) return undefined;\n\tif (Date.now() > cached.expires) {\n\t\tmodelCache.delete(key);\n\t\treturn undefined;\n\t}\n\t// LRU refresh.\n\tmodelCache.delete(key);\n\tmodelCache.set(key, cached);\n\treturn cached.models;\n}\n\nfunction setCachedModels(key: string, models: Model<any>[]): void {\n\tmodelCache.set(key, { models, expires: Date.now() + MODEL_CACHE_TTL_MS });\n\tevictLRU(modelCache, MODEL_CACHE_CAP);\n}\n\nfunction getCachedSessions(key: string): SessionInfo[] | undefined {\n\tconst cached = sessionsCache.get(key);\n\tif (!cached) return undefined;\n\tif (Date.now() > cached.expires) {\n\t\tsessionsCache.delete(key);\n\t\treturn undefined;\n\t}\n\tsessionsCache.delete(key);\n\tsessionsCache.set(key, cached);\n\treturn cached.sessions;\n}\n\nfunction setCachedSessions(key: string, sessions: SessionInfo[]): void {\n\tsessionsCache.set(key, { sessions, expires: Date.now() + SESSIONS_CACHE_TTL_MS });\n\tevictLRU(sessionsCache, SESSIONS_CACHE_CAP);\n}\n\nexport interface ChatCommandContext {\n\tevent: MessageEvent;\n\tkey: string;\n\tadapter: PlatformAdapter;\n\tbridge: BridgeLike;\n\tsession?: BridgeSession;\n\treply(text: string): Promise<void>;\n\targs: string;\n}\n\nexport interface ChatCommand {\n\tname: string;\n\taliases?: string[];\n\tdescription: string;\n\tbypassBusy: boolean;\n\tneedsSession: boolean;\n\t// biome-ignore lint/suspicious/noConfusingVoidType: handlers may return nothing; runChatCommand treats undefined as consumed.\n\thandler(ctx: ChatCommandContext): Promise<boolean | void>;\n}\n\nfunction oneLine(text: string): string {\n\treturn text.replace(/\\s+/g, \" \").trim().slice(0, 200);\n}\n\nfunction prefixLines(text: string, prefix: string): string {\n\treturn text\n\t\t.split(\"\\n\")\n\t\t.map((line, index) => (index === 0 ? prefix : \" \") + line)\n\t\t.join(\"\\n\");\n}\n\nfunction truncate(text: string, max: number): string {\n\tif (text.length <= max) return text;\n\treturn `${text.slice(0, max - 1)}…`;\n}\n\nfunction formatRelativeTime(date: Date): string {\n\tconst seconds = Math.max(0, Math.floor((Date.now() - date.getTime()) / 1000));\n\tif (seconds < 60) return `${seconds}s ago`;\n\tconst minutes = Math.floor(seconds / 60);\n\tif (minutes < 60) return `${minutes}m ago`;\n\tconst hours = Math.floor(minutes / 60);\n\tif (hours < 24) return `${hours}h ago`;\n\tconst days = Math.floor(hours / 24);\n\treturn `${days}d ago`;\n}\n\nfunction formatModelList(models: Model<any>[], maxLines = MAX_MODEL_LIST_LINES): string[] {\n\tif (models.length === 0) return [\"No models available.\"];\n\tconst byProvider = new Map<string, Model<any>[]>();\n\tfor (const model of models) {\n\t\tconst list = byProvider.get(model.provider) ?? [];\n\t\tlist.push(model);\n\t\tbyProvider.set(model.provider, list);\n\t}\n\tconst providers = [...byProvider.keys()].sort();\n\tconst lines: string[] = [];\n\tlet index = 1;\n\tfor (const provider of providers) {\n\t\tconst list = (byProvider.get(provider) ?? []).sort((a, b) => a.id.localeCompare(b.id));\n\t\tfor (const model of list) {\n\t\t\tlines.push(`${index}) ${provider}/${model.id}`);\n\t\t\tindex++;\n\t\t}\n\t}\n\tif (lines.length <= maxLines) return lines;\n\treturn [\n\t\t`${models.length} models across ${providers.length} providers.`,\n\t\t\"Use /model <provider/id> or /model <query>.\",\n\t\t...providers.map((p) => `- ${p}`),\n\t];\n}\n\nfunction groupModelsByProvider(models: Model<any>[]): Map<string, Model<any>[]> {\n\tconst byProvider = new Map<string, Model<any>[]>();\n\tfor (const model of models) {\n\t\tconst list = byProvider.get(model.provider) ?? [];\n\t\tlist.push(model);\n\t\tbyProvider.set(model.provider, list);\n\t}\n\tfor (const list of byProvider.values()) {\n\t\tlist.sort((a, b) => a.id.localeCompare(b.id));\n\t}\n\treturn byProvider;\n}\n\nfunction truncateModelId(id: string): string {\n\tconst lastSlash = id.lastIndexOf(\"/\");\n\tconst name = lastSlash >= 0 ? id.slice(lastSlash + 1) : id;\n\treturn truncate(name, MODEL_ID_MAX);\n}\n\nasync function refreshAndCacheModels(session: BridgeSession, key: string): Promise<Model<any>[]> {\n\tconst runtime: ModelRuntime = session.modelRuntime;\n\tawait runtime.refresh();\n\tconst models = [...(await runtime.getAvailable())].sort(\n\t\t(a, b) => a.provider.localeCompare(b.provider) || a.id.localeCompare(b.id),\n\t);\n\tsetCachedModels(key, models);\n\treturn models;\n}\n\nasync function setModelAndReply(ctx: ChatCommandContext, model: Model<any>): Promise<void> {\n\tconst session = ctx.session!;\n\ttry {\n\t\tawait session.setModel(model);\n\t} catch (error) {\n\t\tconst message = error instanceof Error ? error.message : String(error);\n\t\tif (message.includes(\"No API key\")) {\n\t\t\tawait ctx.reply(`No API key for ${model.provider}.`);\n\t\t\treturn;\n\t\t}\n\t\tthrow error;\n\t}\n\tawait ctx.reply(`Model → ${model.provider}/${model.id} (thinking level re-clamped to ${session.thinkingLevel})`);\n}\n\nconst newCommand: ChatCommand = {\n\tname: \"new\",\n\taliases: [\"reset\"],\n\tdescription: \"start a fresh session for this chat\",\n\tbypassBusy: false,\n\tneedsSession: false,\n\tasync handler(ctx) {\n\t\tawait ctx.bridge.reset(ctx.key);\n\t\tawait ctx.reply(\"Session reset — next message starts a fresh session.\");\n\t},\n};\n\nconst undoCommand: ChatCommand = {\n\tname: \"undo\",\n\tdescription: \"rewind the session tree before the last user turn\",\n\tbypassBusy: false,\n\tneedsSession: true,\n\tasync handler(ctx) {\n\t\tconst { userText } = await ctx.bridge.undo(ctx.key);\n\t\tconst text = userText ? ` \"${truncate(userText, 60)}\"` : \"\";\n\t\tawait ctx.reply(`Undone — rewound before${text}. /redo to restore.`);\n\t},\n};\n\nconst redoCommand: ChatCommand = {\n\tname: \"redo\",\n\tdescription: \"restore the last undone turn\",\n\tbypassBusy: false,\n\tneedsSession: true,\n\tasync handler(ctx) {\n\t\tawait ctx.bridge.redo(ctx.key);\n\t\tawait ctx.reply(\"Redone.\");\n\t},\n};\n\nconst stopCommand: ChatCommand = {\n\tname: \"stop\",\n\tdescription: \"abort the running turn\",\n\tbypassBusy: true,\n\tneedsSession: false,\n\tasync handler(ctx) {\n\t\tawait ctx.bridge.abort(ctx.key);\n\t\tawait ctx.reply(\"Stopped.\");\n\t},\n};\n\nconst statusCommand: ChatCommand = {\n\tname: \"status\",\n\tdescription: \"session status\",\n\tbypassBusy: true,\n\tneedsSession: false,\n\tasync handler(ctx) {\n\t\tconst status = ctx.bridge.getStatus(ctx.key);\n\t\tconst age = status.createdAt\n\t\t\t? `${Math.max(0, Math.round((Date.now() - Date.parse(status.createdAt)) / 1000))}s`\n\t\t\t: \"no session yet\";\n\t\tawait ctx.reply(\n\t\t\t`${ctx.event.source.platform} · session age ${age} · ${status.busy ? \"busy\" : \"idle\"} · queue ${status.queueDepth}`,\n\t\t);\n\t},\n};\n\nconst whoamiCommand: ChatCommand = {\n\tname: \"whoami\",\n\tdescription: \"your ids and session key\",\n\tbypassBusy: true,\n\tneedsSession: false,\n\tasync handler(ctx) {\n\t\tconst { userId, chatId } = ctx.event.source;\n\t\tawait ctx.reply(`userId: ${userId}\\nchatId: ${chatId}\\nkey: ${ctx.key}`);\n\t},\n};\n\nconst helpCommand: ChatCommand = {\n\tname: \"help\",\n\tdescription: \"this message\",\n\tbypassBusy: true,\n\tneedsSession: false,\n\tasync handler(ctx) {\n\t\tawait ctx.reply(formatHelpText());\n\t},\n};\n\nconst modelCommand: ChatCommand = {\n\tname: \"model\",\n\tdescription: \"list or switch models\",\n\tbypassBusy: false,\n\tneedsSession: true,\n\tasync handler(ctx) {\n\t\tconst session = ctx.session!;\n\t\tconst arg = ctx.args.trim();\n\t\tif (!arg) {\n\t\t\tconst cached = getCachedModels(ctx.key);\n\t\t\tconst models = cached ?? (await refreshAndCacheModels(session, ctx.key));\n\t\t\tconst byProvider = groupModelsByProvider(models);\n\t\t\tconst current = session.model;\n\t\t\tconst currentRef = current ? `${current.provider}/${current.id}` : \"\";\n\t\t\tconst providers = [...byProvider.keys()].sort();\n\t\t\tconst providerItems: PickerItem[] = providers.map((provider) => ({\n\t\t\t\tlabel: `${current?.provider === provider ? \"✓ \" : \"\"}${provider} (${byProvider.get(provider)?.length ?? 0})`,\n\t\t\t\tvalue: provider,\n\t\t\t}));\n\n\t\t\tconst pickerOpts = {\n\t\t\t\treplyTo: ctx.event.messageId,\n\t\t\t\tthreadId: ctx.event.source.threadId,\n\t\t\t};\n\t\t\tconst result = await createPicker(\n\t\t\t\tctx.adapter,\n\t\t\t\tctx.event.source,\n\t\t\t\t{\n\t\t\t\t\tkind: \"model\",\n\t\t\t\t\tsessionKey: ctx.key,\n\t\t\t\t\tinvokerId: ctx.event.source.userId,\n\t\t\t\t\titems: providerItems,\n\t\t\t\t\tperPage: PROVIDER_PER_PAGE,\n\t\t\t\t\ttitle: \"Pick a model provider\",\n\t\t\t\t\tasync resolve(item) {\n\t\t\t\t\t\tif (item.value === \"__back__\") {\n\t\t\t\t\t\t\treturn { done: false, items: providerItems, title: \"Pick a model provider\" };\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif (!item.value.includes(\"/\")) {\n\t\t\t\t\t\t\tconst provider = item.value;\n\t\t\t\t\t\t\tconst list = byProvider.get(provider) ?? [];\n\t\t\t\t\t\t\tconst capped = list.slice(0, MAX_MODELS_PER_PROVIDER);\n\t\t\t\t\t\t\tconst note =\n\t\t\t\t\t\t\t\tlist.length > MAX_MODELS_PER_PROVIDER\n\t\t\t\t\t\t\t\t\t? ` — ${list.length - MAX_MODELS_PER_PROVIDER} more available`\n\t\t\t\t\t\t\t\t\t: \"\";\n\t\t\t\t\t\t\tconst modelItems: PickerItem[] = [];\n\t\t\t\t\t\t\tfor (const m of capped) {\n\t\t\t\t\t\t\t\tconst ref = `${provider}/${m.id}`;\n\t\t\t\t\t\t\t\tmodelItems.push({\n\t\t\t\t\t\t\t\t\tlabel: `${currentRef === ref ? \"✓ \" : \"\"}${truncateModelId(m.id)}`,\n\t\t\t\t\t\t\t\t\tvalue: ref,\n\t\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tmodelItems.unshift({ label: \"◀ Back\", value: \"__back__\" });\n\t\t\t\t\t\t\treturn {\n\t\t\t\t\t\t\t\tdone: false,\n\t\t\t\t\t\t\t\titems: modelItems,\n\t\t\t\t\t\t\t\ttitle: `${provider} (${list.length})${note}`,\n\t\t\t\t\t\t\t\tbreadcrumbs: provider,\n\t\t\t\t\t\t\t};\n\t\t\t\t\t\t}\n\t\t\t\t\t\tconst exact = findExactModelReferenceMatch(item.value, models);\n\t\t\t\t\t\tif (!exact) {\n\t\t\t\t\t\t\treturn { done: true, text: \"That model is no longer available.\" };\n\t\t\t\t\t\t}\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\tawait session.setModel(exact);\n\t\t\t\t\t\t} catch (error) {\n\t\t\t\t\t\t\tconst message = error instanceof Error ? error.message : String(error);\n\t\t\t\t\t\t\tif (message.includes(\"No API key\")) {\n\t\t\t\t\t\t\t\treturn { done: true, text: `No API key for ${exact.provider}.` };\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tthrow error;\n\t\t\t\t\t\t}\n\t\t\t\t\t\treturn {\n\t\t\t\t\t\t\tdone: true,\n\t\t\t\t\t\t\ttext: `☾ Model → ${exact.provider}/${exact.id} (thinking level re-clamped to ${session.thinkingLevel})`,\n\t\t\t\t\t\t};\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tpickerOpts,\n\t\t\t);\n\t\t\tif (!result.success) {\n\t\t\t\tconst currentText = `${current?.provider ?? \"none\"}/${current?.id ?? \"none\"}`;\n\t\t\t\tconst lines = formatModelList(models);\n\t\t\t\tawait ctx.reply([`Current: ${currentText}`, ...lines, \"Use /model <n> or /model <provider/id>\"].join(\"\\n\"));\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\n\t\tconst numeric = Number.parseInt(arg, 10);\n\t\tif (!Number.isNaN(numeric) && /^\\d+$/.test(arg)) {\n\t\t\tconst cached = getCachedModels(ctx.key);\n\t\t\tif (!cached || numeric < 1 || numeric > cached.length) {\n\t\t\t\tawait ctx.reply(\"Invalid selection — run /model to see the current list.\");\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tawait setModelAndReply(ctx, cached[numeric - 1]);\n\t\t\treturn;\n\t\t}\n\n\t\tconst models = getCachedModels(ctx.key) ?? (await refreshAndCacheModels(session, ctx.key));\n\t\tconst exact = findExactModelReferenceMatch(arg, models);\n\t\tif (exact) {\n\t\t\tawait setModelAndReply(ctx, exact);\n\t\t\treturn;\n\t\t}\n\n\t\tconst query = arg.toLowerCase();\n\t\tconst matches = models.filter(\n\t\t\t(m) =>\n\t\t\t\tm.id.toLowerCase().includes(query) ||\n\t\t\t\t`${m.provider}/${m.id}`.toLowerCase().includes(query) ||\n\t\t\t\t(m.name?.toLowerCase().includes(query) ?? false),\n\t\t);\n\t\tif (matches.length === 0) {\n\t\t\tawait ctx.reply(`No model matches \"${arg}\".`);\n\t\t\treturn;\n\t\t}\n\t\tif (matches.length > 1) {\n\t\t\tawait ctx.reply(formatModelList(matches).join(\"\\n\"));\n\t\t\treturn;\n\t\t}\n\t\tawait setModelAndReply(ctx, matches[0]);\n\t},\n};\n\nconst sessionsCommand: ChatCommand = {\n\tname: \"sessions\",\n\tdescription: \"list or switch sessions\",\n\tbypassBusy: false,\n\tneedsSession: true,\n\tasync handler(ctx) {\n\t\tconst session = ctx.session!;\n\t\tconst arg = ctx.args.trim();\n\t\tconst currentFile = session.sessionManager?.getSessionFile();\n\n\t\tif (!arg) {\n\t\t\tconst all = await SessionManager.list(process.cwd());\n\t\t\tall.sort((a, b) => b.modified.getTime() - a.modified.getTime());\n\t\t\tconst sessions = all.slice(0, 10);\n\t\t\tsetCachedSessions(ctx.key, sessions);\n\t\t\tconst items: PickerItem[] = sessions.map((s) => ({\n\t\t\t\tlabel: `${s.path === currentFile ? \"☾ \" : \"\"}${s.name ? truncate(s.name, 30) : truncate(s.firstMessage, 30) || \"(empty)\"}`,\n\t\t\t\tvalue: s.path,\n\t\t\t}));\n\t\t\tconst result = await createPicker(\n\t\t\t\tctx.adapter,\n\t\t\t\tctx.event.source,\n\t\t\t\t{\n\t\t\t\t\tkind: \"sessions\",\n\t\t\t\t\tsessionKey: ctx.key,\n\t\t\t\t\tinvokerId: ctx.event.source.userId,\n\t\t\t\t\titems,\n\t\t\t\t\tperPage: 8,\n\t\t\t\t\ttitle: \"Pick a session\",\n\t\t\t\t\tasync resolve(item) {\n\t\t\t\t\t\tawait ctx.bridge.switchSession(ctx.key, item.value);\n\t\t\t\t\t\tconst switched = await ctx.bridge.getSession(ctx.key);\n\t\t\t\t\t\tconst name = switched?.sessionManager?.getSessionName() ?? \"unnamed\";\n\t\t\t\t\t\tconst count = switched?.sessionManager?.getEntries().length ?? 0;\n\t\t\t\t\t\treturn { done: true, text: `☾ Switched to \"${name}\" (${count} msgs). History continues here.` };\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\t{ replyTo: ctx.event.messageId, threadId: ctx.event.source.threadId },\n\t\t\t);\n\t\t\tif (!result.success) {\n\t\t\t\tconst lines = sessions.map((s, i) => {\n\t\t\t\t\tconst marker = s.path === currentFile ? \" ☾\" : \"\";\n\t\t\t\t\tconst label = s.name ? truncate(s.name, 40) : truncate(s.firstMessage, 40) || \"(empty)\";\n\t\t\t\t\treturn `${i + 1}) ${label}${marker} · ${formatRelativeTime(s.modified)} · ${s.messageCount} msgs`;\n\t\t\t\t});\n\t\t\t\tawait ctx.reply(\n\t\t\t\t\t[`Sessions for ${process.cwd()}`, ...lines, \"Use /sessions <n> or /sessions <id-prefix>\"].join(\"\\n\"),\n\t\t\t\t);\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\n\t\tlet path: string | undefined;\n\t\tconst numeric = Number.parseInt(arg, 10);\n\t\tconst cached = getCachedSessions(ctx.key);\n\t\tif (!Number.isNaN(numeric) && /^\\d+$/.test(arg)) {\n\t\t\tif (!cached || numeric < 1 || numeric > cached.length) {\n\t\t\t\tawait ctx.reply(\"Invalid selection — run /sessions to see the current list.\");\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tpath = cached[numeric - 1].path;\n\t\t} else {\n\t\t\tconst pool = cached ?? (await SessionManager.list(process.cwd()));\n\t\t\tconst matches = pool.filter((s) => s.id.startsWith(arg) || s.path.startsWith(arg));\n\t\t\tif (matches.length === 0) {\n\t\t\t\tawait ctx.reply(`No session matches \"${arg}\".`);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif (matches.length > 1) {\n\t\t\t\tawait ctx.reply(`Multiple sessions match \"${arg}\" — use a longer prefix.`);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tpath = matches[0].path;\n\t\t}\n\n\t\tif (!path) {\n\t\t\tawait ctx.reply(\"No session selected.\");\n\t\t\treturn;\n\t\t}\n\n\t\tawait ctx.bridge.switchSession(ctx.key, path);\n\t\tconst switched = await ctx.bridge.getSession(ctx.key);\n\t\tconst name = switched?.sessionManager?.getSessionName() ?? \"unnamed\";\n\t\tconst count = switched?.sessionManager?.getEntries().length ?? 0;\n\t\tawait ctx.reply(`Switched to \"${name}\" (${count} msgs). History continues here.`);\n\t},\n};\n\nconst titleCommand: ChatCommand = {\n\tname: \"title\",\n\taliases: [\"name\"],\n\tdescription: \"name the current session\",\n\tbypassBusy: true,\n\tneedsSession: true,\n\tasync handler(ctx) {\n\t\tconst session = ctx.session!;\n\t\tconst name = ctx.args.trim();\n\t\tif (!name) {\n\t\t\tconst current = session.sessionManager?.getSessionName();\n\t\t\tawait ctx.reply(current ? `Session title: ${current}` : \"(unnamed)\");\n\t\t\treturn;\n\t\t}\n\t\tsession.setSessionName(name);\n\t\tconst readBack = session.sessionManager?.getSessionName() ?? name;\n\t\tawait ctx.reply(`Session titled \"${readBack}\".`);\n\t},\n};\n\nconst contextCommand: ChatCommand = {\n\tname: \"context\",\n\tdescription: \"estimated context window breakdown\",\n\tbypassBusy: true,\n\tneedsSession: true,\n\tasync handler(ctx) {\n\t\tconst session = ctx.session!;\n\t\tconst model = session.model;\n\t\tif (!model) {\n\t\t\tawait ctx.reply(\"No model selected.\");\n\t\t\treturn;\n\t\t}\n\t\tconst contextWindow = model.contextWindow ?? 0;\n\t\tif (contextWindow <= 0) {\n\t\t\tawait ctx.reply(\"Context window unknown for this model.\");\n\t\t\treturn;\n\t\t}\n\n\t\tconst tools: ToolDefinition[] = session\n\t\t\t.getActiveToolNames()\n\t\t\t.map((name) => session.getToolDefinition(name))\n\t\t\t.filter((d): d is ToolDefinition => d !== undefined);\n\n\t\tconst breakdown = computeContextBreakdown({\n\t\t\tsystemPrompt: session.systemPrompt,\n\t\t\ttools,\n\t\t\tmessages: session.messages,\n\t\t\tcontextWindow,\n\t\t});\n\n\t\tconst usage = session.getContextUsage();\n\t\tconst tokens = usage?.tokens ?? breakdown.total;\n\t\tconst percent = usage?.percent ?? (contextWindow > 0 ? (tokens / contextWindow) * 100 : 0);\n\n\t\tconst messageTokens =\n\t\t\tbreakdown.user +\n\t\t\tbreakdown.assistantText +\n\t\t\tbreakdown.thinking +\n\t\t\tbreakdown.toolCalls +\n\t\t\tbreakdown.toolResults +\n\t\t\tbreakdown.summaries;\n\n\t\tconst stats = session.getSessionStats();\n\t\tawait ctx.reply(\n\t\t\t[\n\t\t\t\t`Context: ${tokens.toLocaleString(\"en-US\")} / ${contextWindow.toLocaleString(\"en-US\")} tokens (${Math.round(percent)}%)`,\n\t\t\t\t` system ${breakdown.systemPrompt.toLocaleString(\"en-US\")} · tools ${breakdown.toolDefinitions.toLocaleString(\"en-US\")} · messages ${messageTokens.toLocaleString(\"en-US\")}`,\n\t\t\t\t`Session: ${stats.totalMessages} messages · ${stats.userMessages} turns · model ${model.provider}/${model.id}`,\n\t\t\t].join(\"\\n\"),\n\t\t);\n\t},\n};\n\nconst swarmCommand: ChatCommand = {\n\tname: \"swarm\",\n\tdescription: \"decompose a task across parallel subagents\",\n\tbypassBusy: false,\n\tneedsSession: true,\n\tasync handler(ctx) {\n\t\tconst task = ctx.args.trim();\n\t\tif (!task) {\n\t\t\tawait ctx.reply(\"Usage: /swarm <task> — decomposes the task across parallel subagents.\");\n\t\t\treturn true;\n\t\t}\n\t\tctx.event.text = buildSwarmPrompt(task);\n\t\treturn false;\n\t},\n};\n\nconst compactCommand: ChatCommand = {\n\tname: \"compact\",\n\tdescription: \"summarize and compress session context\",\n\tbypassBusy: true,\n\tneedsSession: true,\n\tasync handler(ctx) {\n\t\tconst session = ctx.session!;\n\t\tconst instructions = ctx.args.trim() || undefined;\n\t\ttry {\n\t\t\tconst result = await session.compact(instructions);\n\t\t\tconst before = result.tokensBefore.toLocaleString(\"en-US\");\n\t\t\tconst after =\n\t\t\t\tresult.estimatedTokensAfter !== undefined\n\t\t\t\t\t? `~${result.estimatedTokensAfter.toLocaleString(\"en-US\")}`\n\t\t\t\t\t: \"~?\";\n\t\t\tawait ctx.reply(`Compacted: ${before} → ${after} tokens.`);\n\t\t} catch (error) {\n\t\t\tconst message = error instanceof Error ? error.message : String(error);\n\t\t\tif (\n\t\t\t\tmessage.includes(\"Nothing to compact\") ||\n\t\t\t\tmessage.includes(\"Already compacted\") ||\n\t\t\t\tmessage.includes(\"No model selected\")\n\t\t\t) {\n\t\t\t\tawait ctx.reply(message);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tthrow error;\n\t\t}\n\t},\n};\n\nconst thinkingCommand: ChatCommand = {\n\tname: \"thinking\",\n\tdescription: \"get or set the thinking level\",\n\tbypassBusy: false,\n\tneedsSession: true,\n\tasync handler(ctx) {\n\t\tconst session = ctx.session!;\n\t\tconst levels = session.getAvailableThinkingLevels();\n\t\tif (!session.supportsThinking()) {\n\t\t\tawait ctx.reply(\n\t\t\t\t`Model ${session.model?.provider ?? \"none\"}/${session.model?.id ?? \"none\"} doesn't support thinking.`,\n\t\t\t);\n\t\t\treturn;\n\t\t}\n\t\tconst arg = ctx.args.trim().toLowerCase() as ThinkingLevel;\n\t\tif (!arg) {\n\t\t\tconst current = session.thinkingLevel;\n\t\t\tconst items: PickerItem[] = levels.map((level) => ({\n\t\t\t\tlabel: `${level === current ? \"✓ \" : \"\"}${level}`,\n\t\t\t\tvalue: level,\n\t\t\t}));\n\t\t\tconst result = await createPicker(\n\t\t\t\tctx.adapter,\n\t\t\t\tctx.event.source,\n\t\t\t\t{\n\t\t\t\t\tkind: \"thinking\",\n\t\t\t\t\tsessionKey: ctx.key,\n\t\t\t\t\tinvokerId: ctx.event.source.userId,\n\t\t\t\t\titems,\n\t\t\t\t\tperPage: levels.length,\n\t\t\t\t\ttitle: \"Pick a thinking level\",\n\t\t\t\t\tasync resolve(item) {\n\t\t\t\t\t\tconst level = item.value as ThinkingLevel;\n\t\t\t\t\t\tsession.setThinkingLevel(level);\n\t\t\t\t\t\treturn { done: true, text: `☾ Thinking → ${level}` };\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\t{ replyTo: ctx.event.messageId, threadId: ctx.event.source.threadId },\n\t\t\t);\n\t\t\tif (!result.success) {\n\t\t\t\tawait ctx.reply(`Level: ${current} — available: ${levels.join(\", \")}`);\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\t\tif (!levels.includes(arg)) {\n\t\t\tawait ctx.reply(`Invalid level. Available: ${levels.join(\", \")}`);\n\t\t\treturn;\n\t\t}\n\t\tsession.setThinkingLevel(arg);\n\t\tawait ctx.reply(`Thinking → ${arg}`);\n\t},\n};\n\nexport const CHAT_COMMANDS: ChatCommand[] = [\n\tnewCommand,\n\tundoCommand,\n\tredoCommand,\n\tstopCommand,\n\tstatusCommand,\n\twhoamiCommand,\n\thelpCommand,\n\tmodelCommand,\n\tsessionsCommand,\n\ttitleCommand,\n\tcontextCommand,\n\tswarmCommand,\n\tcompactCommand,\n\tthinkingCommand,\n];\n\n/** Platform menu specs (e.g. Telegram setMyCommands): canonical names only, aliases skipped. */\nexport function botCommandSpecs(): { name: string; description: string }[] {\n\treturn CHAT_COMMANDS.map((c) => ({ name: c.name, description: c.description }));\n}\n\nexport function formatHelpText(): string {\n\tconst lines = [\"lunR gateway commands:\"];\n\tfor (const cmd of CHAT_COMMANDS) {\n\t\tconst names = [cmd.name, ...(cmd.aliases ?? [])].map((a) => `/${a}`).join(\" | \");\n\t\tlines.push(`${names} — ${cmd.description}`);\n\t}\n\tlines.push(\"\");\n\tlines.push(\"Tap to pick: /model, /thinking, /sessions (run without args to see buttons).\");\n\treturn lines.join(\"\\n\");\n}\n\n/**\n * Run a chat command with busy/session guards and error → \"⚠ one-line\".\n * Returns true when the event was consumed by the command, false when the\n * router should continue (e.g. /swarm mutates the event and wants a normal turn).\n */\nexport async function runChatCommand(cmd: ChatCommand, ctx: ChatCommandContext): Promise<boolean> {\n\tif (!cmd.bypassBusy && ctx.bridge.getStatus(ctx.key).busy) {\n\t\tawait ctx.reply(\"⏳ busy — /stop first or wait\");\n\t\treturn true;\n\t}\n\tif (cmd.needsSession) {\n\t\tconst session = await ctx.bridge.getSession(ctx.key);\n\t\tif (!session) {\n\t\t\tawait ctx.reply(\"No session yet — send a message first.\");\n\t\t\treturn true;\n\t\t}\n\t\tctx.session = session;\n\t}\n\ttry {\n\t\tconst consumed = await cmd.handler(ctx);\n\t\treturn consumed ?? true;\n\t} catch (err) {\n\t\tconst message = err instanceof Error ? err.message : String(err);\n\t\tawait ctx.adapter.send(ctx.event.source.chatId, `⚠ ${oneLine(message)}`, {\n\t\t\treplyTo: ctx.event.messageId,\n\t\t\tthreadId: ctx.event.source.threadId,\n\t\t});\n\t\treturn true;\n\t}\n}\n\n/** Reply helper used by the router to build the ChatCommandContext. */\nexport async function sendCommandReply(adapter: PlatformAdapter, event: MessageEvent, text: string): Promise<void> {\n\tawait adapter.send(event.source.chatId, prefixLines(text, \"☾ \"), {\n\t\treplyTo: event.messageId,\n\t\tthreadId: event.source.threadId,\n\t});\n}\n"]}
|
|
1
|
+
{"version":3,"file":"commands.js","sourceRoot":"","sources":["../../src/gateway/commands.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * lunR: gateway chat command registry.\n *\n * Every command is a small headless handler over AgentSession. Router.ts keeps\n * platform gating/authorization and delegates to runChatCommand for busy/session\n * guards, error wrapping, and /help generation.\n */\n\nimport type { ThinkingLevel } from \"@ashx-j/lunr-agent\";\nimport type { Model } from \"@ashx-j/lunr-ai/compat\";\nimport { computeContextBreakdown } from \"../core/context-breakdown.ts\";\nimport type { ToolDefinition } from \"../core/extensions/types.ts\";\nimport { findExactModelReferenceMatch } from \"../core/model-resolver.ts\";\nimport type { ModelRuntime } from \"../core/model-runtime.ts\";\nimport type { SessionInfo } from \"../core/session-manager.ts\";\nimport { SessionManager } from \"../core/session-manager.ts\";\nimport { buildSwarmPrompt } from \"../core/swarm.ts\";\nimport type { BridgeSession } from \"./agent-bridge.ts\";\nimport { createPicker, type PickerItem } from \"./buttons.ts\";\nimport type { BridgeLike } from \"./router.ts\";\nimport type { MessageEvent, PlatformAdapter } from \"./types.ts\";\n\nconst MODEL_CACHE_TTL_MS = 5 * 60 * 1000;\nconst SESSIONS_CACHE_TTL_MS = 5 * 60 * 1000;\nconst MAX_MODEL_LIST_LINES = 15;\nconst PROVIDER_PER_PAGE = 10;\nconst _MODEL_PER_PAGE = 8;\nconst MAX_MODELS_PER_PROVIDER = 50;\nconst MODEL_ID_MAX = 38;\nconst MODEL_CACHE_CAP = 100;\nconst SESSIONS_CACHE_CAP = 100;\n\ninterface ModelCacheEntry {\n\tmodels: Model<any>[];\n\texpires: number;\n}\n\ninterface SessionsCacheEntry {\n\tsessions: SessionInfo[];\n\texpires: number;\n}\n\nconst modelCache = new Map<string, ModelCacheEntry>();\nconst sessionsCache = new Map<string, SessionsCacheEntry>();\n\nfunction evictLRU<K, V>(map: Map<K, V>, cap: number): void {\n\twhile (map.size > cap) {\n\t\tconst first = map.keys().next().value;\n\t\tif (first !== undefined) map.delete(first);\n\t}\n}\n\nfunction getCachedModels(key: string): Model<any>[] | undefined {\n\tconst cached = modelCache.get(key);\n\tif (!cached) return undefined;\n\tif (Date.now() > cached.expires) {\n\t\tmodelCache.delete(key);\n\t\treturn undefined;\n\t}\n\t// LRU refresh.\n\tmodelCache.delete(key);\n\tmodelCache.set(key, cached);\n\treturn cached.models;\n}\n\nfunction setCachedModels(key: string, models: Model<any>[]): void {\n\tmodelCache.set(key, { models, expires: Date.now() + MODEL_CACHE_TTL_MS });\n\tevictLRU(modelCache, MODEL_CACHE_CAP);\n}\n\nfunction getCachedSessions(key: string): SessionInfo[] | undefined {\n\tconst cached = sessionsCache.get(key);\n\tif (!cached) return undefined;\n\tif (Date.now() > cached.expires) {\n\t\tsessionsCache.delete(key);\n\t\treturn undefined;\n\t}\n\tsessionsCache.delete(key);\n\tsessionsCache.set(key, cached);\n\treturn cached.sessions;\n}\n\nfunction setCachedSessions(key: string, sessions: SessionInfo[]): void {\n\tsessionsCache.set(key, { sessions, expires: Date.now() + SESSIONS_CACHE_TTL_MS });\n\tevictLRU(sessionsCache, SESSIONS_CACHE_CAP);\n}\n\nexport interface ChatCommandContext {\n\tevent: MessageEvent;\n\tkey: string;\n\tadapter: PlatformAdapter;\n\tbridge: BridgeLike;\n\tsession?: BridgeSession;\n\treply(text: string): Promise<void>;\n\targs: string;\n}\n\nexport interface ChatCommand {\n\tname: string;\n\taliases?: string[];\n\tdescription: string;\n\tbypassBusy: boolean;\n\tneedsSession: boolean;\n\t// biome-ignore lint/suspicious/noConfusingVoidType: handlers may return nothing; runChatCommand treats undefined as consumed.\n\thandler(ctx: ChatCommandContext): Promise<boolean | void>;\n}\n\nfunction oneLine(text: string): string {\n\treturn text.replace(/\\s+/g, \" \").trim().slice(0, 200);\n}\n\nfunction prefixLines(text: string, prefix: string): string {\n\treturn text\n\t\t.split(\"\\n\")\n\t\t.map((line, index) => (index === 0 ? prefix : \" \") + line)\n\t\t.join(\"\\n\");\n}\n\nfunction truncate(text: string, max: number): string {\n\tif (text.length <= max) return text;\n\treturn `${text.slice(0, max - 1)}…`;\n}\n\nfunction formatRelativeTime(date: Date): string {\n\tconst seconds = Math.max(0, Math.floor((Date.now() - date.getTime()) / 1000));\n\tif (seconds < 60) return `${seconds}s ago`;\n\tconst minutes = Math.floor(seconds / 60);\n\tif (minutes < 60) return `${minutes}m ago`;\n\tconst hours = Math.floor(minutes / 60);\n\tif (hours < 24) return `${hours}h ago`;\n\tconst days = Math.floor(hours / 24);\n\treturn `${days}d ago`;\n}\n\nfunction formatModelList(models: Model<any>[], maxLines = MAX_MODEL_LIST_LINES): string[] {\n\tif (models.length === 0) return [\"No models available.\"];\n\tconst byProvider = new Map<string, Model<any>[]>();\n\tfor (const model of models) {\n\t\tconst list = byProvider.get(model.provider) ?? [];\n\t\tlist.push(model);\n\t\tbyProvider.set(model.provider, list);\n\t}\n\tconst providers = [...byProvider.keys()].sort();\n\tconst lines: string[] = [];\n\tlet index = 1;\n\tfor (const provider of providers) {\n\t\tconst list = (byProvider.get(provider) ?? []).sort((a, b) => a.id.localeCompare(b.id));\n\t\tfor (const model of list) {\n\t\t\tlines.push(`${index}) ${provider}/${model.id}`);\n\t\t\tindex++;\n\t\t}\n\t}\n\tif (lines.length <= maxLines) return lines;\n\treturn [\n\t\t`${models.length} models across ${providers.length} providers.`,\n\t\t\"Use /model <provider/id> or /model <query>.\",\n\t\t...providers.map((p) => `- ${p}`),\n\t];\n}\n\nfunction groupModelsByProvider(models: Model<any>[]): Map<string, Model<any>[]> {\n\tconst byProvider = new Map<string, Model<any>[]>();\n\tfor (const model of models) {\n\t\tconst list = byProvider.get(model.provider) ?? [];\n\t\tlist.push(model);\n\t\tbyProvider.set(model.provider, list);\n\t}\n\tfor (const list of byProvider.values()) {\n\t\tlist.sort((a, b) => a.id.localeCompare(b.id));\n\t}\n\treturn byProvider;\n}\n\nfunction truncateModelId(id: string): string {\n\tconst lastSlash = id.lastIndexOf(\"/\");\n\tconst name = lastSlash >= 0 ? id.slice(lastSlash + 1) : id;\n\treturn truncate(name, MODEL_ID_MAX);\n}\n\nasync function refreshAndCacheModels(session: BridgeSession, key: string): Promise<Model<any>[]> {\n\tconst runtime: ModelRuntime = session.modelRuntime;\n\tawait runtime.refresh();\n\tconst models = [...(await runtime.getAvailable())].sort(\n\t\t(a, b) => a.provider.localeCompare(b.provider) || a.id.localeCompare(b.id),\n\t);\n\tsetCachedModels(key, models);\n\treturn models;\n}\n\nasync function setModelAndReply(ctx: ChatCommandContext, model: Model<any>): Promise<void> {\n\tconst session = ctx.session!;\n\ttry {\n\t\tawait session.setModel(model);\n\t} catch (error) {\n\t\tconst message = error instanceof Error ? error.message : String(error);\n\t\tif (message.includes(\"No API key\")) {\n\t\t\tawait ctx.reply(`No API key for ${model.provider}.`);\n\t\t\treturn;\n\t\t}\n\t\tthrow error;\n\t}\n\tawait ctx.reply(`Model → ${model.provider}/${model.id} (thinking level re-clamped to ${session.thinkingLevel})`);\n}\n\nconst newCommand: ChatCommand = {\n\tname: \"new\",\n\taliases: [\"reset\"],\n\tdescription: \"start a fresh session for this chat\",\n\tbypassBusy: false,\n\tneedsSession: false,\n\tasync handler(ctx) {\n\t\tawait ctx.bridge.reset(ctx.key);\n\t\tawait ctx.reply(\"Session reset — next message starts a fresh session.\");\n\t},\n};\n\nconst undoCommand: ChatCommand = {\n\tname: \"undo\",\n\tdescription: \"rewind the session tree before the last user turn\",\n\tbypassBusy: false,\n\tneedsSession: true,\n\tasync handler(ctx) {\n\t\tconst { userText } = await ctx.bridge.undo(ctx.key);\n\t\tconst text = userText ? ` \"${truncate(userText, 60)}\"` : \"\";\n\t\tawait ctx.reply(`Undone — rewound before${text}. /redo to restore.`);\n\t},\n};\n\nconst redoCommand: ChatCommand = {\n\tname: \"redo\",\n\tdescription: \"restore the last undone turn\",\n\tbypassBusy: false,\n\tneedsSession: true,\n\tasync handler(ctx) {\n\t\tawait ctx.bridge.redo(ctx.key);\n\t\tawait ctx.reply(\"Redone.\");\n\t},\n};\n\nconst stopCommand: ChatCommand = {\n\tname: \"stop\",\n\tdescription: \"abort the running turn\",\n\tbypassBusy: true,\n\tneedsSession: false,\n\tasync handler(ctx) {\n\t\tawait ctx.bridge.abort(ctx.key);\n\t\tawait ctx.reply(\"Stopped.\");\n\t},\n};\n\nconst statusCommand: ChatCommand = {\n\tname: \"status\",\n\tdescription: \"session status\",\n\tbypassBusy: true,\n\tneedsSession: false,\n\tasync handler(ctx) {\n\t\tconst status = ctx.bridge.getStatus(ctx.key);\n\t\tconst age = status.createdAt\n\t\t\t? `${Math.max(0, Math.round((Date.now() - Date.parse(status.createdAt)) / 1000))}s`\n\t\t\t: \"no session yet\";\n\t\tawait ctx.reply(\n\t\t\t`${ctx.event.source.platform} · session age ${age} · ${status.busy ? \"busy\" : \"idle\"} · queue ${status.queueDepth}`,\n\t\t);\n\t},\n};\n\nconst whoamiCommand: ChatCommand = {\n\tname: \"whoami\",\n\tdescription: \"your ids and session key\",\n\tbypassBusy: true,\n\tneedsSession: false,\n\tasync handler(ctx) {\n\t\tconst { userId, chatId } = ctx.event.source;\n\t\tawait ctx.reply(`userId: ${userId}\\nchatId: ${chatId}\\nkey: ${ctx.key}`);\n\t},\n};\n\nconst helpCommand: ChatCommand = {\n\tname: \"help\",\n\tdescription: \"this message\",\n\tbypassBusy: true,\n\tneedsSession: false,\n\tasync handler(ctx) {\n\t\tawait ctx.reply(formatHelpText());\n\t},\n};\n\nconst modelCommand: ChatCommand = {\n\tname: \"model\",\n\tdescription: \"list or switch models\",\n\tbypassBusy: false,\n\tneedsSession: true,\n\tasync handler(ctx) {\n\t\tconst session = ctx.session!;\n\t\tconst arg = ctx.args.trim();\n\t\tif (!arg) {\n\t\t\tconst cached = getCachedModels(ctx.key);\n\t\t\tconst models = cached ?? (await refreshAndCacheModels(session, ctx.key));\n\t\t\tconst byProvider = groupModelsByProvider(models);\n\t\t\tconst current = session.model;\n\t\t\tconst currentRef = current ? `${current.provider}/${current.id}` : \"\";\n\t\t\tconst providers = [...byProvider.keys()].sort();\n\t\t\tconst providerItems: PickerItem[] = providers.map((provider) => ({\n\t\t\t\tlabel: `${current?.provider === provider ? \"✓ \" : \"\"}${provider} (${byProvider.get(provider)?.length ?? 0})`,\n\t\t\t\tvalue: provider,\n\t\t\t}));\n\n\t\t\tconst pickerOpts = {\n\t\t\t\treplyTo: ctx.event.messageId,\n\t\t\t\tthreadId: ctx.event.source.threadId,\n\t\t\t};\n\t\t\tconst result = await createPicker(\n\t\t\t\tctx.adapter,\n\t\t\t\tctx.event.source,\n\t\t\t\t{\n\t\t\t\t\tkind: \"model\",\n\t\t\t\t\tsessionKey: ctx.key,\n\t\t\t\t\tinvokerId: ctx.event.source.userId,\n\t\t\t\t\titems: providerItems,\n\t\t\t\t\tperPage: PROVIDER_PER_PAGE,\n\t\t\t\t\ttitle: \"Pick a model provider\",\n\t\t\t\t\tasync resolve(item) {\n\t\t\t\t\t\tif (item.value === \"__back__\") {\n\t\t\t\t\t\t\treturn { done: false, items: providerItems, title: \"Pick a model provider\" };\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif (!item.value.includes(\"/\")) {\n\t\t\t\t\t\t\tconst provider = item.value;\n\t\t\t\t\t\t\tconst list = byProvider.get(provider) ?? [];\n\t\t\t\t\t\t\tconst capped = list.slice(0, MAX_MODELS_PER_PROVIDER);\n\t\t\t\t\t\t\tconst note =\n\t\t\t\t\t\t\t\tlist.length > MAX_MODELS_PER_PROVIDER\n\t\t\t\t\t\t\t\t\t? ` — ${list.length - MAX_MODELS_PER_PROVIDER} more available`\n\t\t\t\t\t\t\t\t\t: \"\";\n\t\t\t\t\t\t\tconst modelItems: PickerItem[] = [];\n\t\t\t\t\t\t\tfor (const m of capped) {\n\t\t\t\t\t\t\t\tconst ref = `${provider}/${m.id}`;\n\t\t\t\t\t\t\t\tmodelItems.push({\n\t\t\t\t\t\t\t\t\tlabel: `${currentRef === ref ? \"✓ \" : \"\"}${truncateModelId(m.id)}`,\n\t\t\t\t\t\t\t\t\tvalue: ref,\n\t\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tmodelItems.unshift({ label: \"◀ Back\", value: \"__back__\" });\n\t\t\t\t\t\t\treturn {\n\t\t\t\t\t\t\t\tdone: false,\n\t\t\t\t\t\t\t\titems: modelItems,\n\t\t\t\t\t\t\t\ttitle: `${provider} (${list.length})${note}`,\n\t\t\t\t\t\t\t\tbreadcrumbs: provider,\n\t\t\t\t\t\t\t};\n\t\t\t\t\t\t}\n\t\t\t\t\t\tconst exact = findExactModelReferenceMatch(item.value, models);\n\t\t\t\t\t\tif (!exact) {\n\t\t\t\t\t\t\treturn { done: true, text: \"That model is no longer available.\" };\n\t\t\t\t\t\t}\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\tawait session.setModel(exact);\n\t\t\t\t\t\t} catch (error) {\n\t\t\t\t\t\t\tconst message = error instanceof Error ? error.message : String(error);\n\t\t\t\t\t\t\tif (message.includes(\"No API key\")) {\n\t\t\t\t\t\t\t\treturn { done: true, text: `No API key for ${exact.provider}.` };\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tthrow error;\n\t\t\t\t\t\t}\n\t\t\t\t\t\treturn {\n\t\t\t\t\t\t\tdone: true,\n\t\t\t\t\t\t\ttext: `☾ Model → ${exact.provider}/${exact.id} (thinking level re-clamped to ${session.thinkingLevel})`,\n\t\t\t\t\t\t};\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tpickerOpts,\n\t\t\t);\n\t\t\tif (!result.success) {\n\t\t\t\tconst currentText = `${current?.provider ?? \"none\"}/${current?.id ?? \"none\"}`;\n\t\t\t\tconst lines = formatModelList(models);\n\t\t\t\tawait ctx.reply([`Current: ${currentText}`, ...lines, \"Use /model <n> or /model <provider/id>\"].join(\"\\n\"));\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\n\t\tconst numeric = Number.parseInt(arg, 10);\n\t\tif (!Number.isNaN(numeric) && /^\\d+$/.test(arg)) {\n\t\t\tconst cached = getCachedModels(ctx.key);\n\t\t\tif (!cached || numeric < 1 || numeric > cached.length) {\n\t\t\t\tawait ctx.reply(\"Invalid selection — run /model to see the current list.\");\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tawait setModelAndReply(ctx, cached[numeric - 1]);\n\t\t\treturn;\n\t\t}\n\n\t\tconst models = getCachedModels(ctx.key) ?? (await refreshAndCacheModels(session, ctx.key));\n\t\tconst exact = findExactModelReferenceMatch(arg, models);\n\t\tif (exact) {\n\t\t\tawait setModelAndReply(ctx, exact);\n\t\t\treturn;\n\t\t}\n\n\t\tconst query = arg.toLowerCase();\n\t\tconst matches = models.filter(\n\t\t\t(m) =>\n\t\t\t\tm.id.toLowerCase().includes(query) ||\n\t\t\t\t`${m.provider}/${m.id}`.toLowerCase().includes(query) ||\n\t\t\t\t(m.name?.toLowerCase().includes(query) ?? false),\n\t\t);\n\t\tif (matches.length === 0) {\n\t\t\tawait ctx.reply(`No model matches \"${arg}\".`);\n\t\t\treturn;\n\t\t}\n\t\tif (matches.length > 1) {\n\t\t\tawait ctx.reply(formatModelList(matches).join(\"\\n\"));\n\t\t\treturn;\n\t\t}\n\t\tawait setModelAndReply(ctx, matches[0]);\n\t},\n};\n\nconst sessionsCommand: ChatCommand = {\n\tname: \"sessions\",\n\tdescription: \"list or switch sessions\",\n\tbypassBusy: false,\n\tneedsSession: true,\n\tasync handler(ctx) {\n\t\tconst session = ctx.session!;\n\t\tconst arg = ctx.args.trim();\n\t\tconst currentFile = session.sessionManager?.getSessionFile();\n\n\t\tif (!arg) {\n\t\t\tconst all = await SessionManager.list(process.cwd());\n\t\t\tall.sort((a, b) => b.modified.getTime() - a.modified.getTime());\n\t\t\tconst sessions = all.slice(0, 10);\n\t\t\tsetCachedSessions(ctx.key, sessions);\n\t\t\tconst items: PickerItem[] = sessions.map((s) => ({\n\t\t\t\tlabel: `${s.path === currentFile ? \"☾ \" : \"\"}${s.name ? truncate(s.name, 30) : truncate(s.firstMessage, 30) || \"(empty)\"}`,\n\t\t\t\tvalue: s.path,\n\t\t\t}));\n\t\t\tconst result = await createPicker(\n\t\t\t\tctx.adapter,\n\t\t\t\tctx.event.source,\n\t\t\t\t{\n\t\t\t\t\tkind: \"sessions\",\n\t\t\t\t\tsessionKey: ctx.key,\n\t\t\t\t\tinvokerId: ctx.event.source.userId,\n\t\t\t\t\titems,\n\t\t\t\t\tperPage: 8,\n\t\t\t\t\ttitle: \"Pick a session\",\n\t\t\t\t\tasync resolve(item) {\n\t\t\t\t\t\tawait ctx.bridge.switchSession(ctx.key, item.value);\n\t\t\t\t\t\tconst switched = await ctx.bridge.getSession(ctx.key);\n\t\t\t\t\t\tconst name = switched?.sessionManager?.getSessionName() ?? \"unnamed\";\n\t\t\t\t\t\tconst count = switched?.sessionManager?.getEntries().length ?? 0;\n\t\t\t\t\t\treturn { done: true, text: `☾ Switched to \"${name}\" (${count} msgs). History continues here.` };\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\t{ replyTo: ctx.event.messageId, threadId: ctx.event.source.threadId },\n\t\t\t);\n\t\t\tif (!result.success) {\n\t\t\t\tconst lines = sessions.map((s, i) => {\n\t\t\t\t\tconst marker = s.path === currentFile ? \" ☾\" : \"\";\n\t\t\t\t\tconst label = s.name ? truncate(s.name, 40) : truncate(s.firstMessage, 40) || \"(empty)\";\n\t\t\t\t\treturn `${i + 1}) ${label}${marker} · ${formatRelativeTime(s.modified)} · ${s.messageCount} msgs`;\n\t\t\t\t});\n\t\t\t\tawait ctx.reply(\n\t\t\t\t\t[`Sessions for ${process.cwd()}`, ...lines, \"Use /sessions <n> or /sessions <id-prefix>\"].join(\"\\n\"),\n\t\t\t\t);\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\n\t\tlet path: string | undefined;\n\t\tconst numeric = Number.parseInt(arg, 10);\n\t\tconst cached = getCachedSessions(ctx.key);\n\t\tif (!Number.isNaN(numeric) && /^\\d+$/.test(arg)) {\n\t\t\tif (!cached || numeric < 1 || numeric > cached.length) {\n\t\t\t\tawait ctx.reply(\"Invalid selection — run /sessions to see the current list.\");\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tpath = cached[numeric - 1].path;\n\t\t} else {\n\t\t\tconst pool = cached ?? (await SessionManager.list(process.cwd()));\n\t\t\tconst matches = pool.filter((s) => s.id.startsWith(arg) || s.path.startsWith(arg));\n\t\t\tif (matches.length === 0) {\n\t\t\t\tawait ctx.reply(`No session matches \"${arg}\".`);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif (matches.length > 1) {\n\t\t\t\tawait ctx.reply(`Multiple sessions match \"${arg}\" — use a longer prefix.`);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tpath = matches[0].path;\n\t\t}\n\n\t\tif (!path) {\n\t\t\tawait ctx.reply(\"No session selected.\");\n\t\t\treturn;\n\t\t}\n\n\t\tawait ctx.bridge.switchSession(ctx.key, path);\n\t\tconst switched = await ctx.bridge.getSession(ctx.key);\n\t\tconst name = switched?.sessionManager?.getSessionName() ?? \"unnamed\";\n\t\tconst count = switched?.sessionManager?.getEntries().length ?? 0;\n\t\tawait ctx.reply(`Switched to \"${name}\" (${count} msgs). History continues here.`);\n\t},\n};\n\nconst titleCommand: ChatCommand = {\n\tname: \"title\",\n\taliases: [\"name\"],\n\tdescription: \"name the current session\",\n\tbypassBusy: true,\n\tneedsSession: true,\n\tasync handler(ctx) {\n\t\tconst session = ctx.session!;\n\t\tconst name = ctx.args.trim();\n\t\tif (!name) {\n\t\t\tconst current = session.sessionManager?.getSessionName();\n\t\t\tawait ctx.reply(current ? `Session title: ${current}` : \"(unnamed)\");\n\t\t\treturn;\n\t\t}\n\t\tsession.setSessionName(name);\n\t\tconst readBack = session.sessionManager?.getSessionName() ?? name;\n\t\tawait ctx.reply(`Session titled \"${readBack}\".`);\n\t},\n};\n\nconst contextCommand: ChatCommand = {\n\tname: \"context\",\n\tdescription: \"estimated context window breakdown\",\n\tbypassBusy: true,\n\tneedsSession: true,\n\tasync handler(ctx) {\n\t\tconst session = ctx.session!;\n\t\tconst model = session.model;\n\t\tif (!model) {\n\t\t\tawait ctx.reply(\"No model selected.\");\n\t\t\treturn;\n\t\t}\n\t\tconst contextWindow = model.contextWindow ?? 0;\n\t\tif (contextWindow <= 0) {\n\t\t\tawait ctx.reply(\"Context window unknown for this model.\");\n\t\t\treturn;\n\t\t}\n\n\t\tconst tools: ToolDefinition[] = session\n\t\t\t.getActiveToolNames()\n\t\t\t.map((name) => session.getToolDefinition(name))\n\t\t\t.filter((d): d is ToolDefinition => d !== undefined);\n\n\t\tconst breakdown = computeContextBreakdown({\n\t\t\tsystemPrompt: session.systemPrompt,\n\t\t\ttools,\n\t\t\tmessages: session.messages,\n\t\t\tcontextWindow,\n\t\t});\n\n\t\tconst usage = session.getContextUsage();\n\t\tconst tokens = usage?.tokens ?? breakdown.total;\n\t\tconst percent = usage?.percent ?? (contextWindow > 0 ? (tokens / contextWindow) * 100 : 0);\n\n\t\tconst messageTokens =\n\t\t\tbreakdown.user +\n\t\t\tbreakdown.assistantText +\n\t\t\tbreakdown.thinking +\n\t\t\tbreakdown.toolCalls +\n\t\t\tbreakdown.toolResults +\n\t\t\tbreakdown.summaries;\n\n\t\tconst stats = session.getSessionStats();\n\t\tawait ctx.reply(\n\t\t\t[\n\t\t\t\t`Context: ${tokens.toLocaleString(\"en-US\")} / ${contextWindow.toLocaleString(\"en-US\")} tokens (${Math.round(percent)}%)`,\n\t\t\t\t` system ${breakdown.systemPrompt.toLocaleString(\"en-US\")} · tools ${breakdown.toolDefinitions.toLocaleString(\"en-US\")} · messages ${messageTokens.toLocaleString(\"en-US\")}`,\n\t\t\t\t`Session: ${stats.totalMessages} messages · ${stats.userMessages} turns · model ${model.provider}/${model.id}`,\n\t\t\t].join(\"\\n\"),\n\t\t);\n\t},\n};\n\nconst swarmCommand: ChatCommand = {\n\tname: \"swarm\",\n\tdescription: \"decompose a task across parallel subagents\",\n\tbypassBusy: false,\n\tneedsSession: true,\n\tasync handler(ctx) {\n\t\tconst task = ctx.args.trim();\n\t\tif (!task) {\n\t\t\tawait ctx.reply(\"Usage: /swarm <task> — decomposes the task across parallel subagents.\");\n\t\t\treturn true;\n\t\t}\n\t\tctx.event.text = buildSwarmPrompt(task);\n\t\treturn false;\n\t},\n};\n\nconst compactCommand: ChatCommand = {\n\tname: \"compact\",\n\tdescription: \"summarize and compress session context\",\n\tbypassBusy: true,\n\tneedsSession: true,\n\tasync handler(ctx) {\n\t\tconst session = ctx.session!;\n\t\tconst instructions = ctx.args.trim() || undefined;\n\t\ttry {\n\t\t\tconst result = await session.compact(instructions);\n\t\t\tconst before = result.tokensBefore.toLocaleString(\"en-US\");\n\t\t\tconst after =\n\t\t\t\tresult.estimatedTokensAfter !== undefined\n\t\t\t\t\t? `~${result.estimatedTokensAfter.toLocaleString(\"en-US\")}`\n\t\t\t\t\t: \"~?\";\n\t\t\tawait ctx.reply(`Compacted: ${before} → ${after} tokens.`);\n\t\t} catch (error) {\n\t\t\tconst message = error instanceof Error ? error.message : String(error);\n\t\t\tif (\n\t\t\t\tmessage.includes(\"Nothing to compact\") ||\n\t\t\t\tmessage.includes(\"Already compacted\") ||\n\t\t\t\tmessage.includes(\"No model selected\")\n\t\t\t) {\n\t\t\t\tawait ctx.reply(message);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tthrow error;\n\t\t}\n\t},\n};\n\nconst thinkingCommand: ChatCommand = {\n\tname: \"thinking\",\n\taliases: [\"effort\", \"reasoning\"],\n\tdescription: \"get or set the thinking level\",\n\tbypassBusy: false,\n\tneedsSession: true,\n\tasync handler(ctx) {\n\t\tconst session = ctx.session!;\n\t\tconst levels = session.getAvailableThinkingLevels();\n\t\tif (!session.supportsThinking()) {\n\t\t\tawait ctx.reply(\n\t\t\t\t`Model ${session.model?.provider ?? \"none\"}/${session.model?.id ?? \"none\"} doesn't support thinking.`,\n\t\t\t);\n\t\t\treturn;\n\t\t}\n\t\tconst arg = ctx.args.trim().toLowerCase() as ThinkingLevel;\n\t\tif (!arg) {\n\t\t\tconst current = session.thinkingLevel;\n\t\t\tconst items: PickerItem[] = levels.map((level) => ({\n\t\t\t\tlabel: `${level === current ? \"✓ \" : \"\"}${level}`,\n\t\t\t\tvalue: level,\n\t\t\t}));\n\t\t\tconst result = await createPicker(\n\t\t\t\tctx.adapter,\n\t\t\t\tctx.event.source,\n\t\t\t\t{\n\t\t\t\t\tkind: \"thinking\",\n\t\t\t\t\tsessionKey: ctx.key,\n\t\t\t\t\tinvokerId: ctx.event.source.userId,\n\t\t\t\t\titems,\n\t\t\t\t\tperPage: levels.length,\n\t\t\t\t\ttitle: \"Pick a thinking level\",\n\t\t\t\t\tasync resolve(item) {\n\t\t\t\t\t\tconst level = item.value as ThinkingLevel;\n\t\t\t\t\t\tsession.setThinkingLevel(level);\n\t\t\t\t\t\treturn { done: true, text: `☾ Thinking → ${level}` };\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\t{ replyTo: ctx.event.messageId, threadId: ctx.event.source.threadId },\n\t\t\t);\n\t\t\tif (!result.success) {\n\t\t\t\tawait ctx.reply(`Level: ${current} — available: ${levels.join(\", \")}`);\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\t\tif (!levels.includes(arg)) {\n\t\t\tawait ctx.reply(`Invalid level. Available: ${levels.join(\", \")}`);\n\t\t\treturn;\n\t\t}\n\t\tsession.setThinkingLevel(arg);\n\t\tawait ctx.reply(`Thinking → ${arg}`);\n\t},\n};\n\nexport const CHAT_COMMANDS: ChatCommand[] = [\n\tnewCommand,\n\tundoCommand,\n\tredoCommand,\n\tstopCommand,\n\tstatusCommand,\n\twhoamiCommand,\n\thelpCommand,\n\tmodelCommand,\n\tsessionsCommand,\n\ttitleCommand,\n\tcontextCommand,\n\tswarmCommand,\n\tcompactCommand,\n\tthinkingCommand,\n];\n\n/** Platform menu specs (e.g. Telegram setMyCommands): canonical names only, aliases skipped. */\nexport function botCommandSpecs(): { name: string; description: string }[] {\n\treturn CHAT_COMMANDS.map((c) => ({ name: c.name, description: c.description }));\n}\n\nexport function formatHelpText(): string {\n\tconst lines = [\"lunR gateway commands:\"];\n\tfor (const cmd of CHAT_COMMANDS) {\n\t\tconst names = [cmd.name, ...(cmd.aliases ?? [])].map((a) => `/${a}`).join(\" | \");\n\t\tlines.push(`${names} — ${cmd.description}`);\n\t}\n\tlines.push(\"\");\n\tlines.push(\"Tap to pick: /model, /thinking, /sessions (run without args to see buttons).\");\n\treturn lines.join(\"\\n\");\n}\n\n/**\n * Run a chat command with busy/session guards and error → \"⚠ one-line\".\n * Returns true when the event was consumed by the command, false when the\n * router should continue (e.g. /swarm mutates the event and wants a normal turn).\n */\nexport async function runChatCommand(cmd: ChatCommand, ctx: ChatCommandContext): Promise<boolean> {\n\tif (!cmd.bypassBusy && ctx.bridge.getStatus(ctx.key).busy) {\n\t\tawait ctx.reply(\"⏳ busy — /stop first or wait\");\n\t\treturn true;\n\t}\n\tif (cmd.needsSession) {\n\t\tconst session = await ctx.bridge.getSession(ctx.key);\n\t\tif (!session) {\n\t\t\tawait ctx.reply(\"No session yet — send a message first.\");\n\t\t\treturn true;\n\t\t}\n\t\tctx.session = session;\n\t}\n\ttry {\n\t\tconst consumed = await cmd.handler(ctx);\n\t\treturn consumed ?? true;\n\t} catch (err) {\n\t\tconst message = err instanceof Error ? err.message : String(err);\n\t\tawait ctx.adapter.send(ctx.event.source.chatId, `⚠ ${oneLine(message)}`, {\n\t\t\treplyTo: ctx.event.messageId,\n\t\t\tthreadId: ctx.event.source.threadId,\n\t\t});\n\t\treturn true;\n\t}\n}\n\n/** Reply helper used by the router to build the ChatCommandContext. */\nexport async function sendCommandReply(adapter: PlatformAdapter, event: MessageEvent, text: string): Promise<void> {\n\tawait adapter.send(event.source.chatId, prefixLines(text, \"☾ \"), {\n\t\treplyTo: event.messageId,\n\t\tthreadId: event.source.threadId,\n\t});\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"settings-selector.d.ts","sourceRoot":"","sources":["../../../../src/modes/interactive/components/settings-selector.ts"],"names":[],"mappings":"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","sourcesContent":["import type { ThinkingLevel } from \"@ashx-j/lunr-agent\";\nimport type { Transport } from \"@ashx-j/lunr-ai\";\nimport {\n\ttype Component,\n\tContainer,\n\tgetCapabilities,\n\tgetKeybindings,\n\tInput,\n\ttype SelectItem,\n\tSelectList,\n\ttype SelectListLayoutOptions,\n\ttype SettingItem,\n\tSettingsList,\n\tSpacer,\n\tText,\n} from \"@ashx-j/lunr-tui\";\nimport { getCustomizeBridge } from \"../../../core/customize.ts\";\nimport { formatHttpIdleTimeoutMs, HTTP_IDLE_TIMEOUT_CHOICES } from \"../../../core/http-dispatcher.ts\";\nimport { MEMORY_CHAR_CAP_DEFAULT, MEMORY_CHAR_CAP_MAX, MEMORY_CHAR_CAP_MIN } from \"../../../core/memory-cap.ts\";\nimport type { SearchCuratorSetting } from \"../../../core/search-curator.ts\";\nimport type {\n\tDefaultPermissionMode,\n\tDefaultProjectTrust,\n\tModelTierName,\n\tModelTiersSettings,\n\tRollbackCapture,\n\tRollbackScope,\n} from \"../../../core/settings-manager.ts\";\nimport {\n\tgetSelectListTheme,\n\tgetSettingsListTheme,\n\tparseAutoThemeSetting,\n\ttype TerminalTheme,\n\ttheme,\n} from \"../theme/theme.ts\";\nimport { DynamicBorder } from \"./dynamic-border.ts\";\nimport { keyDisplayText } from \"./keybinding-hints.ts\";\n\nconst SETTINGS_SUBMENU_SELECT_LIST_LAYOUT: SelectListLayoutOptions = {\n\tminPrimaryColumnWidth: 12,\n\tmaxPrimaryColumnWidth: 32,\n};\n\nconst THINKING_DESCRIPTIONS: Record<ThinkingLevel, string> = {\n\toff: \"No reasoning\",\n\tminimal: \"Very brief reasoning (~1k tokens)\",\n\tlow: \"Light reasoning (~2k tokens)\",\n\tmedium: \"Moderate reasoning (~8k tokens)\",\n\thigh: \"Deep reasoning (~16k tokens)\",\n\txhigh: \"Extra-high reasoning (~32k tokens)\",\n\tmax: \"Maximum reasoning\",\n};\n\nconst DEFAULT_PROJECT_TRUST_LABELS: Record<DefaultProjectTrust, string> = {\n\task: \"Ask\",\n\talways: \"Always trust\",\n\tnever: \"Never trust\",\n};\n\nconst DEFAULT_PROJECT_TRUST_BY_LABEL = new Map(\n\tObject.entries(DEFAULT_PROJECT_TRUST_LABELS).map(([value, label]) => [label, value as DefaultProjectTrust]),\n);\n\nexport interface SettingsConfig {\n\tautoCompact: boolean;\n\tshowImages: boolean;\n\timageWidthCells: number;\n\tautoResizeImages: boolean;\n\tblockImages: boolean;\n\tenableSkillCommands: boolean;\n\tsteeringMode: \"all\" | \"one-at-a-time\";\n\tfollowUpMode: \"all\" | \"one-at-a-time\";\n\ttransport: Transport;\n\thttpIdleTimeoutMs: number;\n\tthinkingLevel: ThinkingLevel;\n\tavailableThinkingLevels: ThinkingLevel[];\n\tcurrentTheme: string;\n\tterminalTheme: TerminalTheme;\n\tavailableThemes: string[];\n\thideThinkingBlock: boolean;\n\tthinkingCollapse: boolean;\n\tshowCacheMissNotices: boolean;\n\t/** Display value; unset settings render as \"short\". */\n\tcacheRetention: \"none\" | \"short\" | \"long\";\n\tdoubleEscapeAction: \"fork\" | \"tree\" | \"none\";\n\ttreeFilterMode: \"default\" | \"no-tools\" | \"user-only\" | \"labeled-only\" | \"all\";\n\tshowHardwareCursor: boolean;\n\teditorPaddingX: number;\n\toutputPad: 0 | 1;\n\tautocompleteMaxVisible: number;\n\tquietStartup: boolean;\n\tsmoothStreaming: boolean;\n\tsessionRetentionDays: number;\n\tdefaultProjectTrust: DefaultProjectTrust;\n\tclearOnShrink: boolean;\n\tshowTerminalProgress: boolean;\n\tmodelTiers: ModelTiersSettings;\n\tmemoryCharCap: number;\n\t/** undefined when pi-web-access is not loaded (curator bridge absent). */\n\tsearchCurator: SearchCuratorSetting | undefined;\n\t// lunr: TUI customize settings\n\tgutterRail: boolean;\n\tpromptSymbol: boolean;\n\tfooterMcp: boolean;\n\tfooterLsp: boolean;\n\tfooterContext: boolean;\n\tfooterTokens: boolean;\n\tfooterStatuses: boolean;\n\t// lunr: permission mode default\n\tdefaultPermissionMode: DefaultPermissionMode;\n\t// lunr: rollback settings\n\trollbackEnabled: boolean;\n\trollbackTurns: number;\n\trollbackCapture: RollbackCapture;\n\trollbackScope: RollbackScope;\n\t// lunr: multi-subscription pools\n\tautoManageSubscriptions: boolean;\n\tsubscriptionCount: number;\n}\n\nexport interface SettingsCallbacks {\n\tonAutoCompactChange: (enabled: boolean) => void;\n\tonShowImagesChange: (enabled: boolean) => void;\n\tonImageWidthCellsChange: (width: number) => void;\n\tonAutoResizeImagesChange: (enabled: boolean) => void;\n\tonBlockImagesChange: (blocked: boolean) => void;\n\tonEnableSkillCommandsChange: (enabled: boolean) => void;\n\tonSteeringModeChange: (mode: \"all\" | \"one-at-a-time\") => void;\n\tonFollowUpModeChange: (mode: \"all\" | \"one-at-a-time\") => void;\n\tonTransportChange: (transport: Transport) => void;\n\tonHttpIdleTimeoutMsChange: (timeoutMs: number) => void;\n\tonThinkingLevelChange: (level: ThinkingLevel) => void;\n\tonThemeChange: (theme: string) => void;\n\tonThemePreview?: (theme: string) => void;\n\tonHideThinkingBlockChange: (hidden: boolean) => void;\n\tonThinkingCollapseChange: (collapse: boolean) => void;\n\tonShowCacheMissNoticesChange: (shown: boolean) => void;\n\tonCacheRetentionChange: (retention: \"none\" | \"short\" | \"long\") => void;\n\tonDoubleEscapeActionChange: (action: \"fork\" | \"tree\" | \"none\") => void;\n\tonTreeFilterModeChange: (mode: \"default\" | \"no-tools\" | \"user-only\" | \"labeled-only\" | \"all\") => void;\n\tonShowHardwareCursorChange: (enabled: boolean) => void;\n\tonEditorPaddingXChange: (padding: number) => void;\n\tonOutputPadChange: (padding: 0 | 1) => void;\n\tonAutocompleteMaxVisibleChange: (maxVisible: number) => void;\n\tonQuietStartupChange: (enabled: boolean) => void;\n\tonSmoothStreamingChange: (enabled: boolean) => void;\n\tonSessionRetentionDaysChange: (days: number) => void;\n\tonDefaultProjectTrustChange: (defaultProjectTrust: DefaultProjectTrust) => void;\n\tonClearOnShrinkChange: (enabled: boolean) => void;\n\tonShowTerminalProgressChange: (enabled: boolean) => void;\n\tonModelTiersEnabledChange: (enabled: boolean) => void;\n\tonModelTierModelChange: (tier: ModelTierName, model: string) => void;\n\tonMemoryCharCapChange: (cap: number) => void;\n\tonSearchCuratorChange: (setting: SearchCuratorSetting) => void;\n\t// lunr: TUI customize callbacks\n\tonGutterRailChange: (enabled: boolean) => void;\n\tonPromptSymbolChange: (enabled: boolean) => void;\n\tonFooterMcpChange: (enabled: boolean) => void;\n\tonFooterLspChange: (enabled: boolean) => void;\n\tonFooterContextChange: (enabled: boolean) => void;\n\tonFooterTokensChange: (enabled: boolean) => void;\n\tonFooterStatusesChange: (enabled: boolean) => void;\n\t// lunr: permission mode default\n\tonDefaultPermissionModeChange: (mode: DefaultPermissionMode) => void;\n\t// lunr: rollback callbacks\n\tonRollbackEnabledChange: (enabled: boolean) => void;\n\tonRollbackTurnsChange: (turns: number) => void;\n\tonRollbackCaptureChange: (mode: RollbackCapture) => void;\n\tonRollbackScopeChange: (scope: RollbackScope) => void;\n\tisRollbackSessionForceEnabled: () => boolean;\n\t// lunr: multi-subscription pool callbacks\n\tonAutoManageSubscriptionsChange: (enabled: boolean) => void;\n\t/** lunr: live pool accessors; when absent the Subscriptions row is hidden. */\n\tsubscriptions?: SubscriptionCallbacks;\n\t/** Open the model picker for a tier; done() receives the selected \"provider/model\" string, or no value on cancel. */\n\tcreateModelTierPicker: (\n\t\ttier: ModelTierName,\n\t\tcurrentModel: string | undefined,\n\t\tdone: (selectedValue?: string) => void,\n\t) => Component;\n\tonCancel: () => void;\n}\n\nconst MODEL_TIER_ROWS: { tier: ModelTierName; label: string; description: string }[] = [\n\t{\n\t\ttier: \"light\",\n\t\tlabel: \"Light tier model\",\n\t\tdescription: \"Cheap/fast model for simple subagent tasks (lookups, formatting)\",\n\t},\n\t{\n\t\ttier: \"standard\",\n\t\tlabel: \"Standard tier model\",\n\t\tdescription: \"Mid-tier model for typical coding subagent tasks\",\n\t},\n\t{\n\t\ttier: \"heavy\",\n\t\tlabel: \"Heavy tier model\",\n\t\tdescription: \"Strongest model for deep reasoning and complex debugging subagents\",\n\t},\n];\n\n/**\n * Submenu for the 3-tier subagent model routing (light/standard/heavy).\n * Row 1 toggles tier mode; rows 2-4 open a model picker per tier.\n */\nclass ModelTiersSubmenu extends Container {\n\tprivate settingsList: SettingsList;\n\tprivate state: { enabled: boolean; light?: string; standard?: string; heavy?: string };\n\n\tconstructor(\n\t\tcurrentValue: string | undefined,\n\t\tmodelTiers: ModelTiersSettings,\n\t\tcallbacks: SettingsCallbacks,\n\t\tdone: (selectedValue?: string) => void,\n\t) {\n\t\tsuper();\n\n\t\tthis.state = {\n\t\t\tenabled: currentValue === \"on\" || (currentValue === undefined && (modelTiers.enabled ?? false)),\n\t\t\tlight: modelTiers.light,\n\t\t\tstandard: modelTiers.standard,\n\t\t\theavy: modelTiers.heavy,\n\t\t};\n\n\t\tconst items: SettingItem[] = [\n\t\t\t{\n\t\t\t\tid: \"enabled\",\n\t\t\t\tlabel: \"Enable model tiers\",\n\t\t\t\tdescription:\n\t\t\t\t\t\"Route subagents to per-tier models. An explicit model choice overrides the tier; tiers without a model inherit the parent model.\",\n\t\t\t\tcurrentValue: this.state.enabled ? \"on\" : \"off\",\n\t\t\t\tvalues: [\"on\", \"off\"],\n\t\t\t},\n\t\t\t...MODEL_TIER_ROWS.map((row): SettingItem => {\n\t\t\t\tconst tier = row.tier;\n\t\t\t\treturn {\n\t\t\t\t\tid: tier,\n\t\t\t\t\tlabel: row.label,\n\t\t\t\t\tdescription: row.description,\n\t\t\t\t\tcurrentValue: this.state[tier] ?? \"not set\",\n\t\t\t\t\tdisabled: () => !this.state.enabled,\n\t\t\t\t\tsubmenu: (_currentValue, done) => callbacks.createModelTierPicker(tier, this.state[tier], done),\n\t\t\t\t};\n\t\t\t}),\n\t\t];\n\n\t\tthis.settingsList = new SettingsList(\n\t\t\titems,\n\t\t\tMath.min(items.length, 10),\n\t\t\tgetSettingsListTheme(),\n\t\t\t(id, newValue) => {\n\t\t\t\tif (id === \"enabled\") {\n\t\t\t\t\tthis.state.enabled = newValue === \"on\";\n\t\t\t\t\tcallbacks.onModelTiersEnabledChange(this.state.enabled);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tconst tier = id as ModelTierName;\n\t\t\t\tthis.state[tier] = newValue;\n\t\t\t\tcallbacks.onModelTierModelChange(tier, newValue);\n\t\t\t},\n\t\t\t() => done(this.state.enabled ? \"on\" : \"off\"),\n\t\t);\n\n\t\tthis.addChild(this.settingsList);\n\t}\n\n\thandleInput(data: string): void {\n\t\tthis.settingsList.handleInput(data);\n\t}\n}\n\n/**\n * Numeric input submenu for the simple-pi-memory character cap.\n * Enter validates and applies via done(newValue); Esc cancels.\n */\nclass MemoryCharCapSubmenu extends Container {\n\tprivate input: Input;\n\tprivate errorText: Text;\n\n\tconstructor(currentValue: string, done: (selectedValue?: string) => void) {\n\t\tsuper();\n\n\t\tthis.addChild(new Text(theme.bold(theme.fg(\"accent\", \"Memory Character Cap\")), 0, 0));\n\t\tthis.addChild(new Spacer(1));\n\t\tthis.addChild(\n\t\t\tnew Text(\n\t\t\t\ttheme.fg(\n\t\t\t\t\t\"muted\",\n\t\t\t\t\t`Max characters in the memory file (${MEMORY_CHAR_CAP_MIN}-${MEMORY_CHAR_CAP_MAX}, default ${MEMORY_CHAR_CAP_DEFAULT}).`,\n\t\t\t\t),\n\t\t\t\t0,\n\t\t\t\t0,\n\t\t\t),\n\t\t);\n\t\tthis.addChild(new Spacer(1));\n\n\t\tthis.input = new Input();\n\t\tthis.input.setValue(currentValue);\n\t\tthis.input.onSubmit = (value) => {\n\t\t\tconst n = Number(value.trim());\n\t\t\tif (!Number.isInteger(n) || n < MEMORY_CHAR_CAP_MIN || n > MEMORY_CHAR_CAP_MAX) {\n\t\t\t\tthis.errorText.setText(\n\t\t\t\t\ttheme.fg(\"error\", ` Enter an integer between ${MEMORY_CHAR_CAP_MIN} and ${MEMORY_CHAR_CAP_MAX}.`),\n\t\t\t\t);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tdone(String(n));\n\t\t};\n\t\tthis.input.onEscape = () => done();\n\t\tthis.addChild(this.input);\n\n\t\tthis.errorText = new Text(\"\", 0, 0);\n\t\tthis.addChild(this.errorText);\n\t\tthis.addChild(new Text(theme.fg(\"dim\", \" Enter to save · Esc to cancel\"), 0, 0));\n\t}\n\n\thandleInput(data: string): void {\n\t\tthis.input.handleInput(data);\n\t}\n}\n\nconst SEARCH_CURATOR_VALUES: SearchCuratorSetting[] = [\"off\", \"on\", \"auto-summary\"];\n\n// lunr: Customize submenu — toggles for the lunR TUI customize settings.\nclass CustomizeSubmenu extends Container {\n\tprivate settingsList: SettingsList;\n\n\tconstructor(_config: SettingsConfig, callbacks: SettingsCallbacks, done: (selectedValue?: string) => void) {\n\t\tsuper();\n\n\t\t// Read live values from the customize bridge so re-entering the submenu within\n\t\t// one /settings session reflects toggles made earlier in that session.\n\t\tconst bridge = getCustomizeBridge();\n\t\tconst items: SettingItem[] = [\n\t\t\t{\n\t\t\t\tid: \"gutter-rail\",\n\t\t\t\tlabel: \"Gutter rail\",\n\t\t\t\tdescription: \"Render a thin left │ rail spanning each turn, closing with ╰.\",\n\t\t\t\tcurrentValue: (bridge?.getGutterRail() ?? true) ? \"on\" : \"off\",\n\t\t\t\tvalues: [\"on\", \"off\"],\n\t\t\t},\n\t\t\t{\n\t\t\t\tid: \"prompt-symbol\",\n\t\t\t\tlabel: \"Prompt symbol\",\n\t\t\t\tdescription: \"Show the ☾ › prompt glyph on the editor's first line.\",\n\t\t\t\tcurrentValue: (bridge?.getPromptSymbol() ?? true) ? \"on\" : \"off\",\n\t\t\t\tvalues: [\"on\", \"off\"],\n\t\t\t},\n\t\t\t{\n\t\t\t\tid: \"footer-mcp\",\n\t\t\t\tlabel: \"Footer: MCP status\",\n\t\t\t\tdescription: \"Show the MCP server status segment in the footer stats line.\",\n\t\t\t\tcurrentValue: (bridge?.getFooterMcp() ?? true) ? \"on\" : \"off\",\n\t\t\t\tvalues: [\"on\", \"off\"],\n\t\t\t},\n\t\t\t{\n\t\t\t\tid: \"footer-lsp\",\n\t\t\t\tlabel: \"Footer: LSP status\",\n\t\t\t\tdescription: \"Show the LSP status segment in the footer stats line.\",\n\t\t\t\tcurrentValue: (bridge?.getFooterLsp() ?? false) ? \"on\" : \"off\",\n\t\t\t\tvalues: [\"on\", \"off\"],\n\t\t\t},\n\t\t\t{\n\t\t\t\tid: \"footer-context\",\n\t\t\t\tlabel: \"Footer: context meter\",\n\t\t\t\tdescription: \"Show the context-usage pct/window segment in the footer stats line.\",\n\t\t\t\tcurrentValue: (bridge?.getFooterContext() ?? true) ? \"on\" : \"off\",\n\t\t\t\tvalues: [\"on\", \"off\"],\n\t\t\t},\n\t\t\t{\n\t\t\t\tid: \"footer-tokens\",\n\t\t\t\tlabel: \"Footer: token counter\",\n\t\t\t\tdescription: \"Show the ↑in ↓out token totals segment in the footer stats line.\",\n\t\t\t\tcurrentValue: (bridge?.getFooterTokens() ?? true) ? \"on\" : \"off\",\n\t\t\t\tvalues: [\"on\", \"off\"],\n\t\t\t},\n\t\t\t{\n\t\t\t\tid: \"footer-statuses\",\n\t\t\t\tlabel: \"Footer: feature statuses\",\n\t\t\t\tdescription: \"Show the plan/goal/swarm/research/tps status segments in the footer stats line.\",\n\t\t\t\tcurrentValue: (bridge?.getFooterStatuses() ?? true) ? \"on\" : \"off\",\n\t\t\t\tvalues: [\"on\", \"off\"],\n\t\t\t},\n\t\t];\n\n\t\tthis.settingsList = new SettingsList(\n\t\t\titems,\n\t\t\tMath.min(items.length, 10),\n\t\t\tgetSettingsListTheme(),\n\t\t\t(id, newValue) => {\n\t\t\t\tswitch (id) {\n\t\t\t\t\tcase \"gutter-rail\":\n\t\t\t\t\t\tcallbacks.onGutterRailChange(newValue === \"on\");\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase \"prompt-symbol\":\n\t\t\t\t\t\tcallbacks.onPromptSymbolChange(newValue === \"on\");\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase \"footer-mcp\":\n\t\t\t\t\t\tcallbacks.onFooterMcpChange(newValue === \"on\");\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase \"footer-lsp\":\n\t\t\t\t\t\tcallbacks.onFooterLspChange(newValue === \"on\");\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase \"footer-context\":\n\t\t\t\t\t\tcallbacks.onFooterContextChange(newValue === \"on\");\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase \"footer-tokens\":\n\t\t\t\t\t\tcallbacks.onFooterTokensChange(newValue === \"on\");\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase \"footer-statuses\":\n\t\t\t\t\t\tcallbacks.onFooterStatusesChange(newValue === \"on\");\n\t\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t},\n\t\t\t() => done(),\n\t\t);\n\n\t\tthis.addChild(this.settingsList);\n\t}\n\n\thandleInput(data: string): void {\n\t\tthis.settingsList.handleInput(data);\n\t}\n}\n\n// lunr: Rollback submenu — enable, turns, capture mode, scope.\nclass RollbackSubmenu extends Container {\n\tprivate settingsList: SettingsList;\n\tprivate enabled: boolean;\n\n\tconstructor(\n\t\tcurrentValue: string | undefined,\n\t\tconfig: SettingsConfig,\n\t\tcallbacks: SettingsCallbacks,\n\t\tsessionForceEnabled: boolean,\n\t\tdone: (selectedValue?: string) => void,\n\t) {\n\t\tsuper();\n\n\t\tthis.enabled = currentValue === \"on\" || (currentValue === undefined && config.rollbackEnabled);\n\n\t\tconst items: SettingItem[] = [\n\t\t\t{\n\t\t\t\tid: \"rollback-enabled\",\n\t\t\t\tlabel: \"Rollback enabled\",\n\t\t\t\tdescription:\n\t\t\t\t\t\"Copy files before edits so /rollback can restore them. Uses extra disk + processing.\" +\n\t\t\t\t\t(sessionForceEnabled ? \" (forced on by auto mode)\" : \"\"),\n\t\t\t\tcurrentValue: this.enabled ? \"on\" : \"off\",\n\t\t\t\tvalues: [\"on\", \"off\"],\n\t\t\t\tdisabled: () => sessionForceEnabled,\n\t\t\t},\n\t\t\t{\n\t\t\t\tid: \"rollback-turns\",\n\t\t\t\tlabel: \"Rollback turns\",\n\t\t\t\tdescription: `How many turns of snapshots to retain (1-20, default 2).`,\n\t\t\t\tcurrentValue: String(config.rollbackTurns),\n\t\t\t\tdisabled: () => !this.enabled,\n\t\t\t\tsubmenu: (currentValue, submenuDone) => new RollbackTurnsSubmenu(currentValue, submenuDone),\n\t\t\t},\n\t\t\t{\n\t\t\t\tid: \"rollback-capture\",\n\t\t\t\tlabel: \"Capture mode\",\n\t\t\t\tdescription:\n\t\t\t\t\t\"How snapshots are taken: copies = restore edited files + delete tool-created files, hybrid = also delete files created outside tools (tree scope), shadow-git = hidden git repo (needs git).\",\n\t\t\t\tcurrentValue: config.rollbackCapture,\n\t\t\t\tdisabled: () => !this.enabled,\n\t\t\t\tsubmenu: (currentValue, submenuDone) =>\n\t\t\t\t\tnew SelectSubmenu(\n\t\t\t\t\t\t\"Rollback Capture Mode\",\n\t\t\t\t\t\t\"How file snapshots are captured before edits.\",\n\t\t\t\t\t\t[\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tvalue: \"copies\",\n\t\t\t\t\t\t\t\tlabel: \"copies\",\n\t\t\t\t\t\t\t\tdescription: \"fast; restores edits, deletes tool-created files\",\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tvalue: \"hybrid\",\n\t\t\t\t\t\t\t\tlabel: \"hybrid\",\n\t\t\t\t\t\t\t\tdescription: \"also deletes files created outside tools (tree scope)\",\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tvalue: \"shadow-git\",\n\t\t\t\t\t\t\t\tlabel: \"shadow-git\",\n\t\t\t\t\t\t\t\tdescription: \"needs git, hidden repo — deferred, falls back to copies\",\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t],\n\t\t\t\t\t\tcurrentValue,\n\t\t\t\t\t\t(value) => {\n\t\t\t\t\t\t\tcallbacks.onRollbackCaptureChange(value as RollbackCapture);\n\t\t\t\t\t\t\tsubmenuDone(value);\n\t\t\t\t\t\t},\n\t\t\t\t\t\t() => submenuDone(),\n\t\t\t\t\t),\n\t\t\t},\n\t\t\t{\n\t\t\t\tid: \"rollback-scope\",\n\t\t\t\tlabel: \"Rollback scope\",\n\t\t\t\tdescription:\n\t\t\t\t\t\"tools = only edit/write changes; tree = also catches bash side-effects via git status (slower on large repos).\",\n\t\t\t\tcurrentValue: config.rollbackScope,\n\t\t\t\tdisabled: () => !this.enabled,\n\t\t\t\tsubmenu: (currentValue, submenuDone) =>\n\t\t\t\t\tnew SelectSubmenu(\n\t\t\t\t\t\t\"Rollback Scope\",\n\t\t\t\t\t\t\"What file changes to snapshot.\",\n\t\t\t\t\t\t[\n\t\t\t\t\t\t\t{ value: \"tools\", label: \"tools\", description: \"only edit/write tool changes\" },\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tvalue: \"tree\",\n\t\t\t\t\t\t\t\tlabel: \"tree\",\n\t\t\t\t\t\t\t\tdescription: \"also catches bash side-effects; slower on large repos\",\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t],\n\t\t\t\t\t\tcurrentValue,\n\t\t\t\t\t\t(value) => {\n\t\t\t\t\t\t\tcallbacks.onRollbackScopeChange(value as RollbackScope);\n\t\t\t\t\t\t\tsubmenuDone(value);\n\t\t\t\t\t\t},\n\t\t\t\t\t\t() => submenuDone(),\n\t\t\t\t\t),\n\t\t\t},\n\t\t];\n\n\t\tthis.settingsList = new SettingsList(\n\t\t\titems,\n\t\t\tMath.min(items.length, 10),\n\t\t\tgetSettingsListTheme(),\n\t\t\t(id, newValue) => {\n\t\t\t\tswitch (id) {\n\t\t\t\t\tcase \"rollback-enabled\":\n\t\t\t\t\t\tthis.enabled = newValue === \"on\";\n\t\t\t\t\t\tcallbacks.onRollbackEnabledChange(this.enabled);\n\t\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t},\n\t\t\t() => done(this.enabled ? \"on\" : \"off\"),\n\t\t);\n\t\tthis.addChild(new Text(theme.bold(theme.fg(\"accent\", \"Rollback\")), 0, 0));\n\t\tthis.addChild(new Spacer(1));\n\t\tthis.addChild(this.settingsList);\n\t\tthis.addChild(new Text(theme.fg(\"dim\", \" Esc to go back\"), 0, 0));\n\t}\n\n\thandleInput(data: string): void {\n\t\tthis.settingsList.handleInput(data);\n\t}\n}\n\nclass RollbackTurnsSubmenu extends Container {\n\tprivate input: Input;\n\tprivate errorText: Text;\n\n\tconstructor(currentValue: string, done: (selectedValue?: string) => void) {\n\t\tsuper();\n\t\tthis.addChild(new Text(theme.bold(theme.fg(\"accent\", \"Rollback Turns\")), 0, 0));\n\t\tthis.addChild(new Spacer(1));\n\t\tthis.addChild(new Text(theme.fg(\"muted\", \"How many turns of snapshots to retain (1-20, default 2).\"), 0, 0));\n\t\tthis.addChild(new Spacer(1));\n\t\tthis.input = new Input();\n\t\tthis.input.setValue(currentValue);\n\t\tthis.input.onSubmit = (value) => {\n\t\t\tconst n = Number(value.trim());\n\t\t\tif (!Number.isInteger(n) || n < 1 || n > 20) {\n\t\t\t\tthis.errorText.setText(theme.fg(\"error\", \" Enter an integer between 1 and 20.\"));\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tdone(String(n));\n\t\t};\n\t\tthis.input.onEscape = () => done();\n\t\tthis.addChild(this.input);\n\t\tthis.errorText = new Text(\"\", 0, 0);\n\t\tthis.addChild(this.errorText);\n\t\tthis.addChild(new Text(theme.fg(\"dim\", \" Enter to save · Esc to cancel\"), 0, 0));\n\t}\n\n\thandleInput(data: string): void {\n\t\tthis.input.handleInput(data);\n\t}\n}\n\n// lunr: one subscription pool entry, passed as plain data so render paths stay synchronous.\nexport interface SubscriptionRowInfo {\n\tproviderId: string;\n\tproviderName: string;\n\tid: string;\n\tname: string;\n\tactive: boolean;\n\texhaustedUntil?: number;\n}\n\n// lunr: live accessors for the subscription pool, wired by interactive-mode.\nexport interface SubscriptionCallbacks {\n\tlist: () => Promise<SubscriptionRowInfo[]>;\n\tsetActive: (providerId: string, id: string) => Promise<void>;\n\trename: (providerId: string, id: string, name: string) => Promise<void>;\n\tclearExhaustion: (providerId: string, id: string) => Promise<void>;\n\tremove: (providerId: string, id: string) => Promise<void>;\n\tautoManage: () => boolean;\n\trequestRender: () => void;\n}\n\n// lunr: format an exhaustion timestamp — local HH:mm when it ends today, else a short date.\nexport function formatSubscriptionExhaustedUntil(exhaustedUntil: number, now: number = Date.now()): string {\n\tconst date = new Date(exhaustedUntil);\n\tif (date.toDateString() === new Date(now).toDateString()) {\n\t\treturn date.toTimeString().slice(0, 5);\n\t}\n\treturn date.toLocaleDateString(undefined, { month: \"short\", day: \"numeric\" });\n}\n\n// lunr: free-text rename prompt for a subscription key (same Input pattern as MemoryCharCapSubmenu).\nclass SubscriptionRenameSubmenu extends Container {\n\tprivate input: Input;\n\tprivate errorText: Text;\n\n\tconstructor(currentName: string, done: (selectedValue?: string) => void) {\n\t\tsuper();\n\t\tthis.addChild(new Text(theme.bold(theme.fg(\"accent\", \"Rename Subscription\")), 0, 0));\n\t\tthis.addChild(new Spacer(1));\n\t\tthis.addChild(new Text(theme.fg(\"muted\", \"Display name for this API key.\"), 0, 0));\n\t\tthis.addChild(new Spacer(1));\n\t\tthis.input = new Input();\n\t\tthis.input.setValue(currentName);\n\t\tthis.input.onSubmit = (value) => {\n\t\t\tconst name = value.trim();\n\t\t\tif (!name) {\n\t\t\t\tthis.errorText.setText(theme.fg(\"error\", \" Enter a non-empty name.\"));\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tdone(name);\n\t\t};\n\t\tthis.input.onEscape = () => done();\n\t\tthis.addChild(this.input);\n\t\tthis.errorText = new Text(\"\", 0, 0);\n\t\tthis.addChild(this.errorText);\n\t\tthis.addChild(new Text(theme.fg(\"dim\", \" Enter to save · Esc to cancel\"), 0, 0));\n\t}\n\n\thandleInput(data: string): void {\n\t\tthis.input.handleInput(data);\n\t}\n}\n\n// lunr: per-subscription actions — set active, rename, clear exhaustion, remove.\n// onChanged asks the parent SubscriptionsSubmenu to reload its rows from the live manager.\nclass SubscriptionActionSubmenu extends Container {\n\tprivate settingsList: SettingsList;\n\n\tconstructor(\n\t\trow: SubscriptionRowInfo,\n\t\tsubs: SubscriptionCallbacks,\n\t\tdone: (selectedValue?: string) => void,\n\t\tonChanged: () => void,\n\t) {\n\t\tsuper();\n\n\t\tconst items: SettingItem[] = [\n\t\t\t{\n\t\t\t\tid: \"set-active\",\n\t\t\t\tlabel: \"Set active\",\n\t\t\t\tdescription: subs.autoManage()\n\t\t\t\t\t? \"Manual switching is disabled while Auto-manage subscriptions is on.\"\n\t\t\t\t\t: \"Use this key for new requests.\",\n\t\t\t\tcurrentValue: row.active ? \"already active\" : \"activate\",\n\t\t\t\tvalues: [\"activate\"],\n\t\t\t\tdisabled: () => subs.autoManage() || row.active,\n\t\t\t},\n\t\t\t{\n\t\t\t\tid: \"rename\",\n\t\t\t\tlabel: \"Rename\",\n\t\t\t\tdescription: \"Display name for this key.\",\n\t\t\t\tcurrentValue: row.name,\n\t\t\t\tsubmenu: (currentValue, renameDone) =>\n\t\t\t\t\tnew SubscriptionRenameSubmenu(currentValue, (name) => {\n\t\t\t\t\t\tif (name === undefined) {\n\t\t\t\t\t\t\trenameDone();\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tvoid subs.rename(row.providerId, row.id, name).then(() => {\n\t\t\t\t\t\t\trenameDone(name);\n\t\t\t\t\t\t\tdone();\n\t\t\t\t\t\t\tonChanged();\n\t\t\t\t\t\t});\n\t\t\t\t\t}),\n\t\t\t},\n\t\t\t{\n\t\t\t\tid: \"clear-exhaustion\",\n\t\t\t\tlabel: \"Clear exhausted flag\",\n\t\t\t\tdescription:\n\t\t\t\t\trow.exhaustedUntil !== undefined\n\t\t\t\t\t\t? `Marked exhausted until ${formatSubscriptionExhaustedUntil(row.exhaustedUntil)}.`\n\t\t\t\t\t\t: \"Only available for keys marked exhausted.\",\n\t\t\t\tcurrentValue: \"clear\",\n\t\t\t\tvalues: [\"clear\"],\n\t\t\t\tdisabled: () => row.exhaustedUntil === undefined,\n\t\t\t},\n\t\t\t{\n\t\t\t\tid: \"remove\",\n\t\t\t\tlabel: \"Remove\",\n\t\t\t\tdescription: \"Delete this key. Removing the provider's last key logs it out completely.\",\n\t\t\t\tcurrentValue: \"remove…\",\n\t\t\t\tsubmenu: (_currentValue, confirmDone) =>\n\t\t\t\t\tnew SelectSubmenu(\n\t\t\t\t\t\t\"Remove Subscription\",\n\t\t\t\t\t\t`Remove \"${row.name}\" (${row.providerName})? Removing the provider's last key logs it out.`,\n\t\t\t\t\t\t[\n\t\t\t\t\t\t\t{ value: \"cancel\", label: \"Cancel\" },\n\t\t\t\t\t\t\t{ value: \"remove\", label: \"Remove key\" },\n\t\t\t\t\t\t],\n\t\t\t\t\t\t\"cancel\",\n\t\t\t\t\t\t(value) => {\n\t\t\t\t\t\t\tif (value !== \"remove\") {\n\t\t\t\t\t\t\t\tconfirmDone();\n\t\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tvoid subs.remove(row.providerId, row.id).then(() => {\n\t\t\t\t\t\t\t\tconfirmDone();\n\t\t\t\t\t\t\t\tdone();\n\t\t\t\t\t\t\t\tonChanged();\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t},\n\t\t\t\t\t\t() => confirmDone(),\n\t\t\t\t\t),\n\t\t\t},\n\t\t];\n\n\t\tthis.settingsList = new SettingsList(\n\t\t\titems,\n\t\t\tMath.min(items.length, 10),\n\t\t\tgetSettingsListTheme(),\n\t\t\t(id) => {\n\t\t\t\tif (id === \"set-active\") {\n\t\t\t\t\tvoid subs.setActive(row.providerId, row.id).then(() => {\n\t\t\t\t\t\tdone();\n\t\t\t\t\t\tonChanged();\n\t\t\t\t\t});\n\t\t\t\t} else if (id === \"clear-exhaustion\") {\n\t\t\t\t\tvoid subs.clearExhaustion(row.providerId, row.id).then(() => {\n\t\t\t\t\t\tdone();\n\t\t\t\t\t\tonChanged();\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t},\n\t\t\t() => done(),\n\t\t);\n\n\t\tthis.addChild(new Text(theme.bold(theme.fg(\"accent\", `${row.providerName} — ${row.name}`)), 0, 0));\n\t\tthis.addChild(new Spacer(1));\n\t\tthis.addChild(this.settingsList);\n\t}\n\n\thandleInput(data: string): void {\n\t\tthis.settingsList.handleInput(data);\n\t}\n}\n\n// lunr: Subscriptions submenu — one row per pooled API key across all providers.\n// Rows reload from the live manager on open and after every mutation.\nclass SubscriptionsSubmenu extends Container {\n\tprivate readonly subs: SubscriptionCallbacks;\n\tprivate readonly done: (selectedValue?: string) => void;\n\tprivate contentContainer: Container;\n\tprivate settingsList: SettingsList | undefined;\n\tprivate closed = false;\n\n\tconstructor(subs: SubscriptionCallbacks, done: (selectedValue?: string) => void) {\n\t\tsuper();\n\t\tthis.subs = subs;\n\t\tthis.done = done;\n\t\tthis.addChild(new Text(theme.bold(theme.fg(\"accent\", \"Subscriptions\")), 0, 0));\n\t\tthis.addChild(new Spacer(1));\n\t\tthis.contentContainer = new Container();\n\t\tthis.addChild(this.contentContainer);\n\t\tthis.contentContainer.addChild(new Text(theme.fg(\"muted\", \" Loading…\"), 0, 0));\n\t\tvoid this.reload();\n\t}\n\n\tprivate async reload(): Promise<void> {\n\t\tlet rows: SubscriptionRowInfo[] = [];\n\t\ttry {\n\t\t\trows = await this.subs.list();\n\t\t} catch {\n\t\t\trows = [];\n\t\t}\n\t\tif (this.closed) return;\n\n\t\tthis.contentContainer.clear();\n\t\tthis.settingsList = undefined;\n\n\t\tif (rows.length === 0) {\n\t\t\tthis.contentContainer.addChild(new Text(theme.fg(\"muted\", \" No stored API key subscriptions.\"), 0, 0));\n\t\t\tthis.contentContainer.addChild(new Text(theme.fg(\"dim\", \" Esc to go back\"), 0, 0));\n\t\t\tthis.subs.requestRender();\n\t\t\treturn;\n\t\t}\n\n\t\tconst items: SettingItem[] = rows.map((row) => ({\n\t\t\tid: `${row.providerId}/${row.id}`,\n\t\t\tlabel: `${row.providerName} — ${row.name}`,\n\t\t\tdescription:\n\t\t\t\t`${row.providerId} API key` +\n\t\t\t\t(row.exhaustedUntil !== undefined\n\t\t\t\t\t? ` · exhausted until ${formatSubscriptionExhaustedUntil(row.exhaustedUntil)}`\n\t\t\t\t\t: \"\"),\n\t\t\tcurrentValue: row.active ? \"active\" : row.exhaustedUntil !== undefined ? \"exhausted\" : \"\",\n\t\t\tsubmenu: (_currentValue, subDone) =>\n\t\t\t\tnew SubscriptionActionSubmenu(row, this.subs, subDone, () => void this.reload()),\n\t\t}));\n\n\t\tthis.settingsList = new SettingsList(\n\t\t\titems,\n\t\t\tMath.min(items.length, 10),\n\t\t\tgetSettingsListTheme(),\n\t\t\t() => {},\n\t\t\t// Closing reports the current count so the parent row label stays fresh.\n\t\t\t() => this.done(`${rows.length} key${rows.length === 1 ? \"\" : \"s\"}`),\n\t\t);\n\t\tthis.contentContainer.addChild(this.settingsList);\n\t\tthis.subs.requestRender();\n\t}\n\n\thandleInput(data: string): void {\n\t\tif (this.settingsList) {\n\t\t\tthis.settingsList.handleInput(data);\n\t\t\treturn;\n\t\t}\n\t\t// Loading/empty state: only Esc goes back.\n\t\tif (getKeybindings().matches(data, \"tui.select.cancel\")) {\n\t\t\tthis.closed = true;\n\t\t\tthis.done();\n\t\t}\n\t}\n}\n\nclass SelectSubmenu extends Container {\n\tprivate selectList: SelectList;\n\n\tconstructor(\n\t\ttitle: string,\n\t\tdescription: string,\n\t\toptions: SelectItem[],\n\t\tcurrentValue: string,\n\t\tonSelect: (value: string) => void,\n\t\tonCancel: () => void,\n\t\tonSelectionChange?: (value: string) => void,\n\t) {\n\t\tsuper();\n\n\t\t// Title\n\t\tthis.addChild(new Text(theme.bold(theme.fg(\"accent\", title)), 0, 0));\n\n\t\t// Description\n\t\tif (description) {\n\t\t\tthis.addChild(new Spacer(1));\n\t\t\tthis.addChild(new Text(theme.fg(\"muted\", description), 0, 0));\n\t\t}\n\n\t\t// Spacer\n\t\tthis.addChild(new Spacer(1));\n\n\t\t// Select list\n\t\tthis.selectList = new SelectList(\n\t\t\toptions,\n\t\t\tMath.min(options.length, 10),\n\t\t\tgetSelectListTheme(),\n\t\t\tSETTINGS_SUBMENU_SELECT_LIST_LAYOUT,\n\t\t);\n\n\t\t// Pre-select current value\n\t\tconst currentIndex = options.findIndex((o) => o.value === currentValue);\n\t\tif (currentIndex !== -1) {\n\t\t\tthis.selectList.setSelectedIndex(currentIndex);\n\t\t}\n\n\t\tthis.selectList.onSelect = (item) => {\n\t\t\tonSelect(item.value);\n\t\t};\n\n\t\tthis.selectList.onCancel = onCancel;\n\n\t\tif (onSelectionChange) {\n\t\t\tthis.selectList.onSelectionChange = (item) => {\n\t\t\t\tonSelectionChange(item.value);\n\t\t\t};\n\t\t}\n\n\t\tthis.addChild(this.selectList);\n\n\t\t// Hint\n\t\tthis.addChild(new Spacer(1));\n\t\tthis.addChild(new Text(theme.fg(\"dim\", \" Enter to select · Esc to go back\"), 0, 0));\n\t}\n\n\thandleInput(data: string): void {\n\t\tthis.selectList.handleInput(data);\n\t}\n}\n\nfunction themeItems(availableThemes: string[]): SelectItem[] {\n\treturn availableThemes.map((name) => ({ value: name, label: name }));\n}\n\nconst AUTOMATIC_THEME_VALUE = \"/\";\n\nfunction singleModeThemeItems(availableThemes: string[]): SelectItem[] {\n\treturn [\n\t\t{\n\t\t\tvalue: AUTOMATIC_THEME_VALUE,\n\t\t\tlabel: \"Automatic\",\n\t\t\tdescription: \"Use separate themes for light and dark terminal appearance\",\n\t\t},\n\t\t...themeItems(availableThemes),\n\t];\n}\n\nfunction preferredTheme(availableThemes: string[], preferred: string | undefined, fallback: string): string {\n\tif (preferred && availableThemes.includes(preferred)) return preferred;\n\tif (availableThemes.includes(fallback)) return fallback;\n\treturn availableThemes[0] ?? fallback;\n}\n\nfunction defaultAutomaticThemes(\n\tcurrentThemeSetting: string,\n\tavailableThemes: string[],\n): { lightTheme: string; darkTheme: string } {\n\tconst autoTheme = parseAutoThemeSetting(currentThemeSetting);\n\tif (autoTheme) return autoTheme;\n\n\tconst currentFixedTheme = currentThemeSetting.includes(\"/\") ? undefined : currentThemeSetting;\n\tconst themeName = preferredTheme(availableThemes, currentFixedTheme, \"moon\");\n\treturn { lightTheme: themeName, darkTheme: themeName };\n}\n\nclass ThemeSubmenu extends Container {\n\tprivate inputComponent: Component | undefined;\n\tprivate readonly callbacks: SettingsCallbacks;\n\tprivate readonly availableThemes: string[];\n\tprivate readonly terminalTheme: TerminalTheme;\n\tprivate readonly onDone: (selectedValue?: string) => void;\n\tprivate readonly originalThemeSetting: string;\n\tprivate mode: \"single\" | \"automatic\";\n\tprivate singleTheme: string;\n\tprivate lightTheme: string;\n\tprivate darkTheme: string;\n\n\tconstructor(\n\t\tcurrentThemeSetting: string,\n\t\tterminalTheme: TerminalTheme,\n\t\tavailableThemes: string[],\n\t\tcallbacks: SettingsCallbacks,\n\t\tonDone: (selectedValue?: string) => void,\n\t) {\n\t\tsuper();\n\t\tthis.callbacks = callbacks;\n\t\tthis.availableThemes = availableThemes;\n\t\tthis.terminalTheme = terminalTheme;\n\t\tthis.onDone = onDone;\n\t\tthis.originalThemeSetting = currentThemeSetting;\n\t\tconst autoTheme = parseAutoThemeSetting(currentThemeSetting);\n\t\tconst automaticThemes = defaultAutomaticThemes(currentThemeSetting, availableThemes);\n\t\tconst fixedTheme = autoTheme || currentThemeSetting.includes(\"/\") ? undefined : currentThemeSetting;\n\t\tthis.mode = autoTheme ? \"automatic\" : \"single\";\n\t\tthis.lightTheme = automaticThemes.lightTheme;\n\t\tthis.darkTheme = automaticThemes.darkTheme;\n\t\tthis.singleTheme = preferredTheme(\n\t\t\tavailableThemes,\n\t\t\tfixedTheme ?? (autoTheme ? this.getActiveAutomaticTheme() : undefined),\n\t\t\t\"moon\",\n\t\t);\n\n\t\tif (this.mode === \"automatic\") {\n\t\t\tthis.showAutomaticMenu();\n\t\t} else {\n\t\t\tthis.showSingleMenu();\n\t\t}\n\t}\n\n\thandleInput(data: string): void {\n\t\tthis.inputComponent?.handleInput?.(data);\n\t}\n\n\tprivate setContent(renderComponent: Component, inputComponent: Component = renderComponent): void {\n\t\tthis.clear();\n\t\tthis.addChild(renderComponent);\n\t\tthis.inputComponent = inputComponent;\n\t}\n\n\tprivate showSingleMenu(): void {\n\t\tthis.mode = \"single\";\n\t\tconst menu = new SelectSubmenu(\n\t\t\t\"Theme\",\n\t\t\t\"Select a theme, or choose Automatic to follow terminal appearance.\",\n\t\t\tsingleModeThemeItems(this.availableThemes),\n\t\t\tthis.singleTheme,\n\t\t\t(value) => {\n\t\t\t\tif (value === AUTOMATIC_THEME_VALUE) {\n\t\t\t\t\tthis.mode = \"automatic\";\n\t\t\t\t\tthis.callbacks.onThemePreview?.(this.getThemeSetting());\n\t\t\t\t\tthis.showAutomaticMenu();\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tthis.singleTheme = value;\n\t\t\t\tthis.apply(value);\n\t\t\t},\n\t\t\t() => this.cancel(),\n\t\t\t(value) => {\n\t\t\t\tthis.callbacks.onThemePreview?.(value === AUTOMATIC_THEME_VALUE ? this.getAutomaticThemeSetting() : value);\n\t\t\t},\n\t\t);\n\t\tthis.setContent(menu);\n\t}\n\n\tprivate showAutomaticMenu(): void {\n\t\tthis.mode = \"automatic\";\n\t\tconst content = new Container();\n\t\tcontent.addChild(new Text(theme.bold(theme.fg(\"accent\", \"Automatic Theme\")), 0, 0));\n\t\tcontent.addChild(new Spacer(1));\n\t\tcontent.addChild(new Text(theme.fg(\"muted\", \"Choose themes for terminal light and dark appearance.\"), 0, 0));\n\t\tcontent.addChild(new Text(theme.fg(\"muted\", \"Light/dark detection requires terminal support.\"), 0, 0));\n\t\tcontent.addChild(new Spacer(1));\n\n\t\tconst items: SettingItem[] = [\n\t\t\t{\n\t\t\t\tid: \"light-theme\",\n\t\t\t\tlabel: \"Light theme\",\n\t\t\t\tdescription: \"Theme to use in automatic mode when the terminal is light\",\n\t\t\t\tcurrentValue: this.lightTheme,\n\t\t\t\tsubmenu: (currentValue, done) =>\n\t\t\t\t\tthis.createThemeSelect(\n\t\t\t\t\t\t\"Light Theme\",\n\t\t\t\t\t\t\"Select the theme to use for light terminal appearance\",\n\t\t\t\t\t\tcurrentValue,\n\t\t\t\t\t\tdone,\n\t\t\t\t\t\t(value) => {\n\t\t\t\t\t\t\tthis.lightTheme = value;\n\t\t\t\t\t\t\tthis.callbacks.onThemePreview?.(this.getThemeSetting());\n\t\t\t\t\t\t\tdone(value);\n\t\t\t\t\t\t},\n\t\t\t\t\t),\n\t\t\t},\n\t\t\t{\n\t\t\t\tid: \"dark-theme\",\n\t\t\t\tlabel: \"Dark theme\",\n\t\t\t\tdescription: \"Theme to use in automatic mode when the terminal is dark\",\n\t\t\t\tcurrentValue: this.darkTheme,\n\t\t\t\tsubmenu: (currentValue, done) =>\n\t\t\t\t\tthis.createThemeSelect(\n\t\t\t\t\t\t\"Dark Theme\",\n\t\t\t\t\t\t\"Select the theme to use for dark terminal appearance\",\n\t\t\t\t\t\tcurrentValue,\n\t\t\t\t\t\tdone,\n\t\t\t\t\t\t(value) => {\n\t\t\t\t\t\t\tthis.darkTheme = value;\n\t\t\t\t\t\t\tthis.callbacks.onThemePreview?.(this.getThemeSetting());\n\t\t\t\t\t\t\tdone(value);\n\t\t\t\t\t\t},\n\t\t\t\t\t),\n\t\t\t},\n\t\t\t{\n\t\t\t\tid: \"apply\",\n\t\t\t\tlabel: \"Apply\",\n\t\t\t\tdescription: \"Save and go back\",\n\t\t\t\tcurrentValue: \"save and go back\",\n\t\t\t\tvalues: [\"save and go back\"],\n\t\t\t},\n\t\t\t{\n\t\t\t\tid: \"single-mode\",\n\t\t\t\tlabel: \"Change mode\",\n\t\t\t\tdescription: \"Switch to one theme for light and dark\",\n\t\t\t\tcurrentValue: \"switch to single theme\",\n\t\t\t\tvalues: [\"switch to single theme\"],\n\t\t\t},\n\t\t];\n\n\t\tconst settingsList = new SettingsList(\n\t\t\titems,\n\t\t\tMath.min(items.length, 10),\n\t\t\tgetSettingsListTheme(),\n\t\t\t(id) => {\n\t\t\t\tswitch (id) {\n\t\t\t\t\tcase \"single-mode\":\n\t\t\t\t\t\tthis.mode = \"single\";\n\t\t\t\t\t\tthis.singleTheme = this.getActiveAutomaticTheme();\n\t\t\t\t\t\tthis.callbacks.onThemePreview?.(this.singleTheme);\n\t\t\t\t\t\tthis.showSingleMenu();\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase \"apply\":\n\t\t\t\t\t\tthis.apply(this.getAutomaticThemeSetting());\n\t\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t},\n\t\t\t() => this.cancel(),\n\t\t);\n\t\tcontent.addChild(settingsList);\n\t\tthis.setContent(content, settingsList);\n\t}\n\n\tprivate createThemeSelect(\n\t\ttitle: string,\n\t\tdescription: string,\n\t\tcurrentValue: string,\n\t\tdone: (selectedValue?: string) => void,\n\t\tonSelect: (value: string) => void,\n\t): SelectSubmenu {\n\t\treturn new SelectSubmenu(\n\t\t\ttitle,\n\t\t\tdescription,\n\t\t\tthemeItems(this.availableThemes),\n\t\t\tcurrentValue,\n\t\t\tonSelect,\n\t\t\t() => {\n\t\t\t\tthis.callbacks.onThemePreview?.(this.getThemeSetting());\n\t\t\t\tdone();\n\t\t\t},\n\t\t\t(value) => this.callbacks.onThemePreview?.(value),\n\t\t);\n\t}\n\n\tprivate getThemeSetting(): string {\n\t\treturn this.mode === \"automatic\" ? this.getAutomaticThemeSetting() : this.singleTheme;\n\t}\n\n\tprivate getActiveAutomaticTheme(): string {\n\t\treturn this.terminalTheme === \"light\" ? this.lightTheme : this.darkTheme;\n\t}\n\n\tprivate getAutomaticThemeSetting(): string {\n\t\treturn `${this.lightTheme}/${this.darkTheme}`;\n\t}\n\n\tprivate apply(themeSetting: string): void {\n\t\tthis.onDone(themeSetting);\n\t}\n\n\tprivate cancel(): void {\n\t\tthis.callbacks.onThemePreview?.(this.originalThemeSetting);\n\t\tthis.onDone();\n\t}\n}\n\n/**\n * Main settings selector component.\n */\nexport class SettingsSelectorComponent extends Container {\n\tprivate settingsList: SettingsList;\n\n\tconstructor(config: SettingsConfig, callbacks: SettingsCallbacks) {\n\t\tsuper();\n\n\t\tconst supportsImages = getCapabilities().images;\n\t\tconst followUpKey = keyDisplayText(\"app.message.followUp\");\n\t\tconst curatorAvailable = config.searchCurator !== undefined;\n\n\t\tconst items: SettingItem[] = [\n\t\t\t{\n\t\t\t\tid: \"autocompact\",\n\t\t\t\tlabel: \"Auto-compact\",\n\t\t\t\tdescription: \"Automatically compact context when it gets too large\",\n\t\t\t\tcurrentValue: config.autoCompact ? \"true\" : \"false\",\n\t\t\t\tvalues: [\"true\", \"false\"],\n\t\t\t},\n\t\t\t{\n\t\t\t\tid: \"steering-mode\",\n\t\t\t\tlabel: \"Steering mode\",\n\t\t\t\tdescription:\n\t\t\t\t\t\"Enter while streaming queues steering messages. 'one-at-a-time': deliver one, wait for response. 'all': deliver all at once.\",\n\t\t\t\tcurrentValue: config.steeringMode,\n\t\t\t\tvalues: [\"one-at-a-time\", \"all\"],\n\t\t\t},\n\t\t\t{\n\t\t\t\tid: \"follow-up-mode\",\n\t\t\t\tlabel: \"Follow-up mode\",\n\t\t\t\tdescription: `${followUpKey} queues follow-up messages until agent stops. 'one-at-a-time': deliver one, wait for response. 'all': deliver all at once.`,\n\t\t\t\tcurrentValue: config.followUpMode,\n\t\t\t\tvalues: [\"one-at-a-time\", \"all\"],\n\t\t\t},\n\t\t\t{\n\t\t\t\tid: \"transport\",\n\t\t\t\tlabel: \"Transport\",\n\t\t\t\tdescription: \"Preferred transport for providers that support multiple transports\",\n\t\t\t\tcurrentValue: config.transport,\n\t\t\t\tvalues: [\"sse\", \"websocket\", \"websocket-cached\", \"auto\"],\n\t\t\t},\n\t\t\t{\n\t\t\t\tid: \"http-idle-timeout\",\n\t\t\t\tlabel: \"HTTP idle timeout\",\n\t\t\t\tdescription:\n\t\t\t\t\t\"Maximum idle gap while waiting for HTTP headers or body chunks. Disable for local models that pause longer than five minutes.\",\n\t\t\t\tcurrentValue: formatHttpIdleTimeoutMs(config.httpIdleTimeoutMs),\n\t\t\t\tvalues: HTTP_IDLE_TIMEOUT_CHOICES.map((choice) => choice.label),\n\t\t\t},\n\t\t\t{\n\t\t\t\tid: \"hide-thinking\",\n\t\t\t\tlabel: \"Hide thinking\",\n\t\t\t\tdescription: \"Hide thinking blocks in assistant responses\",\n\t\t\t\tcurrentValue: config.hideThinkingBlock ? \"true\" : \"false\",\n\t\t\t\tvalues: [\"true\", \"false\"],\n\t\t\t},\n\t\t\t{\n\t\t\t\t// lunr: collapsible reasoning — completed thinking runs render as\n\t\t\t\t// \"✻ Thought for Xs\" + first sentence. Disabled when thinking is hidden.\n\t\t\t\tid: \"thinking-collapse\",\n\t\t\t\tlabel: \"Collapse thinking\",\n\t\t\t\tdescription: \"Collapse completed thinking blocks to a short summary\",\n\t\t\t\tcurrentValue: config.thinkingCollapse ? \"true\" : \"false\",\n\t\t\t\tvalues: [\"true\", \"false\"],\n\t\t\t\tdisabled: () => config.hideThinkingBlock,\n\t\t\t},\n\t\t\t{\n\t\t\t\tid: \"cache-miss-notices\",\n\t\t\t\tlabel: \"Cache miss notices\",\n\t\t\t\tdescription: \"Show transcript notices for significant prompt-cache misses\",\n\t\t\t\tcurrentValue: config.showCacheMissNotices ? \"true\" : \"false\",\n\t\t\t\tvalues: [\"true\", \"false\"],\n\t\t\t},\n\t\t\t{\n\t\t\t\t// lunr: unset settings stay undefined so PI_CACHE_RETENTION still\n\t\t\t\t// applies; the row displays \"short\" as the implicit default.\n\t\t\t\tid: \"cache-retention\",\n\t\t\t\tlabel: \"Cache retention\",\n\t\t\t\tdescription: \"Prompt-cache TTL: short (5 min), long (1h where supported), or none\",\n\t\t\t\tcurrentValue: config.cacheRetention,\n\t\t\t\tvalues: [\"short\", \"long\", \"none\"],\n\t\t\t},\n\t\t\t{\n\t\t\t\tid: \"quiet-startup\",\n\t\t\t\tlabel: \"Quiet startup\",\n\t\t\t\tdescription: \"Disable verbose printing at startup\",\n\t\t\t\tcurrentValue: config.quietStartup ? \"true\" : \"false\",\n\t\t\t\tvalues: [\"true\", \"false\"],\n\t\t\t},\n\t\t\t{\n\t\t\t\tid: \"smooth-streaming\",\n\t\t\t\tlabel: \"Smooth streaming\",\n\t\t\t\tdescription: \"Reveal responses grapheme by grapheme (~30 FPS typewriter)\",\n\t\t\t\tcurrentValue: config.smoothStreaming ? \"true\" : \"false\",\n\t\t\t\tvalues: [\"true\", \"false\"],\n\t\t\t},\n\t\t\t{\n\t\t\t\tid: \"memory-char-cap\",\n\t\t\t\tlabel: \"Memory character cap\",\n\t\t\t\tdescription: `Max characters in the simple-pi-memory memory file AND the behavior file (${MEMORY_CHAR_CAP_MIN}-${MEMORY_CHAR_CAP_MAX}, default ${MEMORY_CHAR_CAP_DEFAULT}). Also settable via /memory-char-cap.`,\n\t\t\t\tcurrentValue: String(config.memoryCharCap),\n\t\t\t\tsubmenu: (currentValue, submenuDone) => new MemoryCharCapSubmenu(currentValue, submenuDone),\n\t\t\t},\n\t\t\t{\n\t\t\t\tid: \"search-curator\",\n\t\t\t\tlabel: \"Search curator\",\n\t\t\t\tdescription: curatorAvailable\n\t\t\t\t\t? \"pi-web-access search curator: off = raw results, on = browser curator with summary draft, auto-summary = summary without the curator. Also settable via /curator.\"\n\t\t\t\t\t: \"pi-web-access is not loaded; the search curator is unavailable.\",\n\t\t\t\tcurrentValue: config.searchCurator ?? \"unavailable\",\n\t\t\t\tvalues: curatorAvailable ? SEARCH_CURATOR_VALUES : undefined,\n\t\t\t},\n\t\t\t{\n\t\t\t\tid: \"session-retention-days\",\n\t\t\t\tlabel: \"Session retention\",\n\t\t\t\tdescription: \"Auto-delete session files older than N days at launch (0 = keep forever)\",\n\t\t\t\tcurrentValue: String(config.sessionRetentionDays),\n\t\t\t\tvalues: [\"0\", \"7\", \"14\", \"30\", \"60\", \"90\", \"365\"],\n\t\t\t},\n\t\t\t{\n\t\t\t\tid: \"default-project-trust\",\n\t\t\t\tlabel: \"Default project trust\",\n\t\t\t\tdescription: \"Fallback behavior when no extension or saved trust decision decides project trust\",\n\t\t\t\tcurrentValue: DEFAULT_PROJECT_TRUST_LABELS[config.defaultProjectTrust],\n\t\t\t\tvalues: Object.values(DEFAULT_PROJECT_TRUST_LABELS),\n\t\t\t},\n\t\t\t{\n\t\t\t\tid: \"default-permission-mode\",\n\t\t\t\tlabel: \"Default permission mode\",\n\t\t\t\tdescription:\n\t\t\t\t\t\"Permission mode new sessions start with: manual = approve every action, yolo = auto-approve tools, plan = read-only, auto = fully autonomous. Change per-session with /mode or Shift+Tab.\",\n\t\t\t\tcurrentValue: config.defaultPermissionMode,\n\t\t\t\tvalues: [\"manual\", \"yolo\", \"plan\", \"auto\"],\n\t\t\t},\n\t\t\t{\n\t\t\t\tid: \"double-escape-action\",\n\t\t\t\tlabel: \"Double-escape action\",\n\t\t\t\tdescription: \"Action when pressing Escape twice with empty editor\",\n\t\t\t\tcurrentValue: config.doubleEscapeAction,\n\t\t\t\tvalues: [\"tree\", \"fork\", \"none\"],\n\t\t\t},\n\t\t\t{\n\t\t\t\tid: \"tree-filter-mode\",\n\t\t\t\tlabel: \"Tree filter mode\",\n\t\t\t\tdescription: \"Default filter when opening /tree\",\n\t\t\t\tcurrentValue: config.treeFilterMode,\n\t\t\t\tvalues: [\"default\", \"no-tools\", \"user-only\", \"labeled-only\", \"all\"],\n\t\t\t},\n\t\t\t{\n\t\t\t\tid: \"thinking\",\n\t\t\t\tlabel: \"Thinking level\",\n\t\t\t\tdescription: \"Reasoning depth for thinking-capable models\",\n\t\t\t\tcurrentValue: config.thinkingLevel,\n\t\t\t\tsubmenu: (currentValue, done) =>\n\t\t\t\t\tnew SelectSubmenu(\n\t\t\t\t\t\t\"Thinking Level\",\n\t\t\t\t\t\t\"Select reasoning depth for thinking-capable models\",\n\t\t\t\t\t\tconfig.availableThinkingLevels.map((level) => ({\n\t\t\t\t\t\t\tvalue: level,\n\t\t\t\t\t\t\tlabel: level,\n\t\t\t\t\t\t\tdescription: THINKING_DESCRIPTIONS[level],\n\t\t\t\t\t\t})),\n\t\t\t\t\t\tcurrentValue,\n\t\t\t\t\t\t(value) => {\n\t\t\t\t\t\t\tcallbacks.onThinkingLevelChange(value as ThinkingLevel);\n\t\t\t\t\t\t\tdone(value);\n\t\t\t\t\t\t},\n\t\t\t\t\t\t() => done(),\n\t\t\t\t\t),\n\t\t\t},\n\t\t\t{\n\t\t\t\tid: \"theme\",\n\t\t\t\tlabel: \"Theme\",\n\t\t\t\tdescription: \"Color theme for the interface\",\n\t\t\t\tcurrentValue: config.currentTheme,\n\t\t\t\tsubmenu: (currentValue, done) =>\n\t\t\t\t\tnew ThemeSubmenu(currentValue, config.terminalTheme, config.availableThemes, callbacks, done),\n\t\t\t},\n\t\t\t{\n\t\t\t\tid: \"model-tiers\",\n\t\t\t\tlabel: \"Model tiers\",\n\t\t\t\tdescription:\n\t\t\t\t\t\"Route subagents to light/standard/heavy tier models. An explicit model choice overrides the tier.\",\n\t\t\t\tcurrentValue: config.modelTiers.enabled ? \"on\" : \"off\",\n\t\t\t\tsubmenu: (currentValue, done) => new ModelTiersSubmenu(currentValue, config.modelTiers, callbacks, done),\n\t\t\t},\n\t\t\t// lunr: Customize submenu — lunR TUI toggles (rail, prompt symbol, footer segments)\n\t\t\t{\n\t\t\t\tid: \"customize\",\n\t\t\t\tlabel: \"Customize\",\n\t\t\t\tdescription: \"lunR TUI customizations: gutter rail, prompt symbol, footer segments\",\n\t\t\t\tcurrentValue: \"configure\",\n\t\t\t\tsubmenu: (_currentValue, done) => new CustomizeSubmenu(config, callbacks, done),\n\t\t\t},\n\t\t\t// lunr: Rollback submenu\n\t\t\t{\n\t\t\t\tid: \"rollback\",\n\t\t\t\tlabel: \"Rollback\",\n\t\t\t\tdescription: \"Pre-edit file snapshots so /rollback can restore them. Capture mode, scope, retention.\",\n\t\t\t\tcurrentValue: config.rollbackEnabled ? \"on\" : \"off\",\n\t\t\t\tsubmenu: (currentValue, done) =>\n\t\t\t\t\tnew RollbackSubmenu(currentValue, config, callbacks, callbacks.isRollbackSessionForceEnabled(), done),\n\t\t\t},\n\t\t\t// lunr: multi-subscription pools\n\t\t\t{\n\t\t\t\tid: \"auto-manage-subscriptions\",\n\t\t\t\tlabel: \"Auto-manage subscriptions\",\n\t\t\t\tdescription:\n\t\t\t\t\t\"When on, lunr rotates API keys automatically on usage limits and the model selector won't offer manual subscription switching.\",\n\t\t\t\tcurrentValue: config.autoManageSubscriptions ? \"on\" : \"off\",\n\t\t\t\tvalues: [\"on\", \"off\"],\n\t\t\t},\n\t\t];\n\n\t\t// lunr: Subscriptions submenu — one row per pooled API key (live manager accessors).\n\t\tconst subscriptionCallbacks = callbacks.subscriptions;\n\t\tif (subscriptionCallbacks) {\n\t\t\titems.push({\n\t\t\t\tid: \"subscriptions\",\n\t\t\t\tlabel: \"Subscriptions\",\n\t\t\t\tdescription: \"Per-provider API key pools: set the active key, rename, clear exhaustion, remove.\",\n\t\t\t\tcurrentValue:\n\t\t\t\t\tconfig.subscriptionCount === 0\n\t\t\t\t\t\t? \"none\"\n\t\t\t\t\t\t: `${config.subscriptionCount} key${config.subscriptionCount === 1 ? \"\" : \"s\"}`,\n\t\t\t\tsubmenu: (_currentValue, done) => new SubscriptionsSubmenu(subscriptionCallbacks, done),\n\t\t\t});\n\t\t}\n\n\t\t// Only show image toggle if terminal supports it\n\t\tif (supportsImages) {\n\t\t\t// Insert after autocompact\n\t\t\titems.splice(1, 0, {\n\t\t\t\tid: \"show-images\",\n\t\t\t\tlabel: \"Show images\",\n\t\t\t\tdescription: \"Render images inline in terminal\",\n\t\t\t\tcurrentValue: config.showImages ? \"true\" : \"false\",\n\t\t\t\tvalues: [\"true\", \"false\"],\n\t\t\t});\n\t\t\titems.splice(2, 0, {\n\t\t\t\tid: \"image-width-cells\",\n\t\t\t\tlabel: \"Image width\",\n\t\t\t\tdescription: \"Preferred inline image width in terminal cells\",\n\t\t\t\tcurrentValue: String(config.imageWidthCells),\n\t\t\t\tvalues: [\"60\", \"80\", \"120\"],\n\t\t\t});\n\t\t}\n\n\t\t// Image auto-resize toggle (always available, affects both attached and read images)\n\t\titems.splice(supportsImages ? 3 : 1, 0, {\n\t\t\tid: \"auto-resize-images\",\n\t\t\tlabel: \"Auto-resize images\",\n\t\t\tdescription: \"Resize large images to 2000x2000 max for better model compatibility\",\n\t\t\tcurrentValue: config.autoResizeImages ? \"true\" : \"false\",\n\t\t\tvalues: [\"true\", \"false\"],\n\t\t});\n\n\t\t// Block images toggle (always available, insert after auto-resize-images)\n\t\tconst autoResizeIndex = items.findIndex((item) => item.id === \"auto-resize-images\");\n\t\titems.splice(autoResizeIndex + 1, 0, {\n\t\t\tid: \"block-images\",\n\t\t\tlabel: \"Block images\",\n\t\t\tdescription: \"Prevent images from being sent to LLM providers\",\n\t\t\tcurrentValue: config.blockImages ? \"true\" : \"false\",\n\t\t\tvalues: [\"true\", \"false\"],\n\t\t});\n\n\t\t// Skill commands toggle (insert after block-images)\n\t\tconst blockImagesIndex = items.findIndex((item) => item.id === \"block-images\");\n\t\titems.splice(blockImagesIndex + 1, 0, {\n\t\t\tid: \"skill-commands\",\n\t\t\tlabel: \"Skill commands\",\n\t\t\tdescription: \"Register skills as /skill:name commands\",\n\t\t\tcurrentValue: config.enableSkillCommands ? \"true\" : \"false\",\n\t\t\tvalues: [\"true\", \"false\"],\n\t\t});\n\n\t\t// Hardware cursor toggle (insert after skill-commands)\n\t\tconst skillCommandsIndex = items.findIndex((item) => item.id === \"skill-commands\");\n\t\titems.splice(skillCommandsIndex + 1, 0, {\n\t\t\tid: \"show-hardware-cursor\",\n\t\t\tlabel: \"Show hardware cursor\",\n\t\t\tdescription: \"Show the terminal cursor while still positioning it for IME support\",\n\t\t\tcurrentValue: config.showHardwareCursor ? \"true\" : \"false\",\n\t\t\tvalues: [\"true\", \"false\"],\n\t\t});\n\n\t\t// Editor padding toggle (insert after show-hardware-cursor)\n\t\tconst hardwareCursorIndex = items.findIndex((item) => item.id === \"show-hardware-cursor\");\n\t\titems.splice(hardwareCursorIndex + 1, 0, {\n\t\t\tid: \"editor-padding\",\n\t\t\tlabel: \"Editor padding\",\n\t\t\tdescription: \"Horizontal padding for input editor (0-3)\",\n\t\t\tcurrentValue: String(config.editorPaddingX),\n\t\t\tvalues: [\"0\", \"1\", \"2\", \"3\"],\n\t\t});\n\n\t\t// Output padding toggle (insert after editor-padding)\n\t\tconst editorPaddingIndex = items.findIndex((item) => item.id === \"editor-padding\");\n\t\titems.splice(editorPaddingIndex + 1, 0, {\n\t\t\tid: \"output-padding\",\n\t\t\tlabel: \"Output padding\",\n\t\t\tdescription: \"Horizontal padding for user messages, assistant messages, and thinking\",\n\t\t\tcurrentValue: String(config.outputPad),\n\t\t\tvalues: [\"0\", \"1\"],\n\t\t});\n\n\t\t// Autocomplete max visible toggle (insert after output-padding)\n\t\tconst outputPaddingIndex = items.findIndex((item) => item.id === \"output-padding\");\n\t\titems.splice(outputPaddingIndex + 1, 0, {\n\t\t\tid: \"autocomplete-max-visible\",\n\t\t\tlabel: \"Autocomplete max items\",\n\t\t\tdescription: \"Max visible items in autocomplete dropdown (3-20)\",\n\t\t\tcurrentValue: String(config.autocompleteMaxVisible),\n\t\t\tvalues: [\"3\", \"5\", \"7\", \"10\", \"15\", \"20\"],\n\t\t});\n\n\t\t// Clear on shrink toggle (insert after autocomplete-max-visible)\n\t\tconst autocompleteIndex = items.findIndex((item) => item.id === \"autocomplete-max-visible\");\n\t\titems.splice(autocompleteIndex + 1, 0, {\n\t\t\tid: \"clear-on-shrink\",\n\t\t\tlabel: \"Clear on shrink\",\n\t\t\tdescription: \"Clear empty rows when content shrinks (may cause flicker)\",\n\t\t\tcurrentValue: config.clearOnShrink ? \"true\" : \"false\",\n\t\t\tvalues: [\"true\", \"false\"],\n\t\t});\n\n\t\t// Terminal progress toggle (insert after clear-on-shrink)\n\t\tconst clearOnShrinkIndex = items.findIndex((item) => item.id === \"clear-on-shrink\");\n\t\titems.splice(clearOnShrinkIndex + 1, 0, {\n\t\t\tid: \"terminal-progress\",\n\t\t\tlabel: \"Terminal progress\",\n\t\t\tdescription: \"Show OSC 9;4 progress indicators in the terminal tab bar\",\n\t\t\tcurrentValue: config.showTerminalProgress ? \"true\" : \"false\",\n\t\t\tvalues: [\"true\", \"false\"],\n\t\t});\n\n\t\t// Add borders\n\t\tthis.addChild(new DynamicBorder());\n\n\t\tthis.settingsList = new SettingsList(\n\t\t\titems,\n\t\t\t10,\n\t\t\tgetSettingsListTheme(),\n\t\t\t(id, newValue) => {\n\t\t\t\tswitch (id) {\n\t\t\t\t\tcase \"autocompact\":\n\t\t\t\t\t\tcallbacks.onAutoCompactChange(newValue === \"true\");\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase \"show-images\":\n\t\t\t\t\t\tcallbacks.onShowImagesChange(newValue === \"true\");\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase \"image-width-cells\":\n\t\t\t\t\t\tcallbacks.onImageWidthCellsChange(parseInt(newValue, 10));\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase \"auto-resize-images\":\n\t\t\t\t\t\tcallbacks.onAutoResizeImagesChange(newValue === \"true\");\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase \"block-images\":\n\t\t\t\t\t\tcallbacks.onBlockImagesChange(newValue === \"true\");\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase \"skill-commands\":\n\t\t\t\t\t\tcallbacks.onEnableSkillCommandsChange(newValue === \"true\");\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase \"steering-mode\":\n\t\t\t\t\t\tcallbacks.onSteeringModeChange(newValue as \"all\" | \"one-at-a-time\");\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase \"follow-up-mode\":\n\t\t\t\t\t\tcallbacks.onFollowUpModeChange(newValue as \"all\" | \"one-at-a-time\");\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase \"transport\":\n\t\t\t\t\t\tcallbacks.onTransportChange(newValue as Transport);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase \"http-idle-timeout\": {\n\t\t\t\t\t\tconst choice = HTTP_IDLE_TIMEOUT_CHOICES.find((item) => item.label === newValue);\n\t\t\t\t\t\tif (choice) {\n\t\t\t\t\t\t\tcallbacks.onHttpIdleTimeoutMsChange(choice.timeoutMs);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\tcase \"hide-thinking\":\n\t\t\t\t\t\tcallbacks.onHideThinkingBlockChange(newValue === \"true\");\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase \"thinking-collapse\":\n\t\t\t\t\t\tcallbacks.onThinkingCollapseChange(newValue === \"true\");\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase \"cache-miss-notices\":\n\t\t\t\t\t\tcallbacks.onShowCacheMissNoticesChange(newValue === \"true\");\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase \"cache-retention\":\n\t\t\t\t\t\tcallbacks.onCacheRetentionChange(newValue as \"none\" | \"short\" | \"long\");\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase \"quiet-startup\":\n\t\t\t\t\t\tcallbacks.onQuietStartupChange(newValue === \"true\");\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase \"smooth-streaming\":\n\t\t\t\t\t\tcallbacks.onSmoothStreamingChange(newValue === \"true\");\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase \"memory-char-cap\":\n\t\t\t\t\t\tcallbacks.onMemoryCharCapChange(parseInt(newValue, 10));\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase \"search-curator\":\n\t\t\t\t\t\tcallbacks.onSearchCuratorChange(newValue as SearchCuratorSetting);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase \"session-retention-days\":\n\t\t\t\t\t\tcallbacks.onSessionRetentionDaysChange(parseInt(newValue, 10));\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase \"default-project-trust\": {\n\t\t\t\t\t\tconst defaultProjectTrust = DEFAULT_PROJECT_TRUST_BY_LABEL.get(newValue);\n\t\t\t\t\t\tif (defaultProjectTrust) {\n\t\t\t\t\t\t\tcallbacks.onDefaultProjectTrustChange(defaultProjectTrust);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\tcase \"default-permission-mode\":\n\t\t\t\t\t\tcallbacks.onDefaultPermissionModeChange(newValue as DefaultPermissionMode);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase \"double-escape-action\":\n\t\t\t\t\t\tcallbacks.onDoubleEscapeActionChange(newValue as \"fork\" | \"tree\");\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase \"tree-filter-mode\":\n\t\t\t\t\t\tcallbacks.onTreeFilterModeChange(\n\t\t\t\t\t\t\tnewValue as \"default\" | \"no-tools\" | \"user-only\" | \"labeled-only\" | \"all\",\n\t\t\t\t\t\t);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase \"show-hardware-cursor\":\n\t\t\t\t\t\tcallbacks.onShowHardwareCursorChange(newValue === \"true\");\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase \"editor-padding\":\n\t\t\t\t\t\tcallbacks.onEditorPaddingXChange(parseInt(newValue, 10));\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase \"output-padding\":\n\t\t\t\t\t\tcallbacks.onOutputPadChange(newValue === \"0\" ? 0 : 1);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase \"autocomplete-max-visible\":\n\t\t\t\t\t\tcallbacks.onAutocompleteMaxVisibleChange(parseInt(newValue, 10));\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase \"clear-on-shrink\":\n\t\t\t\t\t\tcallbacks.onClearOnShrinkChange(newValue === \"true\");\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase \"terminal-progress\":\n\t\t\t\t\t\tcallbacks.onShowTerminalProgressChange(newValue === \"true\");\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase \"auto-manage-subscriptions\":\n\t\t\t\t\t\tcallbacks.onAutoManageSubscriptionsChange(newValue === \"on\");\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase \"theme\":\n\t\t\t\t\t\tcallbacks.onThemeChange(newValue);\n\t\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t},\n\t\t\tcallbacks.onCancel,\n\t\t\t{ enableSearch: true },\n\t\t);\n\n\t\tthis.addChild(this.settingsList);\n\t\tthis.addChild(new DynamicBorder());\n\t}\n\n\tgetSettingsList(): SettingsList {\n\t\treturn this.settingsList;\n\t}\n}\n"]}
|
|
1
|
+
{"version":3,"file":"settings-selector.d.ts","sourceRoot":"","sources":["../../../../src/modes/interactive/components/settings-selector.ts"],"names":[],"mappings":"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","sourcesContent":["import type { ThinkingLevel } from \"@ashx-j/lunr-agent\";\nimport type { Transport } from \"@ashx-j/lunr-ai\";\nimport {\n\ttype Component,\n\tContainer,\n\tgetCapabilities,\n\tgetKeybindings,\n\tInput,\n\ttype SelectItem,\n\tSelectList,\n\ttype SelectListLayoutOptions,\n\ttype SettingItem,\n\tSettingsList,\n\tSpacer,\n\tText,\n} from \"@ashx-j/lunr-tui\";\nimport { getCustomizeBridge } from \"../../../core/customize.ts\";\nimport { formatHttpIdleTimeoutMs, HTTP_IDLE_TIMEOUT_CHOICES } from \"../../../core/http-dispatcher.ts\";\nimport { MEMORY_CHAR_CAP_DEFAULT, MEMORY_CHAR_CAP_MAX, MEMORY_CHAR_CAP_MIN } from \"../../../core/memory-cap.ts\";\nimport type { SearchCuratorSetting } from \"../../../core/search-curator.ts\";\nimport type {\n\tDefaultPermissionMode,\n\tDefaultProjectTrust,\n\tModelTierName,\n\tModelTiersSettings,\n\tRollbackCapture,\n\tRollbackScope,\n} from \"../../../core/settings-manager.ts\";\nimport {\n\tgetSelectListTheme,\n\tgetSettingsListTheme,\n\tparseAutoThemeSetting,\n\ttype TerminalTheme,\n\ttheme,\n} from \"../theme/theme.ts\";\nimport { DynamicBorder } from \"./dynamic-border.ts\";\nimport { keyDisplayText } from \"./keybinding-hints.ts\";\n\nconst SETTINGS_SUBMENU_SELECT_LIST_LAYOUT: SelectListLayoutOptions = {\n\tminPrimaryColumnWidth: 12,\n\tmaxPrimaryColumnWidth: 32,\n};\n\nconst THINKING_DESCRIPTIONS: Record<ThinkingLevel, string> = {\n\toff: \"No reasoning\",\n\tminimal: \"Very brief reasoning\",\n\tlow: \"Light reasoning\",\n\tmedium: \"Moderate reasoning\",\n\thigh: \"Deep reasoning\",\n\txhigh: \"Extra-high reasoning\",\n\tmax: \"Maximum reasoning\",\n};\n\nconst DEFAULT_PROJECT_TRUST_LABELS: Record<DefaultProjectTrust, string> = {\n\task: \"Ask\",\n\talways: \"Always trust\",\n\tnever: \"Never trust\",\n};\n\nconst DEFAULT_PROJECT_TRUST_BY_LABEL = new Map(\n\tObject.entries(DEFAULT_PROJECT_TRUST_LABELS).map(([value, label]) => [label, value as DefaultProjectTrust]),\n);\n\nexport interface SettingsConfig {\n\tautoCompact: boolean;\n\tshowImages: boolean;\n\timageWidthCells: number;\n\tautoResizeImages: boolean;\n\tblockImages: boolean;\n\tenableSkillCommands: boolean;\n\tsteeringMode: \"all\" | \"one-at-a-time\";\n\tfollowUpMode: \"all\" | \"one-at-a-time\";\n\ttransport: Transport;\n\thttpIdleTimeoutMs: number;\n\tthinkingLevel: ThinkingLevel;\n\tavailableThinkingLevels: ThinkingLevel[];\n\tcurrentTheme: string;\n\tterminalTheme: TerminalTheme;\n\tavailableThemes: string[];\n\thideThinkingBlock: boolean;\n\tthinkingCollapse: boolean;\n\tshowCacheMissNotices: boolean;\n\t/** Display value; unset settings render as \"short\". */\n\tcacheRetention: \"none\" | \"short\" | \"long\";\n\tdoubleEscapeAction: \"fork\" | \"tree\" | \"none\";\n\ttreeFilterMode: \"default\" | \"no-tools\" | \"user-only\" | \"labeled-only\" | \"all\";\n\tshowHardwareCursor: boolean;\n\teditorPaddingX: number;\n\toutputPad: 0 | 1;\n\tautocompleteMaxVisible: number;\n\tquietStartup: boolean;\n\tsmoothStreaming: boolean;\n\tsessionRetentionDays: number;\n\tdefaultProjectTrust: DefaultProjectTrust;\n\tclearOnShrink: boolean;\n\tshowTerminalProgress: boolean;\n\tmodelTiers: ModelTiersSettings;\n\tmemoryCharCap: number;\n\t/** undefined when pi-web-access is not loaded (curator bridge absent). */\n\tsearchCurator: SearchCuratorSetting | undefined;\n\t// lunr: TUI customize settings\n\tgutterRail: boolean;\n\tpromptSymbol: boolean;\n\tfooterMcp: boolean;\n\tfooterLsp: boolean;\n\tfooterContext: boolean;\n\tfooterTokens: boolean;\n\tfooterStatuses: boolean;\n\t// lunr: permission mode default\n\tdefaultPermissionMode: DefaultPermissionMode;\n\t// lunr: rollback settings\n\trollbackEnabled: boolean;\n\trollbackTurns: number;\n\trollbackCapture: RollbackCapture;\n\trollbackScope: RollbackScope;\n\t// lunr: multi-subscription pools\n\tautoManageSubscriptions: boolean;\n\tsubscriptionCount: number;\n}\n\nexport interface SettingsCallbacks {\n\tonAutoCompactChange: (enabled: boolean) => void;\n\tonShowImagesChange: (enabled: boolean) => void;\n\tonImageWidthCellsChange: (width: number) => void;\n\tonAutoResizeImagesChange: (enabled: boolean) => void;\n\tonBlockImagesChange: (blocked: boolean) => void;\n\tonEnableSkillCommandsChange: (enabled: boolean) => void;\n\tonSteeringModeChange: (mode: \"all\" | \"one-at-a-time\") => void;\n\tonFollowUpModeChange: (mode: \"all\" | \"one-at-a-time\") => void;\n\tonTransportChange: (transport: Transport) => void;\n\tonHttpIdleTimeoutMsChange: (timeoutMs: number) => void;\n\tonThinkingLevelChange: (level: ThinkingLevel) => void;\n\tonThemeChange: (theme: string) => void;\n\tonThemePreview?: (theme: string) => void;\n\tonHideThinkingBlockChange: (hidden: boolean) => void;\n\tonThinkingCollapseChange: (collapse: boolean) => void;\n\tonShowCacheMissNoticesChange: (shown: boolean) => void;\n\tonCacheRetentionChange: (retention: \"none\" | \"short\" | \"long\") => void;\n\tonDoubleEscapeActionChange: (action: \"fork\" | \"tree\" | \"none\") => void;\n\tonTreeFilterModeChange: (mode: \"default\" | \"no-tools\" | \"user-only\" | \"labeled-only\" | \"all\") => void;\n\tonShowHardwareCursorChange: (enabled: boolean) => void;\n\tonEditorPaddingXChange: (padding: number) => void;\n\tonOutputPadChange: (padding: 0 | 1) => void;\n\tonAutocompleteMaxVisibleChange: (maxVisible: number) => void;\n\tonQuietStartupChange: (enabled: boolean) => void;\n\tonSmoothStreamingChange: (enabled: boolean) => void;\n\tonSessionRetentionDaysChange: (days: number) => void;\n\tonDefaultProjectTrustChange: (defaultProjectTrust: DefaultProjectTrust) => void;\n\tonClearOnShrinkChange: (enabled: boolean) => void;\n\tonShowTerminalProgressChange: (enabled: boolean) => void;\n\tonModelTiersEnabledChange: (enabled: boolean) => void;\n\tonModelTierModelChange: (tier: ModelTierName, model: string) => void;\n\tonMemoryCharCapChange: (cap: number) => void;\n\tonSearchCuratorChange: (setting: SearchCuratorSetting) => void;\n\t// lunr: TUI customize callbacks\n\tonGutterRailChange: (enabled: boolean) => void;\n\tonPromptSymbolChange: (enabled: boolean) => void;\n\tonFooterMcpChange: (enabled: boolean) => void;\n\tonFooterLspChange: (enabled: boolean) => void;\n\tonFooterContextChange: (enabled: boolean) => void;\n\tonFooterTokensChange: (enabled: boolean) => void;\n\tonFooterStatusesChange: (enabled: boolean) => void;\n\t// lunr: permission mode default\n\tonDefaultPermissionModeChange: (mode: DefaultPermissionMode) => void;\n\t// lunr: rollback callbacks\n\tonRollbackEnabledChange: (enabled: boolean) => void;\n\tonRollbackTurnsChange: (turns: number) => void;\n\tonRollbackCaptureChange: (mode: RollbackCapture) => void;\n\tonRollbackScopeChange: (scope: RollbackScope) => void;\n\tisRollbackSessionForceEnabled: () => boolean;\n\t// lunr: multi-subscription pool callbacks\n\tonAutoManageSubscriptionsChange: (enabled: boolean) => void;\n\t/** lunr: live pool accessors; when absent the Subscriptions row is hidden. */\n\tsubscriptions?: SubscriptionCallbacks;\n\t/** Open the model picker for a tier; done() receives the selected \"provider/model\" string, or no value on cancel. */\n\tcreateModelTierPicker: (\n\t\ttier: ModelTierName,\n\t\tcurrentModel: string | undefined,\n\t\tdone: (selectedValue?: string) => void,\n\t) => Component;\n\tonCancel: () => void;\n}\n\nconst MODEL_TIER_ROWS: { tier: ModelTierName; label: string; description: string }[] = [\n\t{\n\t\ttier: \"light\",\n\t\tlabel: \"Light tier model\",\n\t\tdescription: \"Cheap/fast model for simple subagent tasks (lookups, formatting)\",\n\t},\n\t{\n\t\ttier: \"standard\",\n\t\tlabel: \"Standard tier model\",\n\t\tdescription: \"Mid-tier model for typical coding subagent tasks\",\n\t},\n\t{\n\t\ttier: \"heavy\",\n\t\tlabel: \"Heavy tier model\",\n\t\tdescription: \"Strongest model for deep reasoning and complex debugging subagents\",\n\t},\n];\n\n/**\n * Submenu for the 3-tier subagent model routing (light/standard/heavy).\n * Row 1 toggles tier mode; rows 2-4 open a model picker per tier.\n */\nclass ModelTiersSubmenu extends Container {\n\tprivate settingsList: SettingsList;\n\tprivate state: { enabled: boolean; light?: string; standard?: string; heavy?: string };\n\n\tconstructor(\n\t\tcurrentValue: string | undefined,\n\t\tmodelTiers: ModelTiersSettings,\n\t\tcallbacks: SettingsCallbacks,\n\t\tdone: (selectedValue?: string) => void,\n\t) {\n\t\tsuper();\n\n\t\tthis.state = {\n\t\t\tenabled: currentValue === \"on\" || (currentValue === undefined && (modelTiers.enabled ?? false)),\n\t\t\tlight: modelTiers.light,\n\t\t\tstandard: modelTiers.standard,\n\t\t\theavy: modelTiers.heavy,\n\t\t};\n\n\t\tconst items: SettingItem[] = [\n\t\t\t{\n\t\t\t\tid: \"enabled\",\n\t\t\t\tlabel: \"Enable model tiers\",\n\t\t\t\tdescription:\n\t\t\t\t\t\"Route subagents to per-tier models. An explicit model choice overrides the tier; tiers without a model inherit the parent model.\",\n\t\t\t\tcurrentValue: this.state.enabled ? \"on\" : \"off\",\n\t\t\t\tvalues: [\"on\", \"off\"],\n\t\t\t},\n\t\t\t...MODEL_TIER_ROWS.map((row): SettingItem => {\n\t\t\t\tconst tier = row.tier;\n\t\t\t\treturn {\n\t\t\t\t\tid: tier,\n\t\t\t\t\tlabel: row.label,\n\t\t\t\t\tdescription: row.description,\n\t\t\t\t\tcurrentValue: this.state[tier] ?? \"not set\",\n\t\t\t\t\tdisabled: () => !this.state.enabled,\n\t\t\t\t\tsubmenu: (_currentValue, done) => callbacks.createModelTierPicker(tier, this.state[tier], done),\n\t\t\t\t};\n\t\t\t}),\n\t\t];\n\n\t\tthis.settingsList = new SettingsList(\n\t\t\titems,\n\t\t\tMath.min(items.length, 10),\n\t\t\tgetSettingsListTheme(),\n\t\t\t(id, newValue) => {\n\t\t\t\tif (id === \"enabled\") {\n\t\t\t\t\tthis.state.enabled = newValue === \"on\";\n\t\t\t\t\tcallbacks.onModelTiersEnabledChange(this.state.enabled);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tconst tier = id as ModelTierName;\n\t\t\t\tthis.state[tier] = newValue;\n\t\t\t\tcallbacks.onModelTierModelChange(tier, newValue);\n\t\t\t},\n\t\t\t() => done(this.state.enabled ? \"on\" : \"off\"),\n\t\t);\n\n\t\tthis.addChild(this.settingsList);\n\t}\n\n\thandleInput(data: string): void {\n\t\tthis.settingsList.handleInput(data);\n\t}\n}\n\n/**\n * Numeric input submenu for the simple-pi-memory character cap.\n * Enter validates and applies via done(newValue); Esc cancels.\n */\nclass MemoryCharCapSubmenu extends Container {\n\tprivate input: Input;\n\tprivate errorText: Text;\n\n\tconstructor(currentValue: string, done: (selectedValue?: string) => void) {\n\t\tsuper();\n\n\t\tthis.addChild(new Text(theme.bold(theme.fg(\"accent\", \"Memory Character Cap\")), 0, 0));\n\t\tthis.addChild(new Spacer(1));\n\t\tthis.addChild(\n\t\t\tnew Text(\n\t\t\t\ttheme.fg(\n\t\t\t\t\t\"muted\",\n\t\t\t\t\t`Max characters in the memory file (${MEMORY_CHAR_CAP_MIN}-${MEMORY_CHAR_CAP_MAX}, default ${MEMORY_CHAR_CAP_DEFAULT}).`,\n\t\t\t\t),\n\t\t\t\t0,\n\t\t\t\t0,\n\t\t\t),\n\t\t);\n\t\tthis.addChild(new Spacer(1));\n\n\t\tthis.input = new Input();\n\t\tthis.input.setValue(currentValue);\n\t\tthis.input.onSubmit = (value) => {\n\t\t\tconst n = Number(value.trim());\n\t\t\tif (!Number.isInteger(n) || n < MEMORY_CHAR_CAP_MIN || n > MEMORY_CHAR_CAP_MAX) {\n\t\t\t\tthis.errorText.setText(\n\t\t\t\t\ttheme.fg(\"error\", ` Enter an integer between ${MEMORY_CHAR_CAP_MIN} and ${MEMORY_CHAR_CAP_MAX}.`),\n\t\t\t\t);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tdone(String(n));\n\t\t};\n\t\tthis.input.onEscape = () => done();\n\t\tthis.addChild(this.input);\n\n\t\tthis.errorText = new Text(\"\", 0, 0);\n\t\tthis.addChild(this.errorText);\n\t\tthis.addChild(new Text(theme.fg(\"dim\", \" Enter to save · Esc to cancel\"), 0, 0));\n\t}\n\n\thandleInput(data: string): void {\n\t\tthis.input.handleInput(data);\n\t}\n}\n\nconst SEARCH_CURATOR_VALUES: SearchCuratorSetting[] = [\"off\", \"on\", \"auto-summary\"];\n\n// lunr: Customize submenu — toggles for the lunR TUI customize settings.\nclass CustomizeSubmenu extends Container {\n\tprivate settingsList: SettingsList;\n\n\tconstructor(_config: SettingsConfig, callbacks: SettingsCallbacks, done: (selectedValue?: string) => void) {\n\t\tsuper();\n\n\t\t// Read live values from the customize bridge so re-entering the submenu within\n\t\t// one /settings session reflects toggles made earlier in that session.\n\t\tconst bridge = getCustomizeBridge();\n\t\tconst items: SettingItem[] = [\n\t\t\t{\n\t\t\t\tid: \"gutter-rail\",\n\t\t\t\tlabel: \"Gutter rail\",\n\t\t\t\tdescription: \"Render a thin left │ rail spanning each turn, closing with ╰.\",\n\t\t\t\tcurrentValue: (bridge?.getGutterRail() ?? true) ? \"on\" : \"off\",\n\t\t\t\tvalues: [\"on\", \"off\"],\n\t\t\t},\n\t\t\t{\n\t\t\t\tid: \"prompt-symbol\",\n\t\t\t\tlabel: \"Prompt symbol\",\n\t\t\t\tdescription: \"Show the ☾ › prompt glyph on the editor's first line.\",\n\t\t\t\tcurrentValue: (bridge?.getPromptSymbol() ?? true) ? \"on\" : \"off\",\n\t\t\t\tvalues: [\"on\", \"off\"],\n\t\t\t},\n\t\t\t{\n\t\t\t\tid: \"footer-mcp\",\n\t\t\t\tlabel: \"Footer: MCP status\",\n\t\t\t\tdescription: \"Show the MCP server status segment in the footer stats line.\",\n\t\t\t\tcurrentValue: (bridge?.getFooterMcp() ?? true) ? \"on\" : \"off\",\n\t\t\t\tvalues: [\"on\", \"off\"],\n\t\t\t},\n\t\t\t{\n\t\t\t\tid: \"footer-lsp\",\n\t\t\t\tlabel: \"Footer: LSP status\",\n\t\t\t\tdescription: \"Show the LSP status segment in the footer stats line.\",\n\t\t\t\tcurrentValue: (bridge?.getFooterLsp() ?? false) ? \"on\" : \"off\",\n\t\t\t\tvalues: [\"on\", \"off\"],\n\t\t\t},\n\t\t\t{\n\t\t\t\tid: \"footer-context\",\n\t\t\t\tlabel: \"Footer: context meter\",\n\t\t\t\tdescription: \"Show the context-usage pct/window segment in the footer stats line.\",\n\t\t\t\tcurrentValue: (bridge?.getFooterContext() ?? true) ? \"on\" : \"off\",\n\t\t\t\tvalues: [\"on\", \"off\"],\n\t\t\t},\n\t\t\t{\n\t\t\t\tid: \"footer-tokens\",\n\t\t\t\tlabel: \"Footer: token counter\",\n\t\t\t\tdescription: \"Show the ↑in ↓out token totals segment in the footer stats line.\",\n\t\t\t\tcurrentValue: (bridge?.getFooterTokens() ?? true) ? \"on\" : \"off\",\n\t\t\t\tvalues: [\"on\", \"off\"],\n\t\t\t},\n\t\t\t{\n\t\t\t\tid: \"footer-statuses\",\n\t\t\t\tlabel: \"Footer: feature statuses\",\n\t\t\t\tdescription: \"Show the plan/goal/swarm/research/tps status segments in the footer stats line.\",\n\t\t\t\tcurrentValue: (bridge?.getFooterStatuses() ?? true) ? \"on\" : \"off\",\n\t\t\t\tvalues: [\"on\", \"off\"],\n\t\t\t},\n\t\t];\n\n\t\tthis.settingsList = new SettingsList(\n\t\t\titems,\n\t\t\tMath.min(items.length, 10),\n\t\t\tgetSettingsListTheme(),\n\t\t\t(id, newValue) => {\n\t\t\t\tswitch (id) {\n\t\t\t\t\tcase \"gutter-rail\":\n\t\t\t\t\t\tcallbacks.onGutterRailChange(newValue === \"on\");\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase \"prompt-symbol\":\n\t\t\t\t\t\tcallbacks.onPromptSymbolChange(newValue === \"on\");\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase \"footer-mcp\":\n\t\t\t\t\t\tcallbacks.onFooterMcpChange(newValue === \"on\");\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase \"footer-lsp\":\n\t\t\t\t\t\tcallbacks.onFooterLspChange(newValue === \"on\");\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase \"footer-context\":\n\t\t\t\t\t\tcallbacks.onFooterContextChange(newValue === \"on\");\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase \"footer-tokens\":\n\t\t\t\t\t\tcallbacks.onFooterTokensChange(newValue === \"on\");\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase \"footer-statuses\":\n\t\t\t\t\t\tcallbacks.onFooterStatusesChange(newValue === \"on\");\n\t\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t},\n\t\t\t() => done(),\n\t\t);\n\n\t\tthis.addChild(this.settingsList);\n\t}\n\n\thandleInput(data: string): void {\n\t\tthis.settingsList.handleInput(data);\n\t}\n}\n\n// lunr: Rollback submenu — enable, turns, capture mode, scope.\nclass RollbackSubmenu extends Container {\n\tprivate settingsList: SettingsList;\n\tprivate enabled: boolean;\n\n\tconstructor(\n\t\tcurrentValue: string | undefined,\n\t\tconfig: SettingsConfig,\n\t\tcallbacks: SettingsCallbacks,\n\t\tsessionForceEnabled: boolean,\n\t\tdone: (selectedValue?: string) => void,\n\t) {\n\t\tsuper();\n\n\t\tthis.enabled = currentValue === \"on\" || (currentValue === undefined && config.rollbackEnabled);\n\n\t\tconst items: SettingItem[] = [\n\t\t\t{\n\t\t\t\tid: \"rollback-enabled\",\n\t\t\t\tlabel: \"Rollback enabled\",\n\t\t\t\tdescription:\n\t\t\t\t\t\"Copy files before edits so /rollback can restore them. Uses extra disk + processing.\" +\n\t\t\t\t\t(sessionForceEnabled ? \" (forced on by auto mode)\" : \"\"),\n\t\t\t\tcurrentValue: this.enabled ? \"on\" : \"off\",\n\t\t\t\tvalues: [\"on\", \"off\"],\n\t\t\t\tdisabled: () => sessionForceEnabled,\n\t\t\t},\n\t\t\t{\n\t\t\t\tid: \"rollback-turns\",\n\t\t\t\tlabel: \"Rollback turns\",\n\t\t\t\tdescription: `How many turns of snapshots to retain (1-20, default 2).`,\n\t\t\t\tcurrentValue: String(config.rollbackTurns),\n\t\t\t\tdisabled: () => !this.enabled,\n\t\t\t\tsubmenu: (currentValue, submenuDone) => new RollbackTurnsSubmenu(currentValue, submenuDone),\n\t\t\t},\n\t\t\t{\n\t\t\t\tid: \"rollback-capture\",\n\t\t\t\tlabel: \"Capture mode\",\n\t\t\t\tdescription:\n\t\t\t\t\t\"How snapshots are taken: copies = restore edited files + delete tool-created files, hybrid = also delete files created outside tools (tree scope), shadow-git = hidden git repo (needs git).\",\n\t\t\t\tcurrentValue: config.rollbackCapture,\n\t\t\t\tdisabled: () => !this.enabled,\n\t\t\t\tsubmenu: (currentValue, submenuDone) =>\n\t\t\t\t\tnew SelectSubmenu(\n\t\t\t\t\t\t\"Rollback Capture Mode\",\n\t\t\t\t\t\t\"How file snapshots are captured before edits.\",\n\t\t\t\t\t\t[\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tvalue: \"copies\",\n\t\t\t\t\t\t\t\tlabel: \"copies\",\n\t\t\t\t\t\t\t\tdescription: \"fast; restores edits, deletes tool-created files\",\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tvalue: \"hybrid\",\n\t\t\t\t\t\t\t\tlabel: \"hybrid\",\n\t\t\t\t\t\t\t\tdescription: \"also deletes files created outside tools (tree scope)\",\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tvalue: \"shadow-git\",\n\t\t\t\t\t\t\t\tlabel: \"shadow-git\",\n\t\t\t\t\t\t\t\tdescription: \"needs git, hidden repo — deferred, falls back to copies\",\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t],\n\t\t\t\t\t\tcurrentValue,\n\t\t\t\t\t\t(value) => {\n\t\t\t\t\t\t\tcallbacks.onRollbackCaptureChange(value as RollbackCapture);\n\t\t\t\t\t\t\tsubmenuDone(value);\n\t\t\t\t\t\t},\n\t\t\t\t\t\t() => submenuDone(),\n\t\t\t\t\t),\n\t\t\t},\n\t\t\t{\n\t\t\t\tid: \"rollback-scope\",\n\t\t\t\tlabel: \"Rollback scope\",\n\t\t\t\tdescription:\n\t\t\t\t\t\"tools = only edit/write changes; tree = also catches bash side-effects via git status (slower on large repos).\",\n\t\t\t\tcurrentValue: config.rollbackScope,\n\t\t\t\tdisabled: () => !this.enabled,\n\t\t\t\tsubmenu: (currentValue, submenuDone) =>\n\t\t\t\t\tnew SelectSubmenu(\n\t\t\t\t\t\t\"Rollback Scope\",\n\t\t\t\t\t\t\"What file changes to snapshot.\",\n\t\t\t\t\t\t[\n\t\t\t\t\t\t\t{ value: \"tools\", label: \"tools\", description: \"only edit/write tool changes\" },\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tvalue: \"tree\",\n\t\t\t\t\t\t\t\tlabel: \"tree\",\n\t\t\t\t\t\t\t\tdescription: \"also catches bash side-effects; slower on large repos\",\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t],\n\t\t\t\t\t\tcurrentValue,\n\t\t\t\t\t\t(value) => {\n\t\t\t\t\t\t\tcallbacks.onRollbackScopeChange(value as RollbackScope);\n\t\t\t\t\t\t\tsubmenuDone(value);\n\t\t\t\t\t\t},\n\t\t\t\t\t\t() => submenuDone(),\n\t\t\t\t\t),\n\t\t\t},\n\t\t];\n\n\t\tthis.settingsList = new SettingsList(\n\t\t\titems,\n\t\t\tMath.min(items.length, 10),\n\t\t\tgetSettingsListTheme(),\n\t\t\t(id, newValue) => {\n\t\t\t\tswitch (id) {\n\t\t\t\t\tcase \"rollback-enabled\":\n\t\t\t\t\t\tthis.enabled = newValue === \"on\";\n\t\t\t\t\t\tcallbacks.onRollbackEnabledChange(this.enabled);\n\t\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t},\n\t\t\t() => done(this.enabled ? \"on\" : \"off\"),\n\t\t);\n\t\tthis.addChild(new Text(theme.bold(theme.fg(\"accent\", \"Rollback\")), 0, 0));\n\t\tthis.addChild(new Spacer(1));\n\t\tthis.addChild(this.settingsList);\n\t\tthis.addChild(new Text(theme.fg(\"dim\", \" Esc to go back\"), 0, 0));\n\t}\n\n\thandleInput(data: string): void {\n\t\tthis.settingsList.handleInput(data);\n\t}\n}\n\nclass RollbackTurnsSubmenu extends Container {\n\tprivate input: Input;\n\tprivate errorText: Text;\n\n\tconstructor(currentValue: string, done: (selectedValue?: string) => void) {\n\t\tsuper();\n\t\tthis.addChild(new Text(theme.bold(theme.fg(\"accent\", \"Rollback Turns\")), 0, 0));\n\t\tthis.addChild(new Spacer(1));\n\t\tthis.addChild(new Text(theme.fg(\"muted\", \"How many turns of snapshots to retain (1-20, default 2).\"), 0, 0));\n\t\tthis.addChild(new Spacer(1));\n\t\tthis.input = new Input();\n\t\tthis.input.setValue(currentValue);\n\t\tthis.input.onSubmit = (value) => {\n\t\t\tconst n = Number(value.trim());\n\t\t\tif (!Number.isInteger(n) || n < 1 || n > 20) {\n\t\t\t\tthis.errorText.setText(theme.fg(\"error\", \" Enter an integer between 1 and 20.\"));\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tdone(String(n));\n\t\t};\n\t\tthis.input.onEscape = () => done();\n\t\tthis.addChild(this.input);\n\t\tthis.errorText = new Text(\"\", 0, 0);\n\t\tthis.addChild(this.errorText);\n\t\tthis.addChild(new Text(theme.fg(\"dim\", \" Enter to save · Esc to cancel\"), 0, 0));\n\t}\n\n\thandleInput(data: string): void {\n\t\tthis.input.handleInput(data);\n\t}\n}\n\n// lunr: one subscription pool entry, passed as plain data so render paths stay synchronous.\nexport interface SubscriptionRowInfo {\n\tproviderId: string;\n\tproviderName: string;\n\tid: string;\n\tname: string;\n\tactive: boolean;\n\texhaustedUntil?: number;\n}\n\n// lunr: live accessors for the subscription pool, wired by interactive-mode.\nexport interface SubscriptionCallbacks {\n\tlist: () => Promise<SubscriptionRowInfo[]>;\n\tsetActive: (providerId: string, id: string) => Promise<void>;\n\trename: (providerId: string, id: string, name: string) => Promise<void>;\n\tclearExhaustion: (providerId: string, id: string) => Promise<void>;\n\tremove: (providerId: string, id: string) => Promise<void>;\n\tautoManage: () => boolean;\n\trequestRender: () => void;\n}\n\n// lunr: format an exhaustion timestamp — local HH:mm when it ends today, else a short date.\nexport function formatSubscriptionExhaustedUntil(exhaustedUntil: number, now: number = Date.now()): string {\n\tconst date = new Date(exhaustedUntil);\n\tif (date.toDateString() === new Date(now).toDateString()) {\n\t\treturn date.toTimeString().slice(0, 5);\n\t}\n\treturn date.toLocaleDateString(undefined, { month: \"short\", day: \"numeric\" });\n}\n\n// lunr: free-text rename prompt for a subscription key (same Input pattern as MemoryCharCapSubmenu).\nclass SubscriptionRenameSubmenu extends Container {\n\tprivate input: Input;\n\tprivate errorText: Text;\n\n\tconstructor(currentName: string, done: (selectedValue?: string) => void) {\n\t\tsuper();\n\t\tthis.addChild(new Text(theme.bold(theme.fg(\"accent\", \"Rename Subscription\")), 0, 0));\n\t\tthis.addChild(new Spacer(1));\n\t\tthis.addChild(new Text(theme.fg(\"muted\", \"Display name for this API key.\"), 0, 0));\n\t\tthis.addChild(new Spacer(1));\n\t\tthis.input = new Input();\n\t\tthis.input.setValue(currentName);\n\t\tthis.input.onSubmit = (value) => {\n\t\t\tconst name = value.trim();\n\t\t\tif (!name) {\n\t\t\t\tthis.errorText.setText(theme.fg(\"error\", \" Enter a non-empty name.\"));\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tdone(name);\n\t\t};\n\t\tthis.input.onEscape = () => done();\n\t\tthis.addChild(this.input);\n\t\tthis.errorText = new Text(\"\", 0, 0);\n\t\tthis.addChild(this.errorText);\n\t\tthis.addChild(new Text(theme.fg(\"dim\", \" Enter to save · Esc to cancel\"), 0, 0));\n\t}\n\n\thandleInput(data: string): void {\n\t\tthis.input.handleInput(data);\n\t}\n}\n\n// lunr: per-subscription actions — set active, rename, clear exhaustion, remove.\n// onChanged asks the parent SubscriptionsSubmenu to reload its rows from the live manager.\nclass SubscriptionActionSubmenu extends Container {\n\tprivate settingsList: SettingsList;\n\n\tconstructor(\n\t\trow: SubscriptionRowInfo,\n\t\tsubs: SubscriptionCallbacks,\n\t\tdone: (selectedValue?: string) => void,\n\t\tonChanged: () => void,\n\t) {\n\t\tsuper();\n\n\t\tconst items: SettingItem[] = [\n\t\t\t{\n\t\t\t\tid: \"set-active\",\n\t\t\t\tlabel: \"Set active\",\n\t\t\t\tdescription: subs.autoManage()\n\t\t\t\t\t? \"Manual switching is disabled while Auto-manage subscriptions is on.\"\n\t\t\t\t\t: \"Use this key for new requests.\",\n\t\t\t\tcurrentValue: row.active ? \"already active\" : \"activate\",\n\t\t\t\tvalues: [\"activate\"],\n\t\t\t\tdisabled: () => subs.autoManage() || row.active,\n\t\t\t},\n\t\t\t{\n\t\t\t\tid: \"rename\",\n\t\t\t\tlabel: \"Rename\",\n\t\t\t\tdescription: \"Display name for this key.\",\n\t\t\t\tcurrentValue: row.name,\n\t\t\t\tsubmenu: (currentValue, renameDone) =>\n\t\t\t\t\tnew SubscriptionRenameSubmenu(currentValue, (name) => {\n\t\t\t\t\t\tif (name === undefined) {\n\t\t\t\t\t\t\trenameDone();\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tvoid subs.rename(row.providerId, row.id, name).then(() => {\n\t\t\t\t\t\t\trenameDone(name);\n\t\t\t\t\t\t\tdone();\n\t\t\t\t\t\t\tonChanged();\n\t\t\t\t\t\t});\n\t\t\t\t\t}),\n\t\t\t},\n\t\t\t{\n\t\t\t\tid: \"clear-exhaustion\",\n\t\t\t\tlabel: \"Clear exhausted flag\",\n\t\t\t\tdescription:\n\t\t\t\t\trow.exhaustedUntil !== undefined\n\t\t\t\t\t\t? `Marked exhausted until ${formatSubscriptionExhaustedUntil(row.exhaustedUntil)}.`\n\t\t\t\t\t\t: \"Only available for keys marked exhausted.\",\n\t\t\t\tcurrentValue: \"clear\",\n\t\t\t\tvalues: [\"clear\"],\n\t\t\t\tdisabled: () => row.exhaustedUntil === undefined,\n\t\t\t},\n\t\t\t{\n\t\t\t\tid: \"remove\",\n\t\t\t\tlabel: \"Remove\",\n\t\t\t\tdescription: \"Delete this key. Removing the provider's last key logs it out completely.\",\n\t\t\t\tcurrentValue: \"remove…\",\n\t\t\t\tsubmenu: (_currentValue, confirmDone) =>\n\t\t\t\t\tnew SelectSubmenu(\n\t\t\t\t\t\t\"Remove Subscription\",\n\t\t\t\t\t\t`Remove \"${row.name}\" (${row.providerName})? Removing the provider's last key logs it out.`,\n\t\t\t\t\t\t[\n\t\t\t\t\t\t\t{ value: \"cancel\", label: \"Cancel\" },\n\t\t\t\t\t\t\t{ value: \"remove\", label: \"Remove key\" },\n\t\t\t\t\t\t],\n\t\t\t\t\t\t\"cancel\",\n\t\t\t\t\t\t(value) => {\n\t\t\t\t\t\t\tif (value !== \"remove\") {\n\t\t\t\t\t\t\t\tconfirmDone();\n\t\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tvoid subs.remove(row.providerId, row.id).then(() => {\n\t\t\t\t\t\t\t\tconfirmDone();\n\t\t\t\t\t\t\t\tdone();\n\t\t\t\t\t\t\t\tonChanged();\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t},\n\t\t\t\t\t\t() => confirmDone(),\n\t\t\t\t\t),\n\t\t\t},\n\t\t];\n\n\t\tthis.settingsList = new SettingsList(\n\t\t\titems,\n\t\t\tMath.min(items.length, 10),\n\t\t\tgetSettingsListTheme(),\n\t\t\t(id) => {\n\t\t\t\tif (id === \"set-active\") {\n\t\t\t\t\tvoid subs.setActive(row.providerId, row.id).then(() => {\n\t\t\t\t\t\tdone();\n\t\t\t\t\t\tonChanged();\n\t\t\t\t\t});\n\t\t\t\t} else if (id === \"clear-exhaustion\") {\n\t\t\t\t\tvoid subs.clearExhaustion(row.providerId, row.id).then(() => {\n\t\t\t\t\t\tdone();\n\t\t\t\t\t\tonChanged();\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t},\n\t\t\t() => done(),\n\t\t);\n\n\t\tthis.addChild(new Text(theme.bold(theme.fg(\"accent\", `${row.providerName} — ${row.name}`)), 0, 0));\n\t\tthis.addChild(new Spacer(1));\n\t\tthis.addChild(this.settingsList);\n\t}\n\n\thandleInput(data: string): void {\n\t\tthis.settingsList.handleInput(data);\n\t}\n}\n\n// lunr: Subscriptions submenu — one row per pooled API key across all providers.\n// Rows reload from the live manager on open and after every mutation.\nclass SubscriptionsSubmenu extends Container {\n\tprivate readonly subs: SubscriptionCallbacks;\n\tprivate readonly done: (selectedValue?: string) => void;\n\tprivate contentContainer: Container;\n\tprivate settingsList: SettingsList | undefined;\n\tprivate closed = false;\n\n\tconstructor(subs: SubscriptionCallbacks, done: (selectedValue?: string) => void) {\n\t\tsuper();\n\t\tthis.subs = subs;\n\t\tthis.done = done;\n\t\tthis.addChild(new Text(theme.bold(theme.fg(\"accent\", \"Subscriptions\")), 0, 0));\n\t\tthis.addChild(new Spacer(1));\n\t\tthis.contentContainer = new Container();\n\t\tthis.addChild(this.contentContainer);\n\t\tthis.contentContainer.addChild(new Text(theme.fg(\"muted\", \" Loading…\"), 0, 0));\n\t\tvoid this.reload();\n\t}\n\n\tprivate async reload(): Promise<void> {\n\t\tlet rows: SubscriptionRowInfo[] = [];\n\t\ttry {\n\t\t\trows = await this.subs.list();\n\t\t} catch {\n\t\t\trows = [];\n\t\t}\n\t\tif (this.closed) return;\n\n\t\tthis.contentContainer.clear();\n\t\tthis.settingsList = undefined;\n\n\t\tif (rows.length === 0) {\n\t\t\tthis.contentContainer.addChild(new Text(theme.fg(\"muted\", \" No stored API key subscriptions.\"), 0, 0));\n\t\t\tthis.contentContainer.addChild(new Text(theme.fg(\"dim\", \" Esc to go back\"), 0, 0));\n\t\t\tthis.subs.requestRender();\n\t\t\treturn;\n\t\t}\n\n\t\tconst items: SettingItem[] = rows.map((row) => ({\n\t\t\tid: `${row.providerId}/${row.id}`,\n\t\t\tlabel: `${row.providerName} — ${row.name}`,\n\t\t\tdescription:\n\t\t\t\t`${row.providerId} API key` +\n\t\t\t\t(row.exhaustedUntil !== undefined\n\t\t\t\t\t? ` · exhausted until ${formatSubscriptionExhaustedUntil(row.exhaustedUntil)}`\n\t\t\t\t\t: \"\"),\n\t\t\tcurrentValue: row.active ? \"active\" : row.exhaustedUntil !== undefined ? \"exhausted\" : \"\",\n\t\t\tsubmenu: (_currentValue, subDone) =>\n\t\t\t\tnew SubscriptionActionSubmenu(row, this.subs, subDone, () => void this.reload()),\n\t\t}));\n\n\t\tthis.settingsList = new SettingsList(\n\t\t\titems,\n\t\t\tMath.min(items.length, 10),\n\t\t\tgetSettingsListTheme(),\n\t\t\t() => {},\n\t\t\t// Closing reports the current count so the parent row label stays fresh.\n\t\t\t() => this.done(`${rows.length} key${rows.length === 1 ? \"\" : \"s\"}`),\n\t\t);\n\t\tthis.contentContainer.addChild(this.settingsList);\n\t\tthis.subs.requestRender();\n\t}\n\n\thandleInput(data: string): void {\n\t\tif (this.settingsList) {\n\t\t\tthis.settingsList.handleInput(data);\n\t\t\treturn;\n\t\t}\n\t\t// Loading/empty state: only Esc goes back.\n\t\tif (getKeybindings().matches(data, \"tui.select.cancel\")) {\n\t\t\tthis.closed = true;\n\t\t\tthis.done();\n\t\t}\n\t}\n}\n\nclass SelectSubmenu extends Container {\n\tprivate selectList: SelectList;\n\n\tconstructor(\n\t\ttitle: string,\n\t\tdescription: string,\n\t\toptions: SelectItem[],\n\t\tcurrentValue: string,\n\t\tonSelect: (value: string) => void,\n\t\tonCancel: () => void,\n\t\tonSelectionChange?: (value: string) => void,\n\t) {\n\t\tsuper();\n\n\t\t// Title\n\t\tthis.addChild(new Text(theme.bold(theme.fg(\"accent\", title)), 0, 0));\n\n\t\t// Description\n\t\tif (description) {\n\t\t\tthis.addChild(new Spacer(1));\n\t\t\tthis.addChild(new Text(theme.fg(\"muted\", description), 0, 0));\n\t\t}\n\n\t\t// Spacer\n\t\tthis.addChild(new Spacer(1));\n\n\t\t// Select list\n\t\tthis.selectList = new SelectList(\n\t\t\toptions,\n\t\t\tMath.min(options.length, 10),\n\t\t\tgetSelectListTheme(),\n\t\t\tSETTINGS_SUBMENU_SELECT_LIST_LAYOUT,\n\t\t);\n\n\t\t// Pre-select current value\n\t\tconst currentIndex = options.findIndex((o) => o.value === currentValue);\n\t\tif (currentIndex !== -1) {\n\t\t\tthis.selectList.setSelectedIndex(currentIndex);\n\t\t}\n\n\t\tthis.selectList.onSelect = (item) => {\n\t\t\tonSelect(item.value);\n\t\t};\n\n\t\tthis.selectList.onCancel = onCancel;\n\n\t\tif (onSelectionChange) {\n\t\t\tthis.selectList.onSelectionChange = (item) => {\n\t\t\t\tonSelectionChange(item.value);\n\t\t\t};\n\t\t}\n\n\t\tthis.addChild(this.selectList);\n\n\t\t// Hint\n\t\tthis.addChild(new Spacer(1));\n\t\tthis.addChild(new Text(theme.fg(\"dim\", \" Enter to select · Esc to go back\"), 0, 0));\n\t}\n\n\thandleInput(data: string): void {\n\t\tthis.selectList.handleInput(data);\n\t}\n}\n\nfunction themeItems(availableThemes: string[]): SelectItem[] {\n\treturn availableThemes.map((name) => ({ value: name, label: name }));\n}\n\nconst AUTOMATIC_THEME_VALUE = \"/\";\n\nfunction singleModeThemeItems(availableThemes: string[]): SelectItem[] {\n\treturn [\n\t\t{\n\t\t\tvalue: AUTOMATIC_THEME_VALUE,\n\t\t\tlabel: \"Automatic\",\n\t\t\tdescription: \"Use separate themes for light and dark terminal appearance\",\n\t\t},\n\t\t...themeItems(availableThemes),\n\t];\n}\n\nfunction preferredTheme(availableThemes: string[], preferred: string | undefined, fallback: string): string {\n\tif (preferred && availableThemes.includes(preferred)) return preferred;\n\tif (availableThemes.includes(fallback)) return fallback;\n\treturn availableThemes[0] ?? fallback;\n}\n\nfunction defaultAutomaticThemes(\n\tcurrentThemeSetting: string,\n\tavailableThemes: string[],\n): { lightTheme: string; darkTheme: string } {\n\tconst autoTheme = parseAutoThemeSetting(currentThemeSetting);\n\tif (autoTheme) return autoTheme;\n\n\tconst currentFixedTheme = currentThemeSetting.includes(\"/\") ? undefined : currentThemeSetting;\n\tconst themeName = preferredTheme(availableThemes, currentFixedTheme, \"moon\");\n\treturn { lightTheme: themeName, darkTheme: themeName };\n}\n\nclass ThemeSubmenu extends Container {\n\tprivate inputComponent: Component | undefined;\n\tprivate readonly callbacks: SettingsCallbacks;\n\tprivate readonly availableThemes: string[];\n\tprivate readonly terminalTheme: TerminalTheme;\n\tprivate readonly onDone: (selectedValue?: string) => void;\n\tprivate readonly originalThemeSetting: string;\n\tprivate mode: \"single\" | \"automatic\";\n\tprivate singleTheme: string;\n\tprivate lightTheme: string;\n\tprivate darkTheme: string;\n\n\tconstructor(\n\t\tcurrentThemeSetting: string,\n\t\tterminalTheme: TerminalTheme,\n\t\tavailableThemes: string[],\n\t\tcallbacks: SettingsCallbacks,\n\t\tonDone: (selectedValue?: string) => void,\n\t) {\n\t\tsuper();\n\t\tthis.callbacks = callbacks;\n\t\tthis.availableThemes = availableThemes;\n\t\tthis.terminalTheme = terminalTheme;\n\t\tthis.onDone = onDone;\n\t\tthis.originalThemeSetting = currentThemeSetting;\n\t\tconst autoTheme = parseAutoThemeSetting(currentThemeSetting);\n\t\tconst automaticThemes = defaultAutomaticThemes(currentThemeSetting, availableThemes);\n\t\tconst fixedTheme = autoTheme || currentThemeSetting.includes(\"/\") ? undefined : currentThemeSetting;\n\t\tthis.mode = autoTheme ? \"automatic\" : \"single\";\n\t\tthis.lightTheme = automaticThemes.lightTheme;\n\t\tthis.darkTheme = automaticThemes.darkTheme;\n\t\tthis.singleTheme = preferredTheme(\n\t\t\tavailableThemes,\n\t\t\tfixedTheme ?? (autoTheme ? this.getActiveAutomaticTheme() : undefined),\n\t\t\t\"moon\",\n\t\t);\n\n\t\tif (this.mode === \"automatic\") {\n\t\t\tthis.showAutomaticMenu();\n\t\t} else {\n\t\t\tthis.showSingleMenu();\n\t\t}\n\t}\n\n\thandleInput(data: string): void {\n\t\tthis.inputComponent?.handleInput?.(data);\n\t}\n\n\tprivate setContent(renderComponent: Component, inputComponent: Component = renderComponent): void {\n\t\tthis.clear();\n\t\tthis.addChild(renderComponent);\n\t\tthis.inputComponent = inputComponent;\n\t}\n\n\tprivate showSingleMenu(): void {\n\t\tthis.mode = \"single\";\n\t\tconst menu = new SelectSubmenu(\n\t\t\t\"Theme\",\n\t\t\t\"Select a theme, or choose Automatic to follow terminal appearance.\",\n\t\t\tsingleModeThemeItems(this.availableThemes),\n\t\t\tthis.singleTheme,\n\t\t\t(value) => {\n\t\t\t\tif (value === AUTOMATIC_THEME_VALUE) {\n\t\t\t\t\tthis.mode = \"automatic\";\n\t\t\t\t\tthis.callbacks.onThemePreview?.(this.getThemeSetting());\n\t\t\t\t\tthis.showAutomaticMenu();\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tthis.singleTheme = value;\n\t\t\t\tthis.apply(value);\n\t\t\t},\n\t\t\t() => this.cancel(),\n\t\t\t(value) => {\n\t\t\t\tthis.callbacks.onThemePreview?.(value === AUTOMATIC_THEME_VALUE ? this.getAutomaticThemeSetting() : value);\n\t\t\t},\n\t\t);\n\t\tthis.setContent(menu);\n\t}\n\n\tprivate showAutomaticMenu(): void {\n\t\tthis.mode = \"automatic\";\n\t\tconst content = new Container();\n\t\tcontent.addChild(new Text(theme.bold(theme.fg(\"accent\", \"Automatic Theme\")), 0, 0));\n\t\tcontent.addChild(new Spacer(1));\n\t\tcontent.addChild(new Text(theme.fg(\"muted\", \"Choose themes for terminal light and dark appearance.\"), 0, 0));\n\t\tcontent.addChild(new Text(theme.fg(\"muted\", \"Light/dark detection requires terminal support.\"), 0, 0));\n\t\tcontent.addChild(new Spacer(1));\n\n\t\tconst items: SettingItem[] = [\n\t\t\t{\n\t\t\t\tid: \"light-theme\",\n\t\t\t\tlabel: \"Light theme\",\n\t\t\t\tdescription: \"Theme to use in automatic mode when the terminal is light\",\n\t\t\t\tcurrentValue: this.lightTheme,\n\t\t\t\tsubmenu: (currentValue, done) =>\n\t\t\t\t\tthis.createThemeSelect(\n\t\t\t\t\t\t\"Light Theme\",\n\t\t\t\t\t\t\"Select the theme to use for light terminal appearance\",\n\t\t\t\t\t\tcurrentValue,\n\t\t\t\t\t\tdone,\n\t\t\t\t\t\t(value) => {\n\t\t\t\t\t\t\tthis.lightTheme = value;\n\t\t\t\t\t\t\tthis.callbacks.onThemePreview?.(this.getThemeSetting());\n\t\t\t\t\t\t\tdone(value);\n\t\t\t\t\t\t},\n\t\t\t\t\t),\n\t\t\t},\n\t\t\t{\n\t\t\t\tid: \"dark-theme\",\n\t\t\t\tlabel: \"Dark theme\",\n\t\t\t\tdescription: \"Theme to use in automatic mode when the terminal is dark\",\n\t\t\t\tcurrentValue: this.darkTheme,\n\t\t\t\tsubmenu: (currentValue, done) =>\n\t\t\t\t\tthis.createThemeSelect(\n\t\t\t\t\t\t\"Dark Theme\",\n\t\t\t\t\t\t\"Select the theme to use for dark terminal appearance\",\n\t\t\t\t\t\tcurrentValue,\n\t\t\t\t\t\tdone,\n\t\t\t\t\t\t(value) => {\n\t\t\t\t\t\t\tthis.darkTheme = value;\n\t\t\t\t\t\t\tthis.callbacks.onThemePreview?.(this.getThemeSetting());\n\t\t\t\t\t\t\tdone(value);\n\t\t\t\t\t\t},\n\t\t\t\t\t),\n\t\t\t},\n\t\t\t{\n\t\t\t\tid: \"apply\",\n\t\t\t\tlabel: \"Apply\",\n\t\t\t\tdescription: \"Save and go back\",\n\t\t\t\tcurrentValue: \"save and go back\",\n\t\t\t\tvalues: [\"save and go back\"],\n\t\t\t},\n\t\t\t{\n\t\t\t\tid: \"single-mode\",\n\t\t\t\tlabel: \"Change mode\",\n\t\t\t\tdescription: \"Switch to one theme for light and dark\",\n\t\t\t\tcurrentValue: \"switch to single theme\",\n\t\t\t\tvalues: [\"switch to single theme\"],\n\t\t\t},\n\t\t];\n\n\t\tconst settingsList = new SettingsList(\n\t\t\titems,\n\t\t\tMath.min(items.length, 10),\n\t\t\tgetSettingsListTheme(),\n\t\t\t(id) => {\n\t\t\t\tswitch (id) {\n\t\t\t\t\tcase \"single-mode\":\n\t\t\t\t\t\tthis.mode = \"single\";\n\t\t\t\t\t\tthis.singleTheme = this.getActiveAutomaticTheme();\n\t\t\t\t\t\tthis.callbacks.onThemePreview?.(this.singleTheme);\n\t\t\t\t\t\tthis.showSingleMenu();\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase \"apply\":\n\t\t\t\t\t\tthis.apply(this.getAutomaticThemeSetting());\n\t\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t},\n\t\t\t() => this.cancel(),\n\t\t);\n\t\tcontent.addChild(settingsList);\n\t\tthis.setContent(content, settingsList);\n\t}\n\n\tprivate createThemeSelect(\n\t\ttitle: string,\n\t\tdescription: string,\n\t\tcurrentValue: string,\n\t\tdone: (selectedValue?: string) => void,\n\t\tonSelect: (value: string) => void,\n\t): SelectSubmenu {\n\t\treturn new SelectSubmenu(\n\t\t\ttitle,\n\t\t\tdescription,\n\t\t\tthemeItems(this.availableThemes),\n\t\t\tcurrentValue,\n\t\t\tonSelect,\n\t\t\t() => {\n\t\t\t\tthis.callbacks.onThemePreview?.(this.getThemeSetting());\n\t\t\t\tdone();\n\t\t\t},\n\t\t\t(value) => this.callbacks.onThemePreview?.(value),\n\t\t);\n\t}\n\n\tprivate getThemeSetting(): string {\n\t\treturn this.mode === \"automatic\" ? this.getAutomaticThemeSetting() : this.singleTheme;\n\t}\n\n\tprivate getActiveAutomaticTheme(): string {\n\t\treturn this.terminalTheme === \"light\" ? this.lightTheme : this.darkTheme;\n\t}\n\n\tprivate getAutomaticThemeSetting(): string {\n\t\treturn `${this.lightTheme}/${this.darkTheme}`;\n\t}\n\n\tprivate apply(themeSetting: string): void {\n\t\tthis.onDone(themeSetting);\n\t}\n\n\tprivate cancel(): void {\n\t\tthis.callbacks.onThemePreview?.(this.originalThemeSetting);\n\t\tthis.onDone();\n\t}\n}\n\n/**\n * Main settings selector component.\n */\nexport class SettingsSelectorComponent extends Container {\n\tprivate settingsList: SettingsList;\n\n\tconstructor(config: SettingsConfig, callbacks: SettingsCallbacks) {\n\t\tsuper();\n\n\t\tconst supportsImages = getCapabilities().images;\n\t\tconst followUpKey = keyDisplayText(\"app.message.followUp\");\n\t\tconst curatorAvailable = config.searchCurator !== undefined;\n\n\t\tconst items: SettingItem[] = [\n\t\t\t{\n\t\t\t\tid: \"autocompact\",\n\t\t\t\tlabel: \"Auto-compact\",\n\t\t\t\tdescription: \"Automatically compact context when it gets too large\",\n\t\t\t\tcurrentValue: config.autoCompact ? \"true\" : \"false\",\n\t\t\t\tvalues: [\"true\", \"false\"],\n\t\t\t},\n\t\t\t{\n\t\t\t\tid: \"steering-mode\",\n\t\t\t\tlabel: \"Steering mode\",\n\t\t\t\tdescription:\n\t\t\t\t\t\"Enter while streaming queues steering messages. 'one-at-a-time': deliver one, wait for response. 'all': deliver all at once.\",\n\t\t\t\tcurrentValue: config.steeringMode,\n\t\t\t\tvalues: [\"one-at-a-time\", \"all\"],\n\t\t\t},\n\t\t\t{\n\t\t\t\tid: \"follow-up-mode\",\n\t\t\t\tlabel: \"Follow-up mode\",\n\t\t\t\tdescription: `${followUpKey} queues follow-up messages until agent stops. 'one-at-a-time': deliver one, wait for response. 'all': deliver all at once.`,\n\t\t\t\tcurrentValue: config.followUpMode,\n\t\t\t\tvalues: [\"one-at-a-time\", \"all\"],\n\t\t\t},\n\t\t\t{\n\t\t\t\tid: \"transport\",\n\t\t\t\tlabel: \"Transport\",\n\t\t\t\tdescription: \"Preferred transport for providers that support multiple transports\",\n\t\t\t\tcurrentValue: config.transport,\n\t\t\t\tvalues: [\"sse\", \"websocket\", \"websocket-cached\", \"auto\"],\n\t\t\t},\n\t\t\t{\n\t\t\t\tid: \"http-idle-timeout\",\n\t\t\t\tlabel: \"HTTP idle timeout\",\n\t\t\t\tdescription:\n\t\t\t\t\t\"Maximum idle gap while waiting for HTTP headers or body chunks. Disable for local models that pause longer than five minutes.\",\n\t\t\t\tcurrentValue: formatHttpIdleTimeoutMs(config.httpIdleTimeoutMs),\n\t\t\t\tvalues: HTTP_IDLE_TIMEOUT_CHOICES.map((choice) => choice.label),\n\t\t\t},\n\t\t\t{\n\t\t\t\tid: \"hide-thinking\",\n\t\t\t\tlabel: \"Hide thinking\",\n\t\t\t\tdescription: \"Hide thinking blocks in assistant responses\",\n\t\t\t\tcurrentValue: config.hideThinkingBlock ? \"true\" : \"false\",\n\t\t\t\tvalues: [\"true\", \"false\"],\n\t\t\t},\n\t\t\t{\n\t\t\t\t// lunr: collapsible reasoning — completed thinking runs render as\n\t\t\t\t// \"✻ Thought for Xs\" + first sentence. Disabled when thinking is hidden.\n\t\t\t\tid: \"thinking-collapse\",\n\t\t\t\tlabel: \"Collapse thinking\",\n\t\t\t\tdescription: \"Collapse completed thinking blocks to a short summary\",\n\t\t\t\tcurrentValue: config.thinkingCollapse ? \"true\" : \"false\",\n\t\t\t\tvalues: [\"true\", \"false\"],\n\t\t\t\tdisabled: () => config.hideThinkingBlock,\n\t\t\t},\n\t\t\t{\n\t\t\t\tid: \"cache-miss-notices\",\n\t\t\t\tlabel: \"Cache miss notices\",\n\t\t\t\tdescription: \"Show transcript notices for significant prompt-cache misses\",\n\t\t\t\tcurrentValue: config.showCacheMissNotices ? \"true\" : \"false\",\n\t\t\t\tvalues: [\"true\", \"false\"],\n\t\t\t},\n\t\t\t{\n\t\t\t\t// lunr: unset settings stay undefined so PI_CACHE_RETENTION still\n\t\t\t\t// applies; the row displays \"short\" as the implicit default.\n\t\t\t\tid: \"cache-retention\",\n\t\t\t\tlabel: \"Cache retention\",\n\t\t\t\tdescription: \"Prompt-cache TTL: short (5 min), long (1h where supported), or none\",\n\t\t\t\tcurrentValue: config.cacheRetention,\n\t\t\t\tvalues: [\"short\", \"long\", \"none\"],\n\t\t\t},\n\t\t\t{\n\t\t\t\tid: \"quiet-startup\",\n\t\t\t\tlabel: \"Quiet startup\",\n\t\t\t\tdescription: \"Disable verbose printing at startup\",\n\t\t\t\tcurrentValue: config.quietStartup ? \"true\" : \"false\",\n\t\t\t\tvalues: [\"true\", \"false\"],\n\t\t\t},\n\t\t\t{\n\t\t\t\tid: \"smooth-streaming\",\n\t\t\t\tlabel: \"Smooth streaming\",\n\t\t\t\tdescription: \"Reveal responses grapheme by grapheme (~30 FPS typewriter)\",\n\t\t\t\tcurrentValue: config.smoothStreaming ? \"true\" : \"false\",\n\t\t\t\tvalues: [\"true\", \"false\"],\n\t\t\t},\n\t\t\t{\n\t\t\t\tid: \"memory-char-cap\",\n\t\t\t\tlabel: \"Memory character cap\",\n\t\t\t\tdescription: `Max characters in the simple-pi-memory memory file AND the behavior file (${MEMORY_CHAR_CAP_MIN}-${MEMORY_CHAR_CAP_MAX}, default ${MEMORY_CHAR_CAP_DEFAULT}). Also settable via /memory-char-cap.`,\n\t\t\t\tcurrentValue: String(config.memoryCharCap),\n\t\t\t\tsubmenu: (currentValue, submenuDone) => new MemoryCharCapSubmenu(currentValue, submenuDone),\n\t\t\t},\n\t\t\t{\n\t\t\t\tid: \"search-curator\",\n\t\t\t\tlabel: \"Search curator\",\n\t\t\t\tdescription: curatorAvailable\n\t\t\t\t\t? \"pi-web-access search curator: off = raw results, on = browser curator with summary draft, auto-summary = summary without the curator. Also settable via /curator.\"\n\t\t\t\t\t: \"pi-web-access is not loaded; the search curator is unavailable.\",\n\t\t\t\tcurrentValue: config.searchCurator ?? \"unavailable\",\n\t\t\t\tvalues: curatorAvailable ? SEARCH_CURATOR_VALUES : undefined,\n\t\t\t},\n\t\t\t{\n\t\t\t\tid: \"session-retention-days\",\n\t\t\t\tlabel: \"Session retention\",\n\t\t\t\tdescription: \"Auto-delete session files older than N days at launch (0 = keep forever)\",\n\t\t\t\tcurrentValue: String(config.sessionRetentionDays),\n\t\t\t\tvalues: [\"0\", \"7\", \"14\", \"30\", \"60\", \"90\", \"365\"],\n\t\t\t},\n\t\t\t{\n\t\t\t\tid: \"default-project-trust\",\n\t\t\t\tlabel: \"Default project trust\",\n\t\t\t\tdescription: \"Fallback behavior when no extension or saved trust decision decides project trust\",\n\t\t\t\tcurrentValue: DEFAULT_PROJECT_TRUST_LABELS[config.defaultProjectTrust],\n\t\t\t\tvalues: Object.values(DEFAULT_PROJECT_TRUST_LABELS),\n\t\t\t},\n\t\t\t{\n\t\t\t\tid: \"default-permission-mode\",\n\t\t\t\tlabel: \"Default permission mode\",\n\t\t\t\tdescription:\n\t\t\t\t\t\"Permission mode new sessions start with: manual = approve every action, yolo = auto-approve tools, plan = read-only, auto = fully autonomous. Change per-session with /mode or Shift+Tab.\",\n\t\t\t\tcurrentValue: config.defaultPermissionMode,\n\t\t\t\tvalues: [\"manual\", \"yolo\", \"plan\", \"auto\"],\n\t\t\t},\n\t\t\t{\n\t\t\t\tid: \"double-escape-action\",\n\t\t\t\tlabel: \"Double-escape action\",\n\t\t\t\tdescription: \"Action when pressing Escape twice with empty editor\",\n\t\t\t\tcurrentValue: config.doubleEscapeAction,\n\t\t\t\tvalues: [\"tree\", \"fork\", \"none\"],\n\t\t\t},\n\t\t\t{\n\t\t\t\tid: \"tree-filter-mode\",\n\t\t\t\tlabel: \"Tree filter mode\",\n\t\t\t\tdescription: \"Default filter when opening /tree\",\n\t\t\t\tcurrentValue: config.treeFilterMode,\n\t\t\t\tvalues: [\"default\", \"no-tools\", \"user-only\", \"labeled-only\", \"all\"],\n\t\t\t},\n\t\t\t{\n\t\t\t\tid: \"thinking\",\n\t\t\t\tlabel: \"Thinking level\",\n\t\t\t\tdescription: \"Reasoning depth for thinking-capable models\",\n\t\t\t\tcurrentValue: config.thinkingLevel,\n\t\t\t\tsubmenu: (currentValue, done) =>\n\t\t\t\t\tnew SelectSubmenu(\n\t\t\t\t\t\t\"Thinking Level\",\n\t\t\t\t\t\t\"Select reasoning depth for thinking-capable models\",\n\t\t\t\t\t\tconfig.availableThinkingLevels.map((level) => ({\n\t\t\t\t\t\t\tvalue: level,\n\t\t\t\t\t\t\tlabel: level,\n\t\t\t\t\t\t\tdescription: THINKING_DESCRIPTIONS[level],\n\t\t\t\t\t\t})),\n\t\t\t\t\t\tcurrentValue,\n\t\t\t\t\t\t(value) => {\n\t\t\t\t\t\t\tcallbacks.onThinkingLevelChange(value as ThinkingLevel);\n\t\t\t\t\t\t\tdone(value);\n\t\t\t\t\t\t},\n\t\t\t\t\t\t() => done(),\n\t\t\t\t\t),\n\t\t\t},\n\t\t\t{\n\t\t\t\tid: \"theme\",\n\t\t\t\tlabel: \"Theme\",\n\t\t\t\tdescription: \"Color theme for the interface\",\n\t\t\t\tcurrentValue: config.currentTheme,\n\t\t\t\tsubmenu: (currentValue, done) =>\n\t\t\t\t\tnew ThemeSubmenu(currentValue, config.terminalTheme, config.availableThemes, callbacks, done),\n\t\t\t},\n\t\t\t{\n\t\t\t\tid: \"model-tiers\",\n\t\t\t\tlabel: \"Model tiers\",\n\t\t\t\tdescription:\n\t\t\t\t\t\"Route subagents to light/standard/heavy tier models. An explicit model choice overrides the tier.\",\n\t\t\t\tcurrentValue: config.modelTiers.enabled ? \"on\" : \"off\",\n\t\t\t\tsubmenu: (currentValue, done) => new ModelTiersSubmenu(currentValue, config.modelTiers, callbacks, done),\n\t\t\t},\n\t\t\t// lunr: Customize submenu — lunR TUI toggles (rail, prompt symbol, footer segments)\n\t\t\t{\n\t\t\t\tid: \"customize\",\n\t\t\t\tlabel: \"Customize\",\n\t\t\t\tdescription: \"lunR TUI customizations: gutter rail, prompt symbol, footer segments\",\n\t\t\t\tcurrentValue: \"configure\",\n\t\t\t\tsubmenu: (_currentValue, done) => new CustomizeSubmenu(config, callbacks, done),\n\t\t\t},\n\t\t\t// lunr: Rollback submenu\n\t\t\t{\n\t\t\t\tid: \"rollback\",\n\t\t\t\tlabel: \"Rollback\",\n\t\t\t\tdescription: \"Pre-edit file snapshots so /rollback can restore them. Capture mode, scope, retention.\",\n\t\t\t\tcurrentValue: config.rollbackEnabled ? \"on\" : \"off\",\n\t\t\t\tsubmenu: (currentValue, done) =>\n\t\t\t\t\tnew RollbackSubmenu(currentValue, config, callbacks, callbacks.isRollbackSessionForceEnabled(), done),\n\t\t\t},\n\t\t\t// lunr: multi-subscription pools\n\t\t\t{\n\t\t\t\tid: \"auto-manage-subscriptions\",\n\t\t\t\tlabel: \"Auto-manage subscriptions\",\n\t\t\t\tdescription:\n\t\t\t\t\t\"When on, lunr rotates API keys automatically on usage limits and the model selector won't offer manual subscription switching.\",\n\t\t\t\tcurrentValue: config.autoManageSubscriptions ? \"on\" : \"off\",\n\t\t\t\tvalues: [\"on\", \"off\"],\n\t\t\t},\n\t\t];\n\n\t\t// lunr: Subscriptions submenu — one row per pooled API key (live manager accessors).\n\t\tconst subscriptionCallbacks = callbacks.subscriptions;\n\t\tif (subscriptionCallbacks) {\n\t\t\titems.push({\n\t\t\t\tid: \"subscriptions\",\n\t\t\t\tlabel: \"Subscriptions\",\n\t\t\t\tdescription: \"Per-provider API key pools: set the active key, rename, clear exhaustion, remove.\",\n\t\t\t\tcurrentValue:\n\t\t\t\t\tconfig.subscriptionCount === 0\n\t\t\t\t\t\t? \"none\"\n\t\t\t\t\t\t: `${config.subscriptionCount} key${config.subscriptionCount === 1 ? \"\" : \"s\"}`,\n\t\t\t\tsubmenu: (_currentValue, done) => new SubscriptionsSubmenu(subscriptionCallbacks, done),\n\t\t\t});\n\t\t}\n\n\t\t// Only show image toggle if terminal supports it\n\t\tif (supportsImages) {\n\t\t\t// Insert after autocompact\n\t\t\titems.splice(1, 0, {\n\t\t\t\tid: \"show-images\",\n\t\t\t\tlabel: \"Show images\",\n\t\t\t\tdescription: \"Render images inline in terminal\",\n\t\t\t\tcurrentValue: config.showImages ? \"true\" : \"false\",\n\t\t\t\tvalues: [\"true\", \"false\"],\n\t\t\t});\n\t\t\titems.splice(2, 0, {\n\t\t\t\tid: \"image-width-cells\",\n\t\t\t\tlabel: \"Image width\",\n\t\t\t\tdescription: \"Preferred inline image width in terminal cells\",\n\t\t\t\tcurrentValue: String(config.imageWidthCells),\n\t\t\t\tvalues: [\"60\", \"80\", \"120\"],\n\t\t\t});\n\t\t}\n\n\t\t// Image auto-resize toggle (always available, affects both attached and read images)\n\t\titems.splice(supportsImages ? 3 : 1, 0, {\n\t\t\tid: \"auto-resize-images\",\n\t\t\tlabel: \"Auto-resize images\",\n\t\t\tdescription: \"Resize large images to 2000x2000 max for better model compatibility\",\n\t\t\tcurrentValue: config.autoResizeImages ? \"true\" : \"false\",\n\t\t\tvalues: [\"true\", \"false\"],\n\t\t});\n\n\t\t// Block images toggle (always available, insert after auto-resize-images)\n\t\tconst autoResizeIndex = items.findIndex((item) => item.id === \"auto-resize-images\");\n\t\titems.splice(autoResizeIndex + 1, 0, {\n\t\t\tid: \"block-images\",\n\t\t\tlabel: \"Block images\",\n\t\t\tdescription: \"Prevent images from being sent to LLM providers\",\n\t\t\tcurrentValue: config.blockImages ? \"true\" : \"false\",\n\t\t\tvalues: [\"true\", \"false\"],\n\t\t});\n\n\t\t// Skill commands toggle (insert after block-images)\n\t\tconst blockImagesIndex = items.findIndex((item) => item.id === \"block-images\");\n\t\titems.splice(blockImagesIndex + 1, 0, {\n\t\t\tid: \"skill-commands\",\n\t\t\tlabel: \"Skill commands\",\n\t\t\tdescription: \"Register skills as /skill:name commands\",\n\t\t\tcurrentValue: config.enableSkillCommands ? \"true\" : \"false\",\n\t\t\tvalues: [\"true\", \"false\"],\n\t\t});\n\n\t\t// Hardware cursor toggle (insert after skill-commands)\n\t\tconst skillCommandsIndex = items.findIndex((item) => item.id === \"skill-commands\");\n\t\titems.splice(skillCommandsIndex + 1, 0, {\n\t\t\tid: \"show-hardware-cursor\",\n\t\t\tlabel: \"Show hardware cursor\",\n\t\t\tdescription: \"Show the terminal cursor while still positioning it for IME support\",\n\t\t\tcurrentValue: config.showHardwareCursor ? \"true\" : \"false\",\n\t\t\tvalues: [\"true\", \"false\"],\n\t\t});\n\n\t\t// Editor padding toggle (insert after show-hardware-cursor)\n\t\tconst hardwareCursorIndex = items.findIndex((item) => item.id === \"show-hardware-cursor\");\n\t\titems.splice(hardwareCursorIndex + 1, 0, {\n\t\t\tid: \"editor-padding\",\n\t\t\tlabel: \"Editor padding\",\n\t\t\tdescription: \"Horizontal padding for input editor (0-3)\",\n\t\t\tcurrentValue: String(config.editorPaddingX),\n\t\t\tvalues: [\"0\", \"1\", \"2\", \"3\"],\n\t\t});\n\n\t\t// Output padding toggle (insert after editor-padding)\n\t\tconst editorPaddingIndex = items.findIndex((item) => item.id === \"editor-padding\");\n\t\titems.splice(editorPaddingIndex + 1, 0, {\n\t\t\tid: \"output-padding\",\n\t\t\tlabel: \"Output padding\",\n\t\t\tdescription: \"Horizontal padding for user messages, assistant messages, and thinking\",\n\t\t\tcurrentValue: String(config.outputPad),\n\t\t\tvalues: [\"0\", \"1\"],\n\t\t});\n\n\t\t// Autocomplete max visible toggle (insert after output-padding)\n\t\tconst outputPaddingIndex = items.findIndex((item) => item.id === \"output-padding\");\n\t\titems.splice(outputPaddingIndex + 1, 0, {\n\t\t\tid: \"autocomplete-max-visible\",\n\t\t\tlabel: \"Autocomplete max items\",\n\t\t\tdescription: \"Max visible items in autocomplete dropdown (3-20)\",\n\t\t\tcurrentValue: String(config.autocompleteMaxVisible),\n\t\t\tvalues: [\"3\", \"5\", \"7\", \"10\", \"15\", \"20\"],\n\t\t});\n\n\t\t// Clear on shrink toggle (insert after autocomplete-max-visible)\n\t\tconst autocompleteIndex = items.findIndex((item) => item.id === \"autocomplete-max-visible\");\n\t\titems.splice(autocompleteIndex + 1, 0, {\n\t\t\tid: \"clear-on-shrink\",\n\t\t\tlabel: \"Clear on shrink\",\n\t\t\tdescription: \"Clear empty rows when content shrinks (may cause flicker)\",\n\t\t\tcurrentValue: config.clearOnShrink ? \"true\" : \"false\",\n\t\t\tvalues: [\"true\", \"false\"],\n\t\t});\n\n\t\t// Terminal progress toggle (insert after clear-on-shrink)\n\t\tconst clearOnShrinkIndex = items.findIndex((item) => item.id === \"clear-on-shrink\");\n\t\titems.splice(clearOnShrinkIndex + 1, 0, {\n\t\t\tid: \"terminal-progress\",\n\t\t\tlabel: \"Terminal progress\",\n\t\t\tdescription: \"Show OSC 9;4 progress indicators in the terminal tab bar\",\n\t\t\tcurrentValue: config.showTerminalProgress ? \"true\" : \"false\",\n\t\t\tvalues: [\"true\", \"false\"],\n\t\t});\n\n\t\t// Add borders\n\t\tthis.addChild(new DynamicBorder());\n\n\t\tthis.settingsList = new SettingsList(\n\t\t\titems,\n\t\t\t10,\n\t\t\tgetSettingsListTheme(),\n\t\t\t(id, newValue) => {\n\t\t\t\tswitch (id) {\n\t\t\t\t\tcase \"autocompact\":\n\t\t\t\t\t\tcallbacks.onAutoCompactChange(newValue === \"true\");\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase \"show-images\":\n\t\t\t\t\t\tcallbacks.onShowImagesChange(newValue === \"true\");\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase \"image-width-cells\":\n\t\t\t\t\t\tcallbacks.onImageWidthCellsChange(parseInt(newValue, 10));\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase \"auto-resize-images\":\n\t\t\t\t\t\tcallbacks.onAutoResizeImagesChange(newValue === \"true\");\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase \"block-images\":\n\t\t\t\t\t\tcallbacks.onBlockImagesChange(newValue === \"true\");\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase \"skill-commands\":\n\t\t\t\t\t\tcallbacks.onEnableSkillCommandsChange(newValue === \"true\");\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase \"steering-mode\":\n\t\t\t\t\t\tcallbacks.onSteeringModeChange(newValue as \"all\" | \"one-at-a-time\");\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase \"follow-up-mode\":\n\t\t\t\t\t\tcallbacks.onFollowUpModeChange(newValue as \"all\" | \"one-at-a-time\");\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase \"transport\":\n\t\t\t\t\t\tcallbacks.onTransportChange(newValue as Transport);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase \"http-idle-timeout\": {\n\t\t\t\t\t\tconst choice = HTTP_IDLE_TIMEOUT_CHOICES.find((item) => item.label === newValue);\n\t\t\t\t\t\tif (choice) {\n\t\t\t\t\t\t\tcallbacks.onHttpIdleTimeoutMsChange(choice.timeoutMs);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\tcase \"hide-thinking\":\n\t\t\t\t\t\tcallbacks.onHideThinkingBlockChange(newValue === \"true\");\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase \"thinking-collapse\":\n\t\t\t\t\t\tcallbacks.onThinkingCollapseChange(newValue === \"true\");\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase \"cache-miss-notices\":\n\t\t\t\t\t\tcallbacks.onShowCacheMissNoticesChange(newValue === \"true\");\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase \"cache-retention\":\n\t\t\t\t\t\tcallbacks.onCacheRetentionChange(newValue as \"none\" | \"short\" | \"long\");\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase \"quiet-startup\":\n\t\t\t\t\t\tcallbacks.onQuietStartupChange(newValue === \"true\");\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase \"smooth-streaming\":\n\t\t\t\t\t\tcallbacks.onSmoothStreamingChange(newValue === \"true\");\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase \"memory-char-cap\":\n\t\t\t\t\t\tcallbacks.onMemoryCharCapChange(parseInt(newValue, 10));\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase \"search-curator\":\n\t\t\t\t\t\tcallbacks.onSearchCuratorChange(newValue as SearchCuratorSetting);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase \"session-retention-days\":\n\t\t\t\t\t\tcallbacks.onSessionRetentionDaysChange(parseInt(newValue, 10));\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase \"default-project-trust\": {\n\t\t\t\t\t\tconst defaultProjectTrust = DEFAULT_PROJECT_TRUST_BY_LABEL.get(newValue);\n\t\t\t\t\t\tif (defaultProjectTrust) {\n\t\t\t\t\t\t\tcallbacks.onDefaultProjectTrustChange(defaultProjectTrust);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\tcase \"default-permission-mode\":\n\t\t\t\t\t\tcallbacks.onDefaultPermissionModeChange(newValue as DefaultPermissionMode);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase \"double-escape-action\":\n\t\t\t\t\t\tcallbacks.onDoubleEscapeActionChange(newValue as \"fork\" | \"tree\");\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase \"tree-filter-mode\":\n\t\t\t\t\t\tcallbacks.onTreeFilterModeChange(\n\t\t\t\t\t\t\tnewValue as \"default\" | \"no-tools\" | \"user-only\" | \"labeled-only\" | \"all\",\n\t\t\t\t\t\t);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase \"show-hardware-cursor\":\n\t\t\t\t\t\tcallbacks.onShowHardwareCursorChange(newValue === \"true\");\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase \"editor-padding\":\n\t\t\t\t\t\tcallbacks.onEditorPaddingXChange(parseInt(newValue, 10));\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase \"output-padding\":\n\t\t\t\t\t\tcallbacks.onOutputPadChange(newValue === \"0\" ? 0 : 1);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase \"autocomplete-max-visible\":\n\t\t\t\t\t\tcallbacks.onAutocompleteMaxVisibleChange(parseInt(newValue, 10));\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase \"clear-on-shrink\":\n\t\t\t\t\t\tcallbacks.onClearOnShrinkChange(newValue === \"true\");\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase \"terminal-progress\":\n\t\t\t\t\t\tcallbacks.onShowTerminalProgressChange(newValue === \"true\");\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase \"auto-manage-subscriptions\":\n\t\t\t\t\t\tcallbacks.onAutoManageSubscriptionsChange(newValue === \"on\");\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase \"theme\":\n\t\t\t\t\t\tcallbacks.onThemeChange(newValue);\n\t\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t},\n\t\t\tcallbacks.onCancel,\n\t\t\t{ enableSearch: true },\n\t\t);\n\n\t\tthis.addChild(this.settingsList);\n\t\tthis.addChild(new DynamicBorder());\n\t}\n\n\tgetSettingsList(): SettingsList {\n\t\treturn this.settingsList;\n\t}\n}\n"]}
|