@ashx-j/lunr 0.2.13 → 0.2.15
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/CHANGELOG.md +27 -1
- package/README.md +10 -7
- package/dist/builtin-extensions/ashxj-tui.d.ts +16 -1
- package/dist/builtin-extensions/ashxj-tui.d.ts.map +1 -1
- package/dist/builtin-extensions/ashxj-tui.js +48 -24
- 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 +2 -0
- package/dist/builtin-extensions/pi-subagents/src/extension/index.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/extension/index.js +29 -23
- 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 +9 -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 +16 -3
- 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 +1 -0
- 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 +7 -4
- package/dist/builtin-extensions/pi-subagents/src/runs/background/async-status.js.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/runs/background/chain-append.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/runs/background/chain-append.js +1 -0
- package/dist/builtin-extensions/pi-subagents/src/runs/background/chain-append.js.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/runs/background/chain-root-attachment.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/runs/background/chain-root-attachment.js +3 -0
- package/dist/builtin-extensions/pi-subagents/src/runs/background/chain-root-attachment.js.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/runs/background/fleet-view.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/runs/background/fleet-view.js +3 -3
- package/dist/builtin-extensions/pi-subagents/src/runs/background/fleet-view.js.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/runs/background/run-status.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/runs/background/run-status.js +2 -2
- package/dist/builtin-extensions/pi-subagents/src/runs/background/run-status.js.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/runs/background/subagent-runner.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/runs/background/subagent-runner.js +3 -0
- package/dist/builtin-extensions/pi-subagents/src/runs/background/subagent-runner.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 +7 -8
- package/dist/builtin-extensions/pi-subagents/src/runs/foreground/chain-execution.js.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/runs/foreground/execution.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/runs/foreground/execution.js +2 -0
- package/dist/builtin-extensions/pi-subagents/src/runs/foreground/execution.js.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/runs/foreground/subagent-executor.d.ts +1 -0
- 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 +20 -21
- 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 +12 -1
- 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 +42 -17
- 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 +2 -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 +2 -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 +23 -1
- 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 +3 -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 +15 -4
- package/dist/builtin-extensions/pi-subagents/src/shared/formatters.js.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/shared/types.d.ts +14 -3
- 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 +5 -4
- 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 +86 -52
- 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/groq.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/cli.d.ts.map +1 -1
- package/dist/cli.js +52 -27
- package/dist/cli.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 +18 -6
- 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/customize.d.ts +2 -4
- package/dist/core/customize.d.ts.map +1 -1
- package/dist/core/customize.js +2 -8
- package/dist/core/customize.js.map +1 -1
- package/dist/core/footer-data-provider.d.ts +3 -4
- package/dist/core/footer-data-provider.d.ts.map +1 -1
- package/dist/core/footer-data-provider.js +54 -82
- package/dist/core/footer-data-provider.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 +10 -11
- package/dist/core/permissions.d.ts.map +1 -1
- package/dist/core/permissions.js +107 -40
- 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/settings-manager.d.ts +13 -6
- package/dist/core/settings-manager.d.ts.map +1 -1
- package/dist/core/settings-manager.js +32 -17
- 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/slash-commands.d.ts.map +1 -1
- package/dist/core/slash-commands.js +1 -1
- package/dist/core/slash-commands.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/commands.d.ts +1 -1
- package/dist/gateway/commands.d.ts.map +1 -1
- package/dist/gateway/commands.js +1 -18
- package/dist/gateway/commands.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 +2 -0
- package/dist/main.d.ts.map +1 -1
- package/dist/main.js +108 -58
- package/dist/main.js.map +1 -1
- package/dist/migrations.d.ts +2 -0
- package/dist/migrations.d.ts.map +1 -1
- package/dist/migrations.js +18 -4
- package/dist/migrations.js.map +1 -1
- package/dist/modes/interactive/components/assistant-message.d.ts +1 -3
- package/dist/modes/interactive/components/assistant-message.d.ts.map +1 -1
- package/dist/modes/interactive/components/assistant-message.js +4 -32
- package/dist/modes/interactive/components/assistant-message.js.map +1 -1
- package/dist/modes/interactive/components/custom-editor.d.ts.map +1 -1
- package/dist/modes/interactive/components/custom-editor.js +2 -1
- package/dist/modes/interactive/components/custom-editor.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/plan-message.d.ts +1 -3
- package/dist/modes/interactive/components/plan-message.d.ts.map +1 -1
- package/dist/modes/interactive/components/plan-message.js +1 -16
- package/dist/modes/interactive/components/plan-message.js.map +1 -1
- package/dist/modes/interactive/components/settings-selector.d.ts +8 -5
- package/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/settings-selector.js +71 -31
- package/dist/modes/interactive/components/settings-selector.js.map +1 -1
- package/dist/modes/interactive/components/user-message.d.ts +1 -3
- package/dist/modes/interactive/components/user-message.d.ts.map +1 -1
- package/dist/modes/interactive/components/user-message.js +2 -19
- package/dist/modes/interactive/components/user-message.js.map +1 -1
- package/dist/modes/interactive/interactive-mode.d.ts +13 -4
- package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-mode.js +163 -177
- package/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/dist/modes/interactive/theme/moon.json +0 -1
- package/dist/modes/interactive/theme/theme-schema.json +3 -3
- package/dist/modes/interactive/theme/theme.d.ts +1 -1
- package/dist/modes/interactive/theme/theme.d.ts.map +1 -1
- package/dist/modes/interactive/theme/theme.js +95 -90
- package/dist/modes/interactive/theme/theme.js.map +1 -1
- package/dist/startup/interactive-view.d.ts +55 -0
- package/dist/startup/interactive-view.d.ts.map +1 -0
- package/dist/startup/interactive-view.js +332 -0
- package/dist/startup/interactive-view.js.map +1 -0
- package/dist/startup/launch-routing.d.ts +8 -0
- package/dist/startup/launch-routing.d.ts.map +1 -0
- package/dist/startup/launch-routing.js +29 -0
- package/dist/startup/launch-routing.js.map +1 -0
- package/dist/startup/startup-milestones.d.ts +4 -0
- package/dist/startup/startup-milestones.d.ts.map +1 -0
- package/dist/startup/startup-milestones.js +14 -0
- package/dist/startup/startup-milestones.js.map +1 -0
- package/dist/utils/syntax-highlight.d.ts.map +1 -1
- package/dist/utils/syntax-highlight.js +10 -4
- package/dist/utils/syntax-highlight.js.map +1 -1
- package/docs/features.md +9 -9
- package/docs/interactive-startup.md +58 -0
- package/docs/keybindings.md +1 -1
- package/docs/model-catalog.md +29 -0
- package/docs/quickstart.md +3 -2
- package/docs/settings.md +4 -4
- package/docs/terminal-setup.md +2 -2
- package/docs/termux.md +1 -1
- package/docs/usage.md +4 -3
- package/docs/windows.md +1 -1
- package/examples/extensions/custom-provider-anthropic/package-lock.json +2 -2
- package/examples/extensions/custom-provider-anthropic/package.json +1 -1
- package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
- package/examples/extensions/gondolin/package-lock.json +2 -2
- package/examples/extensions/gondolin/package.json +1 -1
- package/examples/extensions/sandbox/package-lock.json +2 -2
- package/examples/extensions/sandbox/package.json +1 -1
- package/examples/extensions/subagent/README.md +1 -1
- package/examples/extensions/with-deps/package-lock.json +2 -2
- package/examples/extensions/with-deps/package.json +1 -1
- package/package.json +16 -16
- package/dist/core/swarm.d.ts +0 -54
- package/dist/core/swarm.d.ts.map +0 -1
- package/dist/core/swarm.js +0 -119
- package/dist/core/swarm.js.map +0 -1
|
@@ -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\tgutterRail: boolean;\n\tpromptSymbol: boolean;\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\tonGutterRailChange: (enabled: boolean) => void;\n\tonPromptSymbolChange: (enabled: boolean) => void;\n\tonFooterMcpChange: (enabled: boolean) => void;\n\tonFooterLspChange: (enabled: boolean) => void;\n\tonFooterContextChange: (enabled: boolean) => void;\n\tonFooterTokensChange: (enabled: boolean) => void;\n\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: \"gutter-rail\",\n\t\t\t\tlabel: \"Gutter rail\",\n\t\t\t\tdescription: \"Turn boundary rail\",\n\t\t\t\tcurrentValue: (bridge?.getGutterRail() ?? true) ? \"on\" : \"off\",\n\t\t\t\tvalues: [\"on\", \"off\"],\n\t\t\t},\n\t\t\t{\n\t\t\t\tid: \"prompt-symbol\",\n\t\t\t\tlabel: \"Prompt symbol\",\n\t\t\t\tdescription: \"Moon prompt glyph\",\n\t\t\t\tcurrentValue: (bridge?.getPromptSymbol() ?? true) ? \"on\" : \"off\",\n\t\t\t\tvalues: [\"on\", \"off\"],\n\t\t\t},\n\t\t\t{\n\t\t\t\tid: \"footer-mcp\",\n\t\t\t\tlabel: \"Footer: MCP status\",\n\t\t\t\tdescription: \"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: \"Footer: 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: \"Footer: 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: \"Footer: 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: \"Footer: 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: \"Footer: 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: \"Footer: 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: \"Footer: 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: \"Footer: 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: \"Footer: 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 \"gutter-rail\":\n\t\t\t\t\t\tcallbacks.onGutterRailChange(newValue === \"on\");\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase \"prompt-symbol\":\n\t\t\t\t\t\tcallbacks.onPromptSymbolChange(newValue === \"on\");\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase \"footer-mcp\":\n\t\t\t\t\t\tcallbacks.onFooterMcpChange(newValue === \"on\");\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase \"footer-lsp\":\n\t\t\t\t\t\tcallbacks.onFooterLspChange(newValue === \"on\");\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase \"footer-context\":\n\t\t\t\t\t\tcallbacks.onFooterContextChange(newValue === \"on\");\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase \"footer-tokens\":\n\t\t\t\t\t\tcallbacks.onFooterTokensChange(newValue === \"on\");\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase \"footer-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.
|
|
@@ -171,86 +214,72 @@ class CustomizeSubmenu extends Container {
|
|
|
171
214
|
// one /settings session reflects toggles made earlier in that session.
|
|
172
215
|
const bridge = getCustomizeBridge();
|
|
173
216
|
const items = [
|
|
174
|
-
{
|
|
175
|
-
id: "gutter-rail",
|
|
176
|
-
label: "Gutter rail",
|
|
177
|
-
description: "Turn boundary rail",
|
|
178
|
-
currentValue: (bridge?.getGutterRail() ?? true) ? "on" : "off",
|
|
179
|
-
values: ["on", "off"],
|
|
180
|
-
},
|
|
181
|
-
{
|
|
182
|
-
id: "prompt-symbol",
|
|
183
|
-
label: "Prompt symbol",
|
|
184
|
-
description: "Moon prompt glyph",
|
|
185
|
-
currentValue: (bridge?.getPromptSymbol() ?? true) ? "on" : "off",
|
|
186
|
-
values: ["on", "off"],
|
|
187
|
-
},
|
|
188
217
|
{
|
|
189
218
|
id: "footer-mcp",
|
|
190
|
-
label: "
|
|
219
|
+
label: "MCP status",
|
|
191
220
|
description: "MCP server status",
|
|
192
221
|
currentValue: (bridge?.getFooterMcp() ?? true) ? "on" : "off",
|
|
193
222
|
values: ["on", "off"],
|
|
194
223
|
},
|
|
195
224
|
{
|
|
196
225
|
id: "footer-lsp",
|
|
197
|
-
label: "
|
|
226
|
+
label: "LSP status",
|
|
198
227
|
description: "Language server status",
|
|
199
228
|
currentValue: (bridge?.getFooterLsp() ?? false) ? "on" : "off",
|
|
200
229
|
values: ["on", "off"],
|
|
201
230
|
},
|
|
202
231
|
{
|
|
203
232
|
id: "footer-context",
|
|
204
|
-
label: "
|
|
233
|
+
label: "Context meter",
|
|
205
234
|
description: "Context usage",
|
|
206
235
|
currentValue: (bridge?.getFooterContext() ?? true) ? "on" : "off",
|
|
207
236
|
values: ["on", "off"],
|
|
208
237
|
},
|
|
209
238
|
{
|
|
210
239
|
id: "footer-tokens",
|
|
211
|
-
label: "
|
|
240
|
+
label: "Token counter",
|
|
212
241
|
description: "Input and output token counts",
|
|
213
242
|
currentValue: (bridge?.getFooterTokens() ?? true) ? "on" : "off",
|
|
214
243
|
values: ["on", "off"],
|
|
215
244
|
},
|
|
216
245
|
{
|
|
217
246
|
id: "footer-cache-hit-rate",
|
|
218
|
-
label: "
|
|
247
|
+
label: "Cache hit rate",
|
|
219
248
|
description: "Latest prompt cache hit rate",
|
|
220
249
|
currentValue: (bridge?.getFooterCacheHitRate() ?? true) ? "on" : "off",
|
|
221
250
|
values: ["on", "off"],
|
|
222
251
|
},
|
|
223
252
|
{
|
|
224
253
|
id: "footer-tps",
|
|
225
|
-
label: "
|
|
254
|
+
label: "TPS counter",
|
|
226
255
|
description: "Token generation speed",
|
|
227
256
|
currentValue: (bridge?.getFooterTps() ?? true) ? "on" : "off",
|
|
228
257
|
values: ["on", "off"],
|
|
229
258
|
},
|
|
230
259
|
{
|
|
231
260
|
id: "footer-statuses",
|
|
232
|
-
label: "
|
|
233
|
-
description: "Active plan
|
|
261
|
+
label: "Feature statuses",
|
|
262
|
+
description: "Active plan and goal status",
|
|
234
263
|
currentValue: (bridge?.getFooterStatuses() ?? true) ? "on" : "off",
|
|
235
264
|
values: ["on", "off"],
|
|
236
265
|
},
|
|
237
266
|
{
|
|
238
267
|
id: "footer-git",
|
|
239
|
-
label: "
|
|
268
|
+
label: "Git branch",
|
|
240
269
|
description: "Git branch and line changes",
|
|
241
270
|
currentValue: (bridge?.getFooterGit() ?? true) ? "on" : "off",
|
|
242
271
|
values: ["on", "off"],
|
|
243
272
|
},
|
|
244
273
|
{
|
|
245
274
|
id: "footer-plan",
|
|
246
|
-
label: "
|
|
275
|
+
label: "Plan usage",
|
|
247
276
|
description: "Subscription usage percentage",
|
|
248
277
|
currentValue: (bridge?.getFooterPlan() ?? true) ? "on" : "off",
|
|
249
278
|
values: ["on", "off"],
|
|
250
279
|
},
|
|
251
280
|
{
|
|
252
281
|
id: "footer-plan-bar",
|
|
253
|
-
label: "
|
|
282
|
+
label: "Plan bar",
|
|
254
283
|
description: "Bar beside the subscription usage percentage",
|
|
255
284
|
currentValue: (bridge?.getFooterPlanBar() ?? true) ? "on" : "off",
|
|
256
285
|
values: ["on", "off"],
|
|
@@ -258,12 +287,6 @@ class CustomizeSubmenu extends Container {
|
|
|
258
287
|
];
|
|
259
288
|
this.settingsList = new SettingsList(items, Math.min(items.length, 10), getSettingsListTheme(), (id, newValue) => {
|
|
260
289
|
switch (id) {
|
|
261
|
-
case "gutter-rail":
|
|
262
|
-
callbacks.onGutterRailChange(newValue === "on");
|
|
263
|
-
break;
|
|
264
|
-
case "prompt-symbol":
|
|
265
|
-
callbacks.onPromptSymbolChange(newValue === "on");
|
|
266
|
-
break;
|
|
267
290
|
case "footer-mcp":
|
|
268
291
|
callbacks.onFooterMcpChange(newValue === "on");
|
|
269
292
|
break;
|
|
@@ -995,6 +1018,20 @@ export class SettingsSelectorComponent extends Container {
|
|
|
995
1018
|
currentValue: config.modelTiers.enabled ? "on" : "off",
|
|
996
1019
|
submenu: (currentValue, done) => new ModelTiersSubmenu(currentValue, config.modelTiers, callbacks, done),
|
|
997
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
|
+
},
|
|
998
1035
|
{
|
|
999
1036
|
id: "plan-usage-window",
|
|
1000
1037
|
label: "Plan usage window",
|
|
@@ -1258,6 +1295,9 @@ export class SettingsSelectorComponent extends Container {
|
|
|
1258
1295
|
case "auto-manage-subscriptions":
|
|
1259
1296
|
callbacks.onAutoManageSubscriptionsChange(newValue === "on");
|
|
1260
1297
|
break;
|
|
1298
|
+
case "confirm-large-subagent-launches":
|
|
1299
|
+
callbacks.onConfirmLargeSubagentLaunchesChange(newValue === "on");
|
|
1300
|
+
break;
|
|
1261
1301
|
case "theme":
|
|
1262
1302
|
callbacks.onThemeChange(newValue);
|
|
1263
1303
|
break;
|