@ashx-j/lunr-dev 0.2.13-dev.5.1 → 0.2.13-dev.8.1
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-tui.d.ts.map +1 -1
- package/dist/builtin-extensions/ashxj-tui.js +4 -4
- package/dist/builtin-extensions/ashxj-tui.js.map +1 -1
- package/dist/builtin-extensions/index.d.ts.map +1 -1
- package/dist/builtin-extensions/index.js +2 -0
- package/dist/builtin-extensions/index.js.map +1 -1
- package/dist/builtin-extensions/lunr-settings-tools.d.ts +4 -0
- package/dist/builtin-extensions/lunr-settings-tools.d.ts.map +1 -0
- package/dist/builtin-extensions/lunr-settings-tools.js +120 -0
- package/dist/builtin-extensions/lunr-settings-tools.js.map +1 -0
- package/dist/builtin-extensions/pi-prompt-template-model/subagent-runtime.d.ts +2 -2
- package/dist/builtin-extensions/pi-prompt-template-model/subagent-runtime.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-prompt-template-model/subagent-runtime.js.map +1 -1
- package/dist/builtin-extensions/pi-prompt-template-model/subagent-step.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-prompt-template-model/subagent-step.js +3 -3
- package/dist/builtin-extensions/pi-prompt-template-model/subagent-step.js.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/api/delegation.d.ts +2 -2
- package/dist/builtin-extensions/pi-subagents/src/api/delegation.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/api/delegation.js +1 -1
- package/dist/builtin-extensions/pi-subagents/src/api/delegation.js.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/extension/index.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/extension/index.js +2 -1
- package/dist/builtin-extensions/pi-subagents/src/extension/index.js.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/extension/schemas.d.ts +5 -11
- package/dist/builtin-extensions/pi-subagents/src/extension/schemas.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/extension/schemas.js +12 -15
- package/dist/builtin-extensions/pi-subagents/src/extension/schemas.js.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/extension/tool-description.d.ts +3 -3
- package/dist/builtin-extensions/pi-subagents/src/extension/tool-description.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/extension/tool-description.js +14 -27
- package/dist/builtin-extensions/pi-subagents/src/extension/tool-description.js.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/runs/background/async-execution.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/runs/background/async-execution.js +6 -4
- package/dist/builtin-extensions/pi-subagents/src/runs/background/async-execution.js.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/runs/background/async-job-tracker.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/runs/background/async-job-tracker.js +2 -1
- package/dist/builtin-extensions/pi-subagents/src/runs/background/async-job-tracker.js.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/runs/background/async-resume.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/runs/background/async-resume.js +6 -4
- package/dist/builtin-extensions/pi-subagents/src/runs/background/async-resume.js.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/runs/background/async-status.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/runs/background/async-status.js +4 -2
- package/dist/builtin-extensions/pi-subagents/src/runs/background/async-status.js.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/runs/foreground/chain-clarify.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/runs/foreground/chain-clarify.js +3 -35
- package/dist/builtin-extensions/pi-subagents/src/runs/foreground/chain-clarify.js.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/runs/foreground/chain-execution.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/runs/foreground/chain-execution.js +5 -12
- package/dist/builtin-extensions/pi-subagents/src/runs/foreground/chain-execution.js.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/runs/foreground/subagent-executor.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/runs/foreground/subagent-executor.js +14 -31
- package/dist/builtin-extensions/pi-subagents/src/runs/foreground/subagent-executor.js.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/runs/shared/model-fallback.d.ts +2 -0
- package/dist/builtin-extensions/pi-subagents/src/runs/shared/model-fallback.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/runs/shared/model-fallback.js +28 -22
- package/dist/builtin-extensions/pi-subagents/src/runs/shared/model-fallback.js.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/runs/shared/parallel-utils.d.ts +1 -0
- package/dist/builtin-extensions/pi-subagents/src/runs/shared/parallel-utils.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/runs/shared/parallel-utils.js.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/shared/child-spec.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/shared/child-spec.js +9 -4
- package/dist/builtin-extensions/pi-subagents/src/shared/child-spec.js.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/shared/formatters.d.ts +1 -1
- package/dist/builtin-extensions/pi-subagents/src/shared/formatters.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/shared/formatters.js +2 -2
- package/dist/builtin-extensions/pi-subagents/src/shared/formatters.js.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/shared/types.d.ts +4 -7
- package/dist/builtin-extensions/pi-subagents/src/shared/types.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/shared/types.js +1 -1
- package/dist/builtin-extensions/pi-subagents/src/shared/types.js.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/slash/delegation-adapters.d.ts +3 -3
- package/dist/builtin-extensions/pi-subagents/src/slash/delegation-adapters.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/slash/delegation-adapters.js +7 -6
- package/dist/builtin-extensions/pi-subagents/src/slash/delegation-adapters.js.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/slash/delegation-request.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/slash/delegation-request.js +3 -3
- package/dist/builtin-extensions/pi-subagents/src/slash/delegation-request.js.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/slash/prompt-workflows.d.ts +1 -1
- package/dist/builtin-extensions/pi-subagents/src/slash/prompt-workflows.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/slash/prompt-workflows.js +6 -4
- package/dist/builtin-extensions/pi-subagents/src/slash/prompt-workflows.js.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/slash/slash-commands.d.ts +1 -1
- package/dist/builtin-extensions/pi-subagents/src/slash/slash-commands.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/slash/slash-commands.js +15 -10
- package/dist/builtin-extensions/pi-subagents/src/slash/slash-commands.js.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/tui/fleet.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/tui/fleet.js +3 -2
- package/dist/builtin-extensions/pi-subagents/src/tui/fleet.js.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/tui/render.d.ts +2 -2
- package/dist/builtin-extensions/pi-subagents/src/tui/render.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/tui/render.js +75 -43
- package/dist/builtin-extensions/pi-subagents/src/tui/render.js.map +1 -1
- package/dist/catalog/models.json +1 -1
- package/dist/catalog/providers/amazon-bedrock.json +1 -1
- package/dist/catalog/providers/anthropic.json +1 -1
- package/dist/catalog/providers/azure-openai-responses.json +1 -1
- package/dist/catalog/providers/cloudflare-ai-gateway.json +1 -1
- package/dist/catalog/providers/fireworks.json +1 -1
- package/dist/catalog/providers/github-copilot.json +1 -1
- package/dist/catalog/providers/google-vertex.json +1 -1
- package/dist/catalog/providers/google.json +1 -1
- package/dist/catalog/providers/huggingface.json +1 -1
- package/dist/catalog/providers/nvidia.json +1 -1
- package/dist/catalog/providers/openai-codex.json +1 -1
- package/dist/catalog/providers/openai.json +1 -1
- package/dist/catalog/providers/opencode-go.json +1 -1
- package/dist/catalog/providers/opencode.json +1 -1
- package/dist/catalog/providers/openrouter.json +1 -1
- package/dist/catalog/providers/vercel-ai-gateway.json +1 -1
- package/dist/catalog/publication.json +131 -3
- package/dist/cli/list-models.d.ts.map +1 -1
- package/dist/cli/list-models.js +1 -0
- package/dist/cli/list-models.js.map +1 -1
- package/dist/core/agent-session-runtime.d.ts +5 -1
- package/dist/core/agent-session-runtime.d.ts.map +1 -1
- package/dist/core/agent-session-runtime.js +7 -2
- package/dist/core/agent-session-runtime.js.map +1 -1
- package/dist/core/agent-session.d.ts +2 -0
- package/dist/core/agent-session.d.ts.map +1 -1
- package/dist/core/agent-session.js +20 -5
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/catalog-cache-scope.d.ts +3 -0
- package/dist/core/catalog-cache-scope.d.ts.map +1 -0
- package/dist/core/catalog-cache-scope.js +12 -0
- package/dist/core/catalog-cache-scope.js.map +1 -0
- package/dist/core/catalog-merge.d.ts +2 -0
- package/dist/core/catalog-merge.d.ts.map +1 -1
- package/dist/core/catalog-merge.js +29 -2
- package/dist/core/catalog-merge.js.map +1 -1
- package/dist/core/catalog-refresh-polling.d.ts +8 -0
- package/dist/core/catalog-refresh-polling.d.ts.map +1 -0
- package/dist/core/catalog-refresh-polling.js +30 -0
- package/dist/core/catalog-refresh-polling.js.map +1 -0
- package/dist/core/codex-catalog.d.ts +3 -0
- package/dist/core/codex-catalog.d.ts.map +1 -0
- package/dist/core/codex-catalog.js +15 -0
- package/dist/core/codex-catalog.js.map +1 -0
- package/dist/core/context-breakdown.d.ts +2 -0
- package/dist/core/context-breakdown.d.ts.map +1 -1
- package/dist/core/context-breakdown.js +6 -2
- package/dist/core/context-breakdown.js.map +1 -1
- package/dist/core/injected-prompt.d.ts +3 -3
- package/dist/core/injected-prompt.d.ts.map +1 -1
- package/dist/core/injected-prompt.js +2 -7
- package/dist/core/injected-prompt.js.map +1 -1
- package/dist/core/large-subagent-launch.d.ts +13 -0
- package/dist/core/large-subagent-launch.d.ts.map +1 -0
- package/dist/core/large-subagent-launch.js +54 -0
- package/dist/core/large-subagent-launch.js.map +1 -0
- package/dist/core/live-catalog.d.ts +5 -2
- package/dist/core/live-catalog.d.ts.map +1 -1
- package/dist/core/live-catalog.js +108 -27
- package/dist/core/live-catalog.js.map +1 -1
- package/dist/core/model-instructions.d.ts +24 -0
- package/dist/core/model-instructions.d.ts.map +1 -0
- package/dist/core/model-instructions.js +123 -0
- package/dist/core/model-instructions.js.map +1 -0
- package/dist/core/model-runtime.d.ts +8 -0
- package/dist/core/model-runtime.d.ts.map +1 -1
- package/dist/core/model-runtime.js +64 -12
- package/dist/core/model-runtime.js.map +1 -1
- package/dist/core/official-catalog.d.ts +4 -0
- package/dist/core/official-catalog.d.ts.map +1 -1
- package/dist/core/official-catalog.js +86 -21
- package/dist/core/official-catalog.js.map +1 -1
- package/dist/core/permissions.d.ts +11 -10
- package/dist/core/permissions.d.ts.map +1 -1
- package/dist/core/permissions.js +61 -45
- package/dist/core/permissions.js.map +1 -1
- package/dist/core/plan-mode.d.ts.map +1 -1
- package/dist/core/plan-mode.js +10 -1
- package/dist/core/plan-mode.js.map +1 -1
- package/dist/core/resource-loader.d.ts +3 -0
- package/dist/core/resource-loader.d.ts.map +1 -1
- package/dist/core/resource-loader.js +13 -4
- package/dist/core/resource-loader.js.map +1 -1
- package/dist/core/runtime-bridges.d.ts +4 -0
- package/dist/core/runtime-bridges.d.ts.map +1 -0
- package/dist/core/runtime-bridges.js +16 -0
- package/dist/core/runtime-bridges.js.map +1 -0
- package/dist/core/sdk.d.ts.map +1 -1
- package/dist/core/sdk.js +1 -0
- package/dist/core/sdk.js.map +1 -1
- package/dist/core/session-manager.d.ts.map +1 -1
- package/dist/core/session-manager.js +17 -16
- package/dist/core/session-manager.js.map +1 -1
- package/dist/core/settings-manager.d.ts +13 -0
- package/dist/core/settings-manager.d.ts.map +1 -1
- package/dist/core/settings-manager.js +32 -0
- package/dist/core/settings-manager.js.map +1 -1
- package/dist/core/settings-tools-bridge.d.ts +35 -0
- package/dist/core/settings-tools-bridge.d.ts.map +1 -0
- package/dist/core/settings-tools-bridge.js +56 -0
- package/dist/core/settings-tools-bridge.js.map +1 -0
- package/dist/core/swarm.d.ts +0 -31
- package/dist/core/swarm.d.ts.map +1 -1
- package/dist/core/swarm.js +2 -76
- package/dist/core/swarm.js.map +1 -1
- package/dist/core/system-prompt.d.ts.map +1 -1
- package/dist/core/system-prompt.js +1 -1
- package/dist/core/system-prompt.js.map +1 -1
- package/dist/gateway/agent-bridge.d.ts.map +1 -1
- package/dist/gateway/agent-bridge.js +3 -2
- package/dist/gateway/agent-bridge.js.map +1 -1
- package/dist/gateway/approval.d.ts.map +1 -1
- package/dist/gateway/approval.js +4 -3
- package/dist/gateway/approval.js.map +1 -1
- package/dist/gateway/cron.d.ts.map +1 -1
- package/dist/gateway/cron.js +3 -2
- package/dist/gateway/cron.js.map +1 -1
- package/dist/gateway/router.d.ts +1 -1
- package/dist/gateway/router.d.ts.map +1 -1
- package/dist/gateway/router.js +1 -1
- package/dist/gateway/router.js.map +1 -1
- package/dist/main.d.ts.map +1 -1
- package/dist/main.js +12 -9
- package/dist/main.js.map +1 -1
- package/dist/migrations.d.ts.map +1 -1
- package/dist/migrations.js +4 -0
- package/dist/migrations.js.map +1 -1
- package/dist/modes/interactive/components/injected-prompt-message.d.ts +1 -1
- package/dist/modes/interactive/components/injected-prompt-message.d.ts.map +1 -1
- package/dist/modes/interactive/components/injected-prompt-message.js +1 -1
- package/dist/modes/interactive/components/injected-prompt-message.js.map +1 -1
- package/dist/modes/interactive/components/model-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/model-selector.js +4 -1
- package/dist/modes/interactive/components/model-selector.js.map +1 -1
- package/dist/modes/interactive/components/settings-selector.d.ts +8 -1
- package/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/settings-selector.js +61 -1
- package/dist/modes/interactive/components/settings-selector.js.map +1 -1
- package/dist/modes/interactive/interactive-mode.d.ts +2 -2
- package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-mode.js +65 -99
- package/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/dist/startup/interactive-shell.d.ts.map +1 -1
- package/dist/startup/interactive-shell.js +2 -1
- package/dist/startup/interactive-shell.js.map +1 -1
- package/docs/features.md +7 -6
- package/docs/model-catalog.md +29 -0
- package/docs/quickstart.md +3 -2
- package/docs/settings.md +3 -1
- package/docs/termux.md +1 -1
- package/docs/usage.md +2 -1
- package/examples/extensions/subagent/README.md +1 -1
- package/package.json +4 -4
|
@@ -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 {\n\ttype DefaultPermissionMode,\n\ttype DefaultProjectTrust,\n\ttype ModelTierName,\n\ttype ModelTiersSettings,\n\ttype RollbackCapture,\n\ttype RollbackScope,\n\tSKILL_TAG_CHARACTERS,\n\ttype SkillTagCharacter,\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\tskillTagCharacter: SkillTagCharacter;\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\tmemoryEnabled: boolean;\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\tfooterMcp: boolean;\n\tfooterLsp: boolean;\n\tfooterContext: boolean;\n\tfooterTokens: boolean;\n\tfooterCacheHitRate: boolean;\n\tfooterTps: boolean;\n\tfooterStatuses: boolean;\n\tfooterGit: boolean;\n\tfooterPlan: boolean;\n\tfooterPlanBar: boolean;\n\tplanUsageWindow: \"5h\" | \"weekly\";\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\tonSkillTagCharacterChange: (character: SkillTagCharacter) => 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\tonModelTierThinkingChange: (tier: ModelTierName, level: ThinkingLevel | undefined) => void;\n\tgetTierThinkingLevels: (tier: ModelTierName) => ThinkingLevel[];\n\tonMemoryEnabledChange: (enabled: boolean) => void;\n\tonMemoryCharCapChange: (cap: number) => void;\n\tonSearchCuratorChange: (setting: SearchCuratorSetting) => void;\n\t// lunr: TUI customize callbacks\n\tonFooterMcpChange: (enabled: boolean) => void;\n\tonFooterLspChange: (enabled: boolean) => void;\n\tonFooterContextChange: (enabled: boolean) => void;\n\tonFooterTokensChange: (enabled: boolean) => void;\n\tonFooterCacheHitRateChange: (enabled: boolean) => void;\n\tonFooterTpsChange: (enabled: boolean) => void;\n\tonFooterStatusesChange: (enabled: boolean) => void;\n\tonFooterGitChange: (enabled: boolean) => void;\n\tonFooterPlanChange: (enabled: boolean) => void;\n\tonFooterPlanBarChange: (enabled: boolean) => void;\n\tonPlanUsageWindowChange: (window: \"5h\" | \"weekly\") => 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: \"Fast, low-cost model for simple subagent tasks\",\n\t},\n\t{\n\t\ttier: \"standard\",\n\t\tlabel: \"Standard tier model\",\n\t\tdescription: \"Balanced model for everyday coding tasks\",\n\t},\n\t{\n\t\ttier: \"heavy\",\n\t\tlabel: \"Heavy tier model\",\n\t\tdescription: \"Strong model for complex reasoning and debugging\",\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: {\n\t\tenabled: boolean;\n\t\tlight?: string;\n\t\tstandard?: string;\n\t\theavy?: string;\n\t\tlightThinking?: ThinkingLevel;\n\t\tstandardThinking?: ThinkingLevel;\n\t\theavyThinking?: ThinkingLevel;\n\t};\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\tlightThinking: modelTiers.lightThinking,\n\t\t\tstandardThinking: modelTiers.standardThinking,\n\t\t\theavyThinking: modelTiers.heavyThinking,\n\t\t};\n\n\t\tconst thinkingKey = (tier: ModelTierName): \"lightThinking\" | \"standardThinking\" | \"heavyThinking\" =>\n\t\t\ttier === \"light\" ? \"lightThinking\" : tier === \"standard\" ? \"standardThinking\" : \"heavyThinking\";\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: \"Route subagent work by model tier\",\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.flatMap((row): SettingItem[] => {\n\t\t\t\tconst tier = row.tier;\n\t\t\t\tconst tKey = thinkingKey(tier);\n\t\t\t\treturn [\n\t\t\t\t\t{\n\t\t\t\t\t\tid: tier,\n\t\t\t\t\t\tlabel: row.label,\n\t\t\t\t\t\tdescription: row.description,\n\t\t\t\t\t\tcurrentValue: this.state[tier] ?? \"not set\",\n\t\t\t\t\t\tdisabled: () => !this.state.enabled,\n\t\t\t\t\t\tsubmenu: (_currentValue, done) => callbacks.createModelTierPicker(tier, this.state[tier], done),\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tid: `${tier}-thinking`,\n\t\t\t\t\t\tlabel: `${row.label.replace(\" model\", \"\")} thinking`,\n\t\t\t\t\t\tdescription: \"Reasoning level for this tier\",\n\t\t\t\t\t\tcurrentValue: this.state[tKey] ?? \"inherit\",\n\t\t\t\t\t\tdisabled: () => !this.state.enabled,\n\t\t\t\t\t\tsubmenu: (_currentValue, done) =>\n\t\t\t\t\t\t\tnew SelectSubmenu(\n\t\t\t\t\t\t\t\t`${row.label} thinking`,\n\t\t\t\t\t\t\t\t\"Inherit uses the parent session's reasoning level\",\n\t\t\t\t\t\t\t\t[\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\tvalue: \"inherit\",\n\t\t\t\t\t\t\t\t\t\tlabel: \"inherit\",\n\t\t\t\t\t\t\t\t\t\tdescription: \"Use the parent session's reasoning level\",\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t...callbacks.getTierThinkingLevels(tier).map((level) => ({\n\t\t\t\t\t\t\t\t\t\tvalue: level,\n\t\t\t\t\t\t\t\t\t\tlabel: level,\n\t\t\t\t\t\t\t\t\t\tdescription: THINKING_DESCRIPTIONS[level],\n\t\t\t\t\t\t\t\t\t})),\n\t\t\t\t\t\t\t\t],\n\t\t\t\t\t\t\t\tthis.state[tKey] ?? \"inherit\",\n\t\t\t\t\t\t\t\t(value) => {\n\t\t\t\t\t\t\t\t\tcallbacks.onModelTierThinkingChange(\n\t\t\t\t\t\t\t\t\t\ttier,\n\t\t\t\t\t\t\t\t\t\tvalue === \"inherit\" ? undefined : (value as ThinkingLevel),\n\t\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\t\tdone(value);\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t() => done(),\n\t\t\t\t\t\t\t),\n\t\t\t\t\t},\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\tif (id.endsWith(\"-thinking\")) {\n\t\t\t\t\tconst tier = id.slice(0, -\"-thinking\".length) as ModelTierName;\n\t\t\t\t\tconst tKey = thinkingKey(tier);\n\t\t\t\t\tthis.state[tKey] = newValue === \"inherit\" ? undefined : (newValue as ThinkingLevel);\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`Maximum agent memory size (${MEMORY_CHAR_CAP_MIN} to ${MEMORY_CHAR_CAP_MAX} characters, 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: \"footer-mcp\",\n\t\t\t\tlabel: \"MCP status\",\n\t\t\t\tdescription: \"MCP server status\",\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: \"LSP status\",\n\t\t\t\tdescription: \"Language server status\",\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: \"Context meter\",\n\t\t\t\tdescription: \"Context usage\",\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: \"Token counter\",\n\t\t\t\tdescription: \"Input and output token counts\",\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-cache-hit-rate\",\n\t\t\t\tlabel: \"Cache hit rate\",\n\t\t\t\tdescription: \"Latest prompt cache hit rate\",\n\t\t\t\tcurrentValue: (bridge?.getFooterCacheHitRate() ?? true) ? \"on\" : \"off\",\n\t\t\t\tvalues: [\"on\", \"off\"],\n\t\t\t},\n\t\t\t{\n\t\t\t\tid: \"footer-tps\",\n\t\t\t\tlabel: \"TPS counter\",\n\t\t\t\tdescription: \"Token generation speed\",\n\t\t\t\tcurrentValue: (bridge?.getFooterTps() ?? 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: \"Feature statuses\",\n\t\t\t\tdescription: \"Active plan, goal, and swarm status\",\n\t\t\t\tcurrentValue: (bridge?.getFooterStatuses() ?? true) ? \"on\" : \"off\",\n\t\t\t\tvalues: [\"on\", \"off\"],\n\t\t\t},\n\t\t\t{\n\t\t\t\tid: \"footer-git\",\n\t\t\t\tlabel: \"Git branch\",\n\t\t\t\tdescription: \"Git branch and line changes\",\n\t\t\t\tcurrentValue: (bridge?.getFooterGit() ?? true) ? \"on\" : \"off\",\n\t\t\t\tvalues: [\"on\", \"off\"],\n\t\t\t},\n\t\t\t{\n\t\t\t\tid: \"footer-plan\",\n\t\t\t\tlabel: \"Plan usage\",\n\t\t\t\tdescription: \"Subscription usage percentage\",\n\t\t\t\tcurrentValue: (bridge?.getFooterPlan() ?? true) ? \"on\" : \"off\",\n\t\t\t\tvalues: [\"on\", \"off\"],\n\t\t\t},\n\t\t\t{\n\t\t\t\tid: \"footer-plan-bar\",\n\t\t\t\tlabel: \"Plan bar\",\n\t\t\t\tdescription: \"Bar beside the subscription usage percentage\",\n\t\t\t\tcurrentValue: (bridge?.getFooterPlanBar() ?? 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 \"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-cache-hit-rate\":\n\t\t\t\t\t\tcallbacks.onFooterCacheHitRateChange(newValue === \"on\");\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase \"footer-tps\":\n\t\t\t\t\t\tcallbacks.onFooterTpsChange(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\tcase \"footer-git\":\n\t\t\t\t\t\tcallbacks.onFooterGitChange(newValue === \"on\");\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase \"footer-plan\":\n\t\t\t\t\t\tcallbacks.onFooterPlanChange(newValue === \"on\");\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase \"footer-plan-bar\":\n\t\t\t\t\t\tcallbacks.onFooterPlanBarChange(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: `Save file snapshots for /rollback${sessionForceEnabled ? \". Always on in 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: \"Number of turns kept for rollback\",\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: \"How rollback snapshots are stored\",\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\"Snapshot storage method\",\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: \"File copies for tool edits and 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: \"Track files created outside tools with 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: \"Reserved mode; currently 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: \"Which file changes rollback tracks\",\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\"File changes included in snapshots\",\n\t\t\t\t\t\t[\n\t\t\t\t\t\t\t{ value: \"tools\", label: \"tools\", description: \"Changes made by edit and write tools\" },\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: \"Tool and shell changes across the repository\",\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\", \"Number of turns kept for rollback (1 to 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? \"Turn off automatic key rotation to switch keys\"\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: \"Change the key's display name\",\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: \"Unavailable until the key is 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 stored key\",\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`Delete \"${row.name}\" from ${row.providerName}? The last key also logs out the provider.`,\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: \"Follow the terminal's light or dark 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\"Choose a theme or 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\", \"Use different themes for light and dark terminals.\"), 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 for light terminals\",\n\t\t\t\tcurrentValue: this.lightTheme,\n\t\t\t\tsubmenu: (currentValue, done) =>\n\t\t\t\t\tthis.createThemeSelect(\"Light Theme\", \"Theme for light terminals\", currentValue, done, (value) => {\n\t\t\t\t\t\tthis.lightTheme = value;\n\t\t\t\t\t\tthis.callbacks.onThemePreview?.(this.getThemeSetting());\n\t\t\t\t\t\tdone(value);\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 for dark terminals\",\n\t\t\t\tcurrentValue: this.darkTheme,\n\t\t\t\tsubmenu: (currentValue, done) =>\n\t\t\t\t\tthis.createThemeSelect(\"Dark Theme\", \"Theme for dark terminals\", currentValue, done, (value) => {\n\t\t\t\t\t\tthis.darkTheme = value;\n\t\t\t\t\t\tthis.callbacks.onThemePreview?.(this.getThemeSetting());\n\t\t\t\t\t\tdone(value);\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 theme settings\",\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: \"Use one theme for all terminal appearances\",\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: \"Compact context before it reaches the model limit\",\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: \"How new messages interrupt a streaming response\",\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: `How ${followUpKey} messages run after the current response`,\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: \"Connection method for supported providers\",\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: \"Time before an inactive HTTP request times out\",\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: \"Thinking block visibility\",\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: \"Short summaries for completed thinking\",\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: \"Prompt cache miss notices in the transcript\",\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 lifetime\",\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: \"Startup log visibility\",\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: \"Typewriter-style response streaming\",\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: \"agent-memory\",\n\t\t\t\tlabel: \"Agent memory\",\n\t\t\t\tdescription: \"Durable facts the agent can manage\",\n\t\t\t\tcurrentValue: config.memoryEnabled ? \"on\" : \"off\",\n\t\t\t\tvalues: [\"on\", \"off\"],\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: \"Maximum agent memory size\",\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? \"Web search review and summary mode\"\n\t\t\t\t\t: \"Unavailable because web access is not loaded\",\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: \"How long session files are kept\",\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: \"Trust choice when a project has no saved decision\",\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: \"Starting permission mode for new sessions\",\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 for double Escape in an 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 /tree filter\",\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 level for supported 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\"Reasoning level for supported 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: \"Interface color theme\",\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: \"Subagent model routing\",\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{\n\t\t\t\tid: \"plan-usage-window\",\n\t\t\t\tlabel: \"Plan usage window\",\n\t\t\t\tdescription: \"Subscription usage period shown in the footer\",\n\t\t\t\tcurrentValue: config.planUsageWindow,\n\t\t\t\tvalues: [\"5h\", \"weekly\"],\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: \"Interface and footer options\",\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: \"Rollback behavior options\",\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: \"Automatic API key rotation after usage limits\",\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: \"Saved API key management\",\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: \"Inline terminal image rendering\",\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: \"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: \"Limit images to 2000 x 2000 pixels\",\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 reaching model 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: \"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// Skill tag character (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: \"skill-tag-character\",\n\t\t\tlabel: \"Skill tag\",\n\t\t\tdescription: \"After a space, this character lists skills to tag in the message\",\n\t\t\tcurrentValue: config.skillTagCharacter,\n\t\t\tvalues: [...SKILL_TAG_CHARACTERS],\n\t\t});\n\n\t\t// Hardware cursor toggle (insert after skill-tag-character)\n\t\tconst skillTagIndex = items.findIndex((item) => item.id === \"skill-tag-character\");\n\t\titems.splice(skillTagIndex + 1, 0, {\n\t\t\tid: \"show-hardware-cursor\",\n\t\t\tlabel: \"Show hardware cursor\",\n\t\t\tdescription: \"Terminal cursor for input method editors\",\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 editor padding\",\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 message padding\",\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: \"Visible autocomplete items\",\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 leftover terminal rows when content shrinks\",\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: \"Progress in supported terminal tabs\",\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 \"skill-tag-character\":\n\t\t\t\t\t\tcallbacks.onSkillTagCharacterChange(newValue as SkillTagCharacter);\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 \"plan-usage-window\":\n\t\t\t\t\t\tcallbacks.onPlanUsageWindowChange(newValue === \"5h\" ? \"5h\" : \"weekly\");\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 \"agent-memory\":\n\t\t\t\t\t\tcallbacks.onMemoryEnabledChange(newValue === \"on\");\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 {\n\ttype DefaultPermissionMode,\n\ttype DefaultProjectTrust,\n\ttype ModelInstructionsSettings,\n\ttype ModelTierName,\n\ttype ModelTiersSettings,\n\ttype RollbackCapture,\n\ttype RollbackScope,\n\tSKILL_TAG_CHARACTERS,\n\ttype SkillTagCharacter,\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\tskillTagCharacter: SkillTagCharacter;\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\tmodelInstructions: Required<ModelInstructionsSettings>;\n\tglobalInstructionsPath: string;\n\tmodelInstructionsPath: string;\n\tconfirmLargeSubagentLaunches: boolean;\n\tmemoryEnabled: boolean;\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\tfooterMcp: boolean;\n\tfooterLsp: boolean;\n\tfooterContext: boolean;\n\tfooterTokens: boolean;\n\tfooterCacheHitRate: boolean;\n\tfooterTps: boolean;\n\tfooterStatuses: boolean;\n\tfooterGit: boolean;\n\tfooterPlan: boolean;\n\tfooterPlanBar: boolean;\n\tplanUsageWindow: \"5h\" | \"weekly\";\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\tonSkillTagCharacterChange: (character: SkillTagCharacter) => 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\tonModelTierThinkingChange: (tier: ModelTierName, level: ThinkingLevel | undefined) => void;\n\tonModelInstructionsEnabledChange: (enabled: boolean) => void;\n\tonModelInstructionsModeChange: (mode: \"both\" | \"model-only\") => void;\n\tonConfirmLargeSubagentLaunchesChange: (enabled: boolean) => void;\n\tgetTierThinkingLevels: (tier: ModelTierName) => ThinkingLevel[];\n\tonMemoryEnabledChange: (enabled: boolean) => void;\n\tonMemoryCharCapChange: (cap: number) => void;\n\tonSearchCuratorChange: (setting: SearchCuratorSetting) => void;\n\t// lunr: TUI customize callbacks\n\tonFooterMcpChange: (enabled: boolean) => void;\n\tonFooterLspChange: (enabled: boolean) => void;\n\tonFooterContextChange: (enabled: boolean) => void;\n\tonFooterTokensChange: (enabled: boolean) => void;\n\tonFooterCacheHitRateChange: (enabled: boolean) => void;\n\tonFooterTpsChange: (enabled: boolean) => void;\n\tonFooterStatusesChange: (enabled: boolean) => void;\n\tonFooterGitChange: (enabled: boolean) => void;\n\tonFooterPlanChange: (enabled: boolean) => void;\n\tonFooterPlanBarChange: (enabled: boolean) => void;\n\tonPlanUsageWindowChange: (window: \"5h\" | \"weekly\") => 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: \"Fast, low-cost model for simple subagent tasks\",\n\t},\n\t{\n\t\ttier: \"standard\",\n\t\tlabel: \"Standard tier model\",\n\t\tdescription: \"Balanced model for everyday coding tasks\",\n\t},\n\t{\n\t\ttier: \"heavy\",\n\t\tlabel: \"Heavy tier model\",\n\t\tdescription: \"Strong model for complex reasoning and debugging\",\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: {\n\t\tenabled: boolean;\n\t\tlight?: string;\n\t\tstandard?: string;\n\t\theavy?: string;\n\t\tlightThinking?: ThinkingLevel;\n\t\tstandardThinking?: ThinkingLevel;\n\t\theavyThinking?: ThinkingLevel;\n\t};\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\tlightThinking: modelTiers.lightThinking,\n\t\t\tstandardThinking: modelTiers.standardThinking,\n\t\t\theavyThinking: modelTiers.heavyThinking,\n\t\t};\n\n\t\tconst thinkingKey = (tier: ModelTierName): \"lightThinking\" | \"standardThinking\" | \"heavyThinking\" =>\n\t\t\ttier === \"light\" ? \"lightThinking\" : tier === \"standard\" ? \"standardThinking\" : \"heavyThinking\";\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: \"Route subagent work by model tier\",\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.flatMap((row): SettingItem[] => {\n\t\t\t\tconst tier = row.tier;\n\t\t\t\tconst tKey = thinkingKey(tier);\n\t\t\t\treturn [\n\t\t\t\t\t{\n\t\t\t\t\t\tid: tier,\n\t\t\t\t\t\tlabel: row.label,\n\t\t\t\t\t\tdescription: row.description,\n\t\t\t\t\t\tcurrentValue: this.state[tier] ?? \"not set\",\n\t\t\t\t\t\tdisabled: () => !this.state.enabled,\n\t\t\t\t\t\tsubmenu: (_currentValue, done) => callbacks.createModelTierPicker(tier, this.state[tier], done),\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tid: `${tier}-thinking`,\n\t\t\t\t\t\tlabel: `${row.label.replace(\" model\", \"\")} thinking`,\n\t\t\t\t\t\tdescription: \"Reasoning level for this tier\",\n\t\t\t\t\t\tcurrentValue: this.state[tKey] ?? \"inherit\",\n\t\t\t\t\t\tdisabled: () => !this.state.enabled,\n\t\t\t\t\t\tsubmenu: (_currentValue, done) =>\n\t\t\t\t\t\t\tnew SelectSubmenu(\n\t\t\t\t\t\t\t\t`${row.label} thinking`,\n\t\t\t\t\t\t\t\t\"Inherit uses the parent session's reasoning level\",\n\t\t\t\t\t\t\t\t[\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\tvalue: \"inherit\",\n\t\t\t\t\t\t\t\t\t\tlabel: \"inherit\",\n\t\t\t\t\t\t\t\t\t\tdescription: \"Use the parent session's reasoning level\",\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t...callbacks.getTierThinkingLevels(tier).map((level) => ({\n\t\t\t\t\t\t\t\t\t\tvalue: level,\n\t\t\t\t\t\t\t\t\t\tlabel: level,\n\t\t\t\t\t\t\t\t\t\tdescription: THINKING_DESCRIPTIONS[level],\n\t\t\t\t\t\t\t\t\t})),\n\t\t\t\t\t\t\t\t],\n\t\t\t\t\t\t\t\tthis.state[tKey] ?? \"inherit\",\n\t\t\t\t\t\t\t\t(value) => {\n\t\t\t\t\t\t\t\t\tcallbacks.onModelTierThinkingChange(\n\t\t\t\t\t\t\t\t\t\ttier,\n\t\t\t\t\t\t\t\t\t\tvalue === \"inherit\" ? undefined : (value as ThinkingLevel),\n\t\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\t\tdone(value);\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t() => done(),\n\t\t\t\t\t\t\t),\n\t\t\t\t\t},\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\tif (id.endsWith(\"-thinking\")) {\n\t\t\t\t\tconst tier = id.slice(0, -\"-thinking\".length) as ModelTierName;\n\t\t\t\t\tconst tKey = thinkingKey(tier);\n\t\t\t\t\tthis.state[tKey] = newValue === \"inherit\" ? undefined : (newValue as ThinkingLevel);\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\nclass ModelInstructionsSubmenu extends Container {\n\tprivate settingsList: SettingsList;\n\n\tconstructor(config: SettingsConfig, callbacks: SettingsCallbacks, done: (selectedValue?: string) => void) {\n\t\tsuper();\n\t\tconst state = { ...config.modelInstructions };\n\t\tconst items: SettingItem[] = [\n\t\t\t{\n\t\t\t\tid: \"enabled\",\n\t\t\t\tlabel: \"Model instructions\",\n\t\t\t\tdescription: \"Load instructions for the selected model\",\n\t\t\t\tcurrentValue: state.enabled ? \"on\" : \"off\",\n\t\t\t\tvalues: [\"on\", \"off\"],\n\t\t\t},\n\t\t\t{\n\t\t\t\tid: \"mode\",\n\t\t\t\tlabel: \"Instruction mode\",\n\t\t\t\tdescription: \"Load global and model instructions, or model only\",\n\t\t\t\tcurrentValue: state.mode,\n\t\t\t\tvalues: [\"both\", \"model-only\"],\n\t\t\t\tdisabled: () => !state.enabled,\n\t\t\t},\n\t\t];\n\t\tthis.addChild(new Text(theme.bold(theme.fg(\"accent\", \"Model Instructions\")), 0, 0));\n\t\tthis.addChild(new Spacer(1));\n\t\tthis.settingsList = new SettingsList(\n\t\t\titems,\n\t\t\titems.length,\n\t\t\tgetSettingsListTheme(),\n\t\t\t(id, value) => {\n\t\t\t\tif (id === \"enabled\") {\n\t\t\t\t\tstate.enabled = value === \"on\";\n\t\t\t\t\tcallbacks.onModelInstructionsEnabledChange(state.enabled);\n\t\t\t\t} else if (id === \"mode\") {\n\t\t\t\t\tstate.mode = value === \"model-only\" ? \"model-only\" : \"both\";\n\t\t\t\t\tcallbacks.onModelInstructionsModeChange(state.mode);\n\t\t\t\t}\n\t\t\t},\n\t\t\t() => done(state.enabled ? \"on\" : \"off\"),\n\t\t);\n\t\tthis.addChild(this.settingsList);\n\t\tthis.addChild(new Spacer(1));\n\t\tthis.addChild(new Text(theme.fg(\"muted\", `Global: ${config.globalInstructionsPath}`), 0, 0));\n\t\tthis.addChild(new Text(theme.fg(\"muted\", `Current model: ${config.modelInstructionsPath}`), 0, 0));\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`Maximum agent memory size (${MEMORY_CHAR_CAP_MIN} to ${MEMORY_CHAR_CAP_MAX} characters, 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: \"footer-mcp\",\n\t\t\t\tlabel: \"MCP status\",\n\t\t\t\tdescription: \"MCP server status\",\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: \"LSP status\",\n\t\t\t\tdescription: \"Language server status\",\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: \"Context meter\",\n\t\t\t\tdescription: \"Context usage\",\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: \"Token counter\",\n\t\t\t\tdescription: \"Input and output token counts\",\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-cache-hit-rate\",\n\t\t\t\tlabel: \"Cache hit rate\",\n\t\t\t\tdescription: \"Latest prompt cache hit rate\",\n\t\t\t\tcurrentValue: (bridge?.getFooterCacheHitRate() ?? true) ? \"on\" : \"off\",\n\t\t\t\tvalues: [\"on\", \"off\"],\n\t\t\t},\n\t\t\t{\n\t\t\t\tid: \"footer-tps\",\n\t\t\t\tlabel: \"TPS counter\",\n\t\t\t\tdescription: \"Token generation speed\",\n\t\t\t\tcurrentValue: (bridge?.getFooterTps() ?? 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: \"Feature statuses\",\n\t\t\t\tdescription: \"Active plan and goal status\",\n\t\t\t\tcurrentValue: (bridge?.getFooterStatuses() ?? true) ? \"on\" : \"off\",\n\t\t\t\tvalues: [\"on\", \"off\"],\n\t\t\t},\n\t\t\t{\n\t\t\t\tid: \"footer-git\",\n\t\t\t\tlabel: \"Git branch\",\n\t\t\t\tdescription: \"Git branch and line changes\",\n\t\t\t\tcurrentValue: (bridge?.getFooterGit() ?? true) ? \"on\" : \"off\",\n\t\t\t\tvalues: [\"on\", \"off\"],\n\t\t\t},\n\t\t\t{\n\t\t\t\tid: \"footer-plan\",\n\t\t\t\tlabel: \"Plan usage\",\n\t\t\t\tdescription: \"Subscription usage percentage\",\n\t\t\t\tcurrentValue: (bridge?.getFooterPlan() ?? true) ? \"on\" : \"off\",\n\t\t\t\tvalues: [\"on\", \"off\"],\n\t\t\t},\n\t\t\t{\n\t\t\t\tid: \"footer-plan-bar\",\n\t\t\t\tlabel: \"Plan bar\",\n\t\t\t\tdescription: \"Bar beside the subscription usage percentage\",\n\t\t\t\tcurrentValue: (bridge?.getFooterPlanBar() ?? 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 \"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-cache-hit-rate\":\n\t\t\t\t\t\tcallbacks.onFooterCacheHitRateChange(newValue === \"on\");\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase \"footer-tps\":\n\t\t\t\t\t\tcallbacks.onFooterTpsChange(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\tcase \"footer-git\":\n\t\t\t\t\t\tcallbacks.onFooterGitChange(newValue === \"on\");\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase \"footer-plan\":\n\t\t\t\t\t\tcallbacks.onFooterPlanChange(newValue === \"on\");\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase \"footer-plan-bar\":\n\t\t\t\t\t\tcallbacks.onFooterPlanBarChange(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: `Save file snapshots for /rollback${sessionForceEnabled ? \". Always on in 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: \"Number of turns kept for rollback\",\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: \"How rollback snapshots are stored\",\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\"Snapshot storage method\",\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: \"File copies for tool edits and 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: \"Track files created outside tools with 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: \"Reserved mode; currently 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: \"Which file changes rollback tracks\",\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\"File changes included in snapshots\",\n\t\t\t\t\t\t[\n\t\t\t\t\t\t\t{ value: \"tools\", label: \"tools\", description: \"Changes made by edit and write tools\" },\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: \"Tool and shell changes across the repository\",\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\", \"Number of turns kept for rollback (1 to 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? \"Turn off automatic key rotation to switch keys\"\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: \"Change the key's display name\",\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: \"Unavailable until the key is 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 stored key\",\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`Delete \"${row.name}\" from ${row.providerName}? The last key also logs out the provider.`,\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: \"Follow the terminal's light or dark 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\"Choose a theme or 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\", \"Use different themes for light and dark terminals.\"), 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 for light terminals\",\n\t\t\t\tcurrentValue: this.lightTheme,\n\t\t\t\tsubmenu: (currentValue, done) =>\n\t\t\t\t\tthis.createThemeSelect(\"Light Theme\", \"Theme for light terminals\", currentValue, done, (value) => {\n\t\t\t\t\t\tthis.lightTheme = value;\n\t\t\t\t\t\tthis.callbacks.onThemePreview?.(this.getThemeSetting());\n\t\t\t\t\t\tdone(value);\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 for dark terminals\",\n\t\t\t\tcurrentValue: this.darkTheme,\n\t\t\t\tsubmenu: (currentValue, done) =>\n\t\t\t\t\tthis.createThemeSelect(\"Dark Theme\", \"Theme for dark terminals\", currentValue, done, (value) => {\n\t\t\t\t\t\tthis.darkTheme = value;\n\t\t\t\t\t\tthis.callbacks.onThemePreview?.(this.getThemeSetting());\n\t\t\t\t\t\tdone(value);\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 theme settings\",\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: \"Use one theme for all terminal appearances\",\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: \"Compact context before it reaches the model limit\",\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: \"How new messages interrupt a streaming response\",\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: `How ${followUpKey} messages run after the current response`,\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: \"Connection method for supported providers\",\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: \"Time before an inactive HTTP request times out\",\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: \"Thinking block visibility\",\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: \"Short summaries for completed thinking\",\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: \"Prompt cache miss notices in the transcript\",\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 lifetime\",\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: \"Startup log visibility\",\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: \"Typewriter-style response streaming\",\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: \"agent-memory\",\n\t\t\t\tlabel: \"Agent memory\",\n\t\t\t\tdescription: \"Durable facts the agent can manage\",\n\t\t\t\tcurrentValue: config.memoryEnabled ? \"on\" : \"off\",\n\t\t\t\tvalues: [\"on\", \"off\"],\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: \"Maximum agent memory size\",\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? \"Web search review and summary mode\"\n\t\t\t\t\t: \"Unavailable because web access is not loaded\",\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: \"How long session files are kept\",\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: \"Trust choice when a project has no saved decision\",\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: \"Starting permission mode for new sessions\",\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 for double Escape in an 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 /tree filter\",\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 level for supported 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\"Reasoning level for supported 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: \"Interface color theme\",\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: \"Subagent model routing\",\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{\n\t\t\t\tid: \"model-instructions\",\n\t\t\t\tlabel: \"Model instructions\",\n\t\t\t\tdescription: \"Global and selected-model AGENTS.md loading\",\n\t\t\t\tcurrentValue: config.modelInstructions.enabled ? \"on\" : \"off\",\n\t\t\t\tsubmenu: (_currentValue, done) => new ModelInstructionsSubmenu(config, callbacks, done),\n\t\t\t},\n\t\t\t{\n\t\t\t\tid: \"confirm-large-subagent-launches\",\n\t\t\t\tlabel: \"Confirm large subagent launches\",\n\t\t\t\tdescription: \"Confirm 3+ children; Auto bypasses confirmation\",\n\t\t\t\tcurrentValue: config.confirmLargeSubagentLaunches ? \"on\" : \"off\",\n\t\t\t\tvalues: [\"on\", \"off\"],\n\t\t\t},\n\t\t\t{\n\t\t\t\tid: \"plan-usage-window\",\n\t\t\t\tlabel: \"Plan usage window\",\n\t\t\t\tdescription: \"Subscription usage period shown in the footer\",\n\t\t\t\tcurrentValue: config.planUsageWindow,\n\t\t\t\tvalues: [\"5h\", \"weekly\"],\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: \"Interface and footer options\",\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: \"Rollback behavior options\",\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: \"Automatic API key rotation after usage limits\",\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: \"Saved API key management\",\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: \"Inline terminal image rendering\",\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: \"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: \"Limit images to 2000 x 2000 pixels\",\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 reaching model 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: \"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// Skill tag character (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: \"skill-tag-character\",\n\t\t\tlabel: \"Skill tag\",\n\t\t\tdescription: \"After a space, this character lists skills to tag in the message\",\n\t\t\tcurrentValue: config.skillTagCharacter,\n\t\t\tvalues: [...SKILL_TAG_CHARACTERS],\n\t\t});\n\n\t\t// Hardware cursor toggle (insert after skill-tag-character)\n\t\tconst skillTagIndex = items.findIndex((item) => item.id === \"skill-tag-character\");\n\t\titems.splice(skillTagIndex + 1, 0, {\n\t\t\tid: \"show-hardware-cursor\",\n\t\t\tlabel: \"Show hardware cursor\",\n\t\t\tdescription: \"Terminal cursor for input method editors\",\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 editor padding\",\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 message padding\",\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: \"Visible autocomplete items\",\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 leftover terminal rows when content shrinks\",\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: \"Progress in supported terminal tabs\",\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 \"skill-tag-character\":\n\t\t\t\t\t\tcallbacks.onSkillTagCharacterChange(newValue as SkillTagCharacter);\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 \"plan-usage-window\":\n\t\t\t\t\t\tcallbacks.onPlanUsageWindowChange(newValue === \"5h\" ? \"5h\" : \"weekly\");\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 \"agent-memory\":\n\t\t\t\t\t\tcallbacks.onMemoryEnabledChange(newValue === \"on\");\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 \"confirm-large-subagent-launches\":\n\t\t\t\t\t\tcallbacks.onConfirmLargeSubagentLaunchesChange(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"]}
|
|
@@ -128,6 +128,49 @@ class ModelTiersSubmenu extends Container {
|
|
|
128
128
|
this.settingsList.handleInput(data);
|
|
129
129
|
}
|
|
130
130
|
}
|
|
131
|
+
class ModelInstructionsSubmenu extends Container {
|
|
132
|
+
settingsList;
|
|
133
|
+
constructor(config, callbacks, done) {
|
|
134
|
+
super();
|
|
135
|
+
const state = { ...config.modelInstructions };
|
|
136
|
+
const items = [
|
|
137
|
+
{
|
|
138
|
+
id: "enabled",
|
|
139
|
+
label: "Model instructions",
|
|
140
|
+
description: "Load instructions for the selected model",
|
|
141
|
+
currentValue: state.enabled ? "on" : "off",
|
|
142
|
+
values: ["on", "off"],
|
|
143
|
+
},
|
|
144
|
+
{
|
|
145
|
+
id: "mode",
|
|
146
|
+
label: "Instruction mode",
|
|
147
|
+
description: "Load global and model instructions, or model only",
|
|
148
|
+
currentValue: state.mode,
|
|
149
|
+
values: ["both", "model-only"],
|
|
150
|
+
disabled: () => !state.enabled,
|
|
151
|
+
},
|
|
152
|
+
];
|
|
153
|
+
this.addChild(new Text(theme.bold(theme.fg("accent", "Model Instructions")), 0, 0));
|
|
154
|
+
this.addChild(new Spacer(1));
|
|
155
|
+
this.settingsList = new SettingsList(items, items.length, getSettingsListTheme(), (id, value) => {
|
|
156
|
+
if (id === "enabled") {
|
|
157
|
+
state.enabled = value === "on";
|
|
158
|
+
callbacks.onModelInstructionsEnabledChange(state.enabled);
|
|
159
|
+
}
|
|
160
|
+
else if (id === "mode") {
|
|
161
|
+
state.mode = value === "model-only" ? "model-only" : "both";
|
|
162
|
+
callbacks.onModelInstructionsModeChange(state.mode);
|
|
163
|
+
}
|
|
164
|
+
}, () => done(state.enabled ? "on" : "off"));
|
|
165
|
+
this.addChild(this.settingsList);
|
|
166
|
+
this.addChild(new Spacer(1));
|
|
167
|
+
this.addChild(new Text(theme.fg("muted", `Global: ${config.globalInstructionsPath}`), 0, 0));
|
|
168
|
+
this.addChild(new Text(theme.fg("muted", `Current model: ${config.modelInstructionsPath}`), 0, 0));
|
|
169
|
+
}
|
|
170
|
+
handleInput(data) {
|
|
171
|
+
this.settingsList.handleInput(data);
|
|
172
|
+
}
|
|
173
|
+
}
|
|
131
174
|
/**
|
|
132
175
|
* Numeric input submenu for the simple-pi-memory character cap.
|
|
133
176
|
* Enter validates and applies via done(newValue); Esc cancels.
|
|
@@ -216,7 +259,7 @@ class CustomizeSubmenu extends Container {
|
|
|
216
259
|
{
|
|
217
260
|
id: "footer-statuses",
|
|
218
261
|
label: "Feature statuses",
|
|
219
|
-
description: "Active plan
|
|
262
|
+
description: "Active plan and goal status",
|
|
220
263
|
currentValue: (bridge?.getFooterStatuses() ?? true) ? "on" : "off",
|
|
221
264
|
values: ["on", "off"],
|
|
222
265
|
},
|
|
@@ -975,6 +1018,20 @@ export class SettingsSelectorComponent extends Container {
|
|
|
975
1018
|
currentValue: config.modelTiers.enabled ? "on" : "off",
|
|
976
1019
|
submenu: (currentValue, done) => new ModelTiersSubmenu(currentValue, config.modelTiers, callbacks, done),
|
|
977
1020
|
},
|
|
1021
|
+
{
|
|
1022
|
+
id: "model-instructions",
|
|
1023
|
+
label: "Model instructions",
|
|
1024
|
+
description: "Global and selected-model AGENTS.md loading",
|
|
1025
|
+
currentValue: config.modelInstructions.enabled ? "on" : "off",
|
|
1026
|
+
submenu: (_currentValue, done) => new ModelInstructionsSubmenu(config, callbacks, done),
|
|
1027
|
+
},
|
|
1028
|
+
{
|
|
1029
|
+
id: "confirm-large-subagent-launches",
|
|
1030
|
+
label: "Confirm large subagent launches",
|
|
1031
|
+
description: "Confirm 3+ children; Auto bypasses confirmation",
|
|
1032
|
+
currentValue: config.confirmLargeSubagentLaunches ? "on" : "off",
|
|
1033
|
+
values: ["on", "off"],
|
|
1034
|
+
},
|
|
978
1035
|
{
|
|
979
1036
|
id: "plan-usage-window",
|
|
980
1037
|
label: "Plan usage window",
|
|
@@ -1238,6 +1295,9 @@ export class SettingsSelectorComponent extends Container {
|
|
|
1238
1295
|
case "auto-manage-subscriptions":
|
|
1239
1296
|
callbacks.onAutoManageSubscriptionsChange(newValue === "on");
|
|
1240
1297
|
break;
|
|
1298
|
+
case "confirm-large-subagent-launches":
|
|
1299
|
+
callbacks.onConfirmLargeSubagentLaunchesChange(newValue === "on");
|
|
1300
|
+
break;
|
|
1241
1301
|
case "theme":
|
|
1242
1302
|
callbacks.onThemeChange(newValue);
|
|
1243
1303
|
break;
|