@prometheus-ai/agent 0.5.3 → 0.5.8
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 +39 -0
- package/dist/cli.js +25110 -0
- package/dist/types/async/index.d.ts +0 -1
- package/dist/types/async/job-manager.d.ts +33 -0
- package/dist/types/autolearn/controller.d.ts +25 -0
- package/dist/types/autolearn/managed-skills.d.ts +45 -0
- package/dist/types/autoresearch/state.d.ts +1 -1
- package/dist/types/autoresearch/tools/init-experiment.d.ts +1 -1
- package/dist/types/autoresearch/tools/log-experiment.d.ts +1 -1
- package/dist/types/autoresearch/tools/run-experiment.d.ts +1 -1
- package/dist/types/autoresearch/tools/update-notes.d.ts +1 -1
- package/dist/types/autoresearch/types.d.ts +1 -1
- package/dist/types/capability/context-file.d.ts +0 -13
- package/dist/types/capability/mcp.d.ts +1 -0
- package/dist/types/capability/rule-buckets.d.ts +1 -1
- package/dist/types/capability/rule.d.ts +6 -1
- package/dist/types/capability/types.d.ts +0 -4
- package/dist/types/cli/args.d.ts +23 -3
- package/dist/types/cli/bench-cli.d.ts +78 -0
- package/dist/types/cli/claude-trace-cli.d.ts +7 -0
- package/dist/types/cli/dry-balance-cli.d.ts +16 -2
- package/dist/types/cli/gallery-cli.d.ts +43 -0
- package/dist/types/cli/gallery-fixtures/agentic.d.ts +2 -0
- package/dist/types/cli/gallery-fixtures/codeintel.d.ts +3 -0
- package/dist/types/cli/gallery-fixtures/edit.d.ts +3 -0
- package/dist/types/cli/gallery-fixtures/fs.d.ts +2 -0
- package/dist/types/cli/gallery-fixtures/index.d.ts +4 -0
- package/dist/types/cli/gallery-fixtures/interaction.d.ts +3 -0
- package/dist/types/cli/gallery-fixtures/memory.d.ts +2 -0
- package/dist/types/cli/gallery-fixtures/misc.d.ts +3 -0
- package/dist/types/cli/gallery-fixtures/search.d.ts +3 -0
- package/dist/types/cli/gallery-fixtures/shell.d.ts +3 -0
- package/dist/types/cli/gallery-fixtures/types.d.ts +55 -0
- package/dist/types/cli/gallery-fixtures/web.d.ts +2 -0
- package/dist/types/cli/gallery-screenshot.d.ts +35 -0
- package/dist/types/cli/gateway-cli.d.ts +4 -0
- package/dist/types/cli/grievances-cli.d.ts +1 -1
- package/dist/types/cli/list-models.d.ts +6 -14
- package/dist/types/cli/models-cli.d.ts +49 -0
- package/dist/types/cli/session-picker.d.ts +1 -1
- package/dist/types/cli/setup-cli.d.ts +1 -1
- package/dist/types/cli/setup-model-picker.d.ts +14 -0
- package/dist/types/cli/startup-cwd.d.ts +2 -0
- package/dist/types/cli/update-cli.d.ts +13 -40
- package/dist/types/cli/usage-cli.d.ts +81 -0
- package/dist/types/cli-commands.d.ts +12 -0
- package/dist/types/collab/crypto.d.ts +7 -0
- package/dist/types/collab/guest.d.ts +37 -0
- package/dist/types/collab/host.d.ts +29 -0
- package/dist/types/collab/protocol.d.ts +119 -0
- package/dist/types/collab/relay-client.d.ts +22 -0
- package/dist/types/commands/bench.d.ts +29 -0
- package/dist/types/commands/gallery.d.ts +47 -0
- package/dist/types/commands/gateway.d.ts +3 -0
- package/dist/types/commands/install.d.ts +1 -1
- package/dist/types/commands/join.d.ts +12 -0
- package/dist/types/commands/launch.d.ts +8 -4
- package/dist/types/commands/models.d.ts +33 -0
- package/dist/types/commands/read.d.ts +1 -1
- package/dist/types/commands/say.d.ts +24 -0
- package/dist/types/commands/token.d.ts +25 -0
- package/dist/types/commands/usage.d.ts +34 -0
- package/dist/types/commit/agentic/tools/analyze-file.d.ts +1 -1
- package/dist/types/commit/agentic/tools/git-file-diff.d.ts +1 -1
- package/dist/types/commit/agentic/tools/git-hunk.d.ts +1 -1
- package/dist/types/commit/agentic/tools/git-overview.d.ts +1 -1
- package/dist/types/commit/agentic/tools/propose-changelog.d.ts +1 -1
- package/dist/types/commit/agentic/tools/propose-commit.d.ts +1 -1
- package/dist/types/commit/agentic/tools/recent-commits.d.ts +1 -1
- package/dist/types/commit/agentic/tools/schemas.d.ts +1 -1
- package/dist/types/commit/agentic/tools/split-commit.d.ts +1 -1
- package/dist/types/commit/analysis/conventional.d.ts +2 -2
- package/dist/types/commit/analysis/summary.d.ts +2 -2
- package/dist/types/commit/changelog/generate.d.ts +3 -3
- package/dist/types/commit/changelog/index.d.ts +2 -2
- package/dist/types/commit/map-reduce/index.d.ts +3 -3
- package/dist/types/commit/map-reduce/map-phase.d.ts +2 -2
- package/dist/types/commit/map-reduce/reduce-phase.d.ts +2 -2
- package/dist/types/commit/model-selection.d.ts +10 -4
- package/dist/types/commit/shared-llm.d.ts +1 -1
- package/dist/types/config/api-key-resolver.d.ts +43 -0
- package/dist/types/config/append-only-context-mode.d.ts +2 -1
- package/dist/types/config/keybindings.d.ts +12 -7
- package/dist/types/config/model-discovery.d.ts +57 -0
- package/dist/types/config/model-equivalence.d.ts +1 -1
- package/dist/types/config/model-registry.d.ts +86 -222
- package/dist/types/config/model-resolver.d.ts +43 -12
- package/dist/types/config/model-roles.d.ts +29 -0
- package/dist/types/config/models-config-schema.d.ts +536 -43
- package/dist/types/config/models-config.d.ts +391 -0
- package/dist/types/config/settings-schema.d.ts +1211 -324
- package/dist/types/config/settings.d.ts +15 -3
- package/dist/types/dap/config.d.ts +14 -1
- package/dist/types/dap/types.d.ts +10 -0
- package/dist/types/debug/log-viewer.d.ts +1 -1
- package/dist/types/debug/raw-sse.d.ts +1 -1
- package/dist/types/debug/report-bundle.d.ts +3 -0
- package/dist/types/debug/terminal-info.d.ts +0 -1
- package/dist/types/discovery/at-imports.d.ts +15 -0
- package/dist/types/discovery/prometheus-extension-roots.d.ts +7 -7
- package/dist/types/edit/diff.d.ts +3 -2
- package/dist/types/edit/file-snapshot-store.d.ts +18 -0
- package/dist/types/edit/hashline/noop-loop-guard.d.ts +72 -0
- package/dist/types/edit/hashline/params.d.ts +1 -1
- package/dist/types/edit/index.d.ts +0 -1
- package/dist/types/edit/modes/apply-patch.d.ts +1 -1
- package/dist/types/edit/modes/patch.d.ts +1 -1
- package/dist/types/edit/modes/replace.d.ts +1 -1
- package/dist/types/edit/renderer.d.ts +1 -0
- package/dist/types/eval/__tests__/completion-bridge.test.d.ts +1 -0
- package/dist/types/eval/__tests__/helpers-local-roots.test.d.ts +1 -0
- package/dist/types/eval/__tests__/js-context-manager.test.d.ts +1 -0
- package/dist/types/eval/backend.d.ts +7 -2
- package/dist/types/eval/bridge-timeout.d.ts +1 -1
- package/dist/types/eval/completion-bridge.d.ts +25 -0
- package/dist/types/eval/idle-timeout.d.ts +1 -5
- package/dist/types/eval/js/context-manager.d.ts +1 -0
- package/dist/types/eval/js/executor.d.ts +2 -0
- package/dist/types/eval/js/index.d.ts +1 -1
- package/dist/types/eval/js/shared/helpers.d.ts +7 -1
- package/dist/types/eval/js/shared/rewrite-imports.d.ts +6 -6
- package/dist/types/eval/js/shared/runtime.d.ts +6 -1
- package/dist/types/eval/js/worker-protocol.d.ts +6 -0
- package/dist/types/eval/py/__tests__/prelude.test.d.ts +1 -0
- package/dist/types/eval/py/executor.d.ts +12 -0
- package/dist/types/eval/py/index.d.ts +1 -1
- package/dist/types/eval/py/kernel.d.ts +6 -1
- package/dist/types/eval/py/runtime.d.ts +9 -0
- package/dist/types/exa/index.d.ts +1 -19
- package/dist/types/exa/mcp-client.d.ts +10 -3
- package/dist/types/exa/types.d.ts +0 -83
- package/dist/types/exec/bash-executor.d.ts +7 -0
- package/dist/types/export/custom-share.d.ts +1 -2
- package/dist/types/export/html/index.d.ts +39 -0
- package/dist/types/export/html/template-js.d.ts +2 -0
- package/dist/types/export/share.d.ts +61 -0
- package/dist/types/export/ttsr.d.ts +14 -0
- package/dist/types/extensibility/custom-commands/types.d.ts +9 -4
- package/dist/types/extensibility/custom-tools/loader.d.ts +30 -4
- package/dist/types/extensibility/custom-tools/types.d.ts +16 -8
- package/dist/types/extensibility/extensions/index.d.ts +1 -1
- package/dist/types/extensibility/extensions/loader.d.ts +20 -1
- package/dist/types/extensibility/extensions/model-api.d.ts +17 -0
- package/dist/types/extensibility/extensions/runner.d.ts +5 -2
- package/dist/types/extensibility/extensions/types.d.ts +72 -11
- package/dist/types/extensibility/hooks/index.d.ts +2 -1
- package/dist/types/extensibility/hooks/loader.d.ts +1 -1
- package/dist/types/extensibility/hooks/types.d.ts +11 -5
- package/dist/types/extensibility/{legacy-pi-ai-shim.d.ts → legacy-package-ai-shim.d.ts} +2 -2
- package/dist/types/extensibility/plugins/{legacy-pi-compat.d.ts → legacy-package-compat.d.ts} +20 -3
- package/dist/types/extensibility/plugins/loader.d.ts +11 -0
- package/dist/types/extensibility/plugins/marketplace-auto-update.d.ts +8 -0
- package/dist/types/extensibility/plugins/types.d.ts +2 -2
- package/dist/types/extensibility/shared-events.d.ts +3 -3
- package/dist/types/extensibility/skills.d.ts +10 -0
- package/dist/types/extensibility/slash-commands.d.ts +1 -11
- package/dist/types/gateway/adapters/telegram/access.d.ts +4 -1
- package/dist/types/gateway/adapters/telegram/setup-api.d.ts +1 -1
- package/dist/types/gateway/adapters/telegram/webhook.d.ts +1 -1
- package/dist/types/gateway/types.d.ts +1 -1
- package/dist/types/goals/guided-setup.d.ts +18 -0
- package/dist/types/goals/state.d.ts +1 -1
- package/dist/types/goals/tools/goal-tool.d.ts +1 -1
- package/dist/types/hindsight/mental-models.d.ts +17 -8
- package/dist/types/hindsight/transcript.d.ts +1 -1
- package/dist/types/index.d.ts +5 -0
- package/dist/types/internal-urls/artifact-protocol.d.ts +2 -2
- package/dist/types/internal-urls/history-protocol.d.ts +14 -0
- package/dist/types/internal-urls/index.d.ts +1 -0
- package/dist/types/internal-urls/local-protocol.d.ts +14 -2
- package/dist/types/internal-urls/types.d.ts +1 -1
- package/dist/types/irc/bus.d.ts +79 -0
- package/dist/types/lib/xai-http.d.ts +1 -1
- package/dist/types/lsp/client.d.ts +10 -0
- package/dist/types/lsp/config.d.ts +2 -2
- package/dist/types/lsp/edits.d.ts +9 -0
- package/dist/types/lsp/format-options.d.ts +32 -0
- package/dist/types/lsp/index.d.ts +2 -7
- package/dist/types/lsp/types.d.ts +13 -1
- package/dist/types/lsp/utils.d.ts +6 -2
- package/dist/types/main.d.ts +23 -8
- package/dist/types/mcp/json-rpc.d.ts +5 -0
- package/dist/types/mcp/manager.d.ts +8 -0
- package/dist/types/mcp/oauth-discovery.d.ts +6 -1
- package/dist/types/mcp/oauth-flow.d.ts +13 -3
- package/dist/types/mcp/startup-events.d.ts +11 -0
- package/dist/types/mcp/tool-bridge.d.ts +2 -0
- package/dist/types/mcp/transports/stdio.d.ts +13 -0
- package/dist/types/mcp/types.d.ts +2 -0
- package/dist/types/memories/index.d.ts +7 -15
- package/dist/types/memories/storage.d.ts +0 -10
- package/dist/types/memory-backend/index.d.ts +3 -1
- package/dist/types/memory-backend/local-backend.d.ts +4 -3
- package/dist/types/memory-backend/resolve.d.ts +2 -2
- package/dist/types/memory-backend/runtime.d.ts +4 -0
- package/dist/types/memory-backend/types.d.ts +67 -2
- package/dist/types/mnemopi/config.d.ts +31 -1
- package/dist/types/mnemopi/state.d.ts +40 -2
- package/dist/types/modes/acp/acp-agent.d.ts +1 -2
- package/dist/types/modes/components/agent-dashboard.d.ts +17 -1
- package/dist/types/modes/components/agent-hub.d.ts +82 -0
- package/dist/types/modes/components/assistant-message.d.ts +5 -12
- package/dist/types/modes/components/bash-execution.d.ts +1 -1
- package/dist/types/modes/components/chat-block.d.ts +64 -0
- package/dist/types/modes/components/collab-prompt-message.d.ts +10 -0
- package/dist/types/modes/components/compaction-summary-message.d.ts +25 -5
- package/dist/types/modes/components/copy-selector.d.ts +1 -1
- package/dist/types/modes/components/custom-editor.d.ts +49 -2
- package/dist/types/modes/components/custom-editor.test.d.ts +1 -0
- package/dist/types/modes/components/dynamic-border.d.ts +1 -1
- package/dist/types/modes/components/extensions/extension-dashboard.d.ts +1 -1
- package/dist/types/modes/components/extensions/extension-list.d.ts +1 -1
- package/dist/types/modes/components/extensions/inspector-panel.d.ts +1 -1
- package/dist/types/modes/components/footer.d.ts +1 -1
- package/dist/types/modes/components/hook-editor.d.ts +5 -0
- package/dist/types/modes/components/hook-input.d.ts +4 -0
- package/dist/types/modes/components/hook-selector.d.ts +5 -7
- package/dist/types/modes/components/index.d.ts +1 -0
- package/dist/types/modes/components/late-diagnostics-message.d.ts +20 -0
- package/dist/types/modes/components/logout-account-selector.d.ts +8 -0
- package/dist/types/modes/components/mcp-add-wizard.d.ts +2 -1
- package/dist/types/modes/components/model-selector.d.ts +1 -1
- package/dist/types/modes/components/oauth-selector.d.ts +10 -1
- package/dist/types/modes/components/overlay-box.d.ts +17 -0
- package/dist/types/modes/components/plan-review-overlay.d.ts +61 -0
- package/dist/types/modes/components/plan-toc.d.ts +41 -0
- package/dist/types/modes/components/read-tool-group.d.ts +8 -0
- package/dist/types/modes/components/reset-usage-selector.d.ts +12 -0
- package/dist/types/modes/components/segment-track.d.ts +11 -6
- package/dist/types/modes/components/session-selector.d.ts +18 -9
- package/dist/types/modes/components/settings-defs.d.ts +9 -2
- package/dist/types/modes/components/settings-selector.d.ts +17 -4
- package/dist/types/modes/components/snapcompact-shape-preview.d.ts +31 -0
- package/dist/types/modes/components/status-line/component.d.ts +61 -0
- package/dist/types/modes/components/status-line/index.d.ts +1 -0
- package/dist/types/modes/components/status-line/types.d.ts +47 -3
- package/dist/types/modes/components/tiny-title-download-progress.d.ts +1 -1
- package/dist/types/modes/components/tool-execution.d.ts +49 -2
- package/dist/types/modes/components/transcript-container.d.ts +76 -26
- package/dist/types/modes/components/tree-selector.d.ts +2 -2
- package/dist/types/modes/components/ttsr-notification.d.ts +5 -1
- package/dist/types/modes/components/usage-row.d.ts +3 -0
- package/dist/types/modes/components/user-message-selector.d.ts +1 -1
- package/dist/types/modes/components/user-message.d.ts +2 -1
- package/dist/types/modes/components/visual-truncate.d.ts +1 -1
- package/dist/types/modes/components/welcome.d.ts +12 -2
- package/dist/types/modes/controllers/command-controller.d.ts +3 -2
- package/dist/types/modes/controllers/event-controller.d.ts +7 -1
- package/dist/types/modes/controllers/extension-ui-controller.d.ts +0 -1
- package/dist/types/modes/controllers/input-controller.d.ts +25 -3
- package/dist/types/modes/controllers/mcp-command-controller.d.ts +8 -0
- package/dist/types/modes/controllers/selector-controller.d.ts +5 -2
- package/dist/types/modes/controllers/session-focus-controller.d.ts +31 -0
- package/dist/types/modes/controllers/streaming-reveal.d.ts +22 -0
- package/dist/types/modes/controllers/tan-command-controller.d.ts +6 -0
- package/dist/types/modes/controllers/tool-args-reveal.d.ts +43 -0
- package/dist/types/modes/gradient-highlight.d.ts +9 -4
- package/dist/types/modes/image-references.d.ts +14 -3
- package/dist/types/modes/index.d.ts +8 -7
- package/dist/types/modes/interactive-mode.d.ts +92 -16
- package/dist/types/modes/magic-keywords.d.ts +14 -2
- package/dist/types/modes/markdown-prose.d.ts +1 -1
- package/dist/types/modes/oauth-manual-input.d.ts +7 -0
- package/dist/types/modes/rpc/rpc-client.d.ts +48 -2
- package/dist/types/modes/rpc/rpc-mode.d.ts +67 -2
- package/dist/types/modes/rpc/rpc-subagents.d.ts +24 -0
- package/dist/types/modes/rpc/rpc-types.d.ts +113 -1
- package/dist/types/modes/runtime-init.d.ts +4 -0
- package/dist/types/modes/session-observer-registry.d.ts +9 -0
- package/dist/types/modes/setup-version.d.ts +11 -0
- package/dist/types/modes/setup-wizard/index.d.ts +7 -2
- package/dist/types/modes/setup-wizard/lazy.d.ts +2 -0
- package/dist/types/modes/setup-wizard/scenes/sign-in.d.ts +4 -1
- package/dist/types/modes/setup-wizard/scenes/types.d.ts +11 -2
- package/dist/types/modes/setup-wizard/scenes/web-search.d.ts +6 -2
- package/dist/types/modes/setup-wizard/wizard-overlay.d.ts +1 -1
- package/dist/types/modes/theme/theme.d.ts +42 -7
- package/dist/types/modes/types.d.ts +62 -13
- package/dist/types/modes/utils/context-usage.d.ts +6 -1
- package/dist/types/modes/utils/copy-targets.d.ts +21 -1
- package/dist/types/modes/utils/ui-helpers.d.ts +4 -4
- package/dist/types/modes/workflow.d.ts +3 -3
- package/dist/types/plan-mode/approved-plan.d.ts +27 -8
- package/dist/types/plan-mode/plan-protection.d.ts +4 -4
- package/dist/types/registry/agent-lifecycle.d.ts +51 -0
- package/dist/types/registry/agent-registry.d.ts +33 -5
- package/dist/types/sdk.d.ts +46 -4
- package/dist/types/secrets/index.d.ts +1 -1
- package/dist/types/secrets/obfuscator.d.ts +9 -3
- package/dist/types/session/agent-session.d.ts +136 -66
- package/dist/types/session/agent-storage.d.ts +2 -1
- package/dist/types/session/auth-broker-config.d.ts +4 -0
- package/dist/types/session/auth-storage.d.ts +1 -1
- package/dist/types/session/codex-auto-reset.d.ts +111 -0
- package/dist/types/session/indexed-session-storage.d.ts +3 -3
- package/dist/types/session/messages.d.ts +26 -15
- package/dist/types/session/session-context.d.ts +39 -0
- package/dist/types/session/session-entries.d.ts +159 -0
- package/dist/types/session/session-history-format.d.ts +12 -0
- package/dist/types/session/session-listing.d.ts +69 -0
- package/dist/types/session/session-loader.d.ts +16 -0
- package/dist/types/session/session-manager.d.ts +107 -440
- package/dist/types/session/session-migrations.d.ts +12 -0
- package/dist/types/session/session-paths.d.ts +25 -0
- package/dist/types/session/session-persistence.d.ts +8 -0
- package/dist/types/session/session-storage.d.ts +11 -7
- package/dist/types/session/snapcompact-inline.d.ts +145 -0
- package/dist/types/session/snapcompact-savings-journal.d.ts +46 -0
- package/dist/types/session/streaming-output.d.ts +46 -0
- package/dist/types/session/tool-choice-queue.d.ts +6 -6
- package/dist/types/session/yield-queue.d.ts +10 -1
- package/dist/types/slash-commands/acp-builtins.d.ts +16 -0
- package/dist/types/slash-commands/available-commands.d.ts +34 -0
- package/dist/types/slash-commands/builtin-registry.d.ts +10 -0
- package/dist/types/slash-commands/helpers/active-oauth-account.d.ts +14 -0
- package/dist/types/slash-commands/helpers/logout.d.ts +15 -0
- package/dist/types/slash-commands/helpers/reset-usage.d.ts +27 -0
- package/dist/types/slash-commands/helpers/stats-dashboard.d.ts +13 -0
- package/dist/types/slash-commands/types.d.ts +5 -9
- package/dist/types/ssh/connection-manager.d.ts +8 -0
- package/dist/types/stt/asr-client.d.ts +90 -0
- package/dist/types/stt/asr-protocol.d.ts +97 -0
- package/dist/types/stt/asr-worker.d.ts +2 -0
- package/dist/types/stt/downloader.d.ts +38 -0
- package/dist/types/stt/endpointer.d.ts +59 -0
- package/dist/types/stt/index.d.ts +5 -1
- package/dist/types/stt/models.d.ts +120 -0
- package/dist/types/stt/recorder.d.ts +17 -0
- package/dist/types/stt/stt-controller.d.ts +6 -0
- package/dist/types/stt/transcriber.d.ts +5 -7
- package/dist/types/stt/wav.d.ts +29 -0
- package/dist/types/system-prompt.d.ts +9 -1
- package/dist/types/task/commands.d.ts +1 -1
- package/dist/types/task/discovery.d.ts +1 -2
- package/dist/types/task/executor.d.ts +61 -2
- package/dist/types/task/index.d.ts +37 -6
- package/dist/types/task/output-manager.d.ts +0 -7
- package/dist/types/task/parallel.d.ts +2 -2
- package/dist/types/task/prometheus-command.d.ts +2 -2
- package/dist/types/task/render.d.ts +20 -7
- package/dist/types/task/repair-args.d.ts +8 -7
- package/dist/types/task/types.d.ts +109 -52
- package/dist/types/task/worktree.d.ts +2 -0
- package/dist/types/telemetry-export.d.ts +2 -2
- package/dist/types/thinking.d.ts +4 -0
- package/dist/types/tiny/models.d.ts +1 -1
- package/dist/types/tiny/title-client.d.ts +12 -1
- package/dist/types/tiny/title-protocol.d.ts +1 -0
- package/dist/types/tools/archive-reader.d.ts +5 -0
- package/dist/types/tools/ask.d.ts +6 -1
- package/dist/types/tools/ast-edit.d.ts +4 -1
- package/dist/types/tools/ast-grep.d.ts +4 -1
- package/dist/types/tools/bash.d.ts +5 -2
- package/dist/types/tools/browser/attach.d.ts +4 -4
- package/dist/types/tools/browser/cmux/cmux-tab.d.ts +202 -0
- package/dist/types/tools/browser/cmux/rpc.d.ts +70 -0
- package/dist/types/tools/browser/cmux/socket-client.d.ts +19 -0
- package/dist/types/tools/browser/registry.d.ts +17 -3
- package/dist/types/tools/browser/render.d.ts +2 -0
- package/dist/types/tools/browser/tab-protocol.d.ts +2 -0
- package/dist/types/tools/browser/tab-supervisor.d.ts +16 -4
- package/dist/types/tools/browser/tab-worker.d.ts +18 -1
- package/dist/types/tools/browser.d.ts +3 -1
- package/dist/types/tools/checkpoint.d.ts +1 -1
- package/dist/types/tools/conflict-detect.d.ts +16 -0
- package/dist/types/tools/debug.d.ts +1 -1
- package/dist/types/tools/eval-render.d.ts +1 -8
- package/dist/types/tools/eval.d.ts +9 -1
- package/dist/types/tools/fetch.d.ts +17 -8
- package/dist/types/tools/find.d.ts +1 -8
- package/dist/types/tools/gh-cache-invalidation.d.ts +6 -0
- package/dist/types/tools/gh.d.ts +4 -1
- package/dist/types/tools/github-cache.d.ts +19 -0
- package/dist/types/tools/grouped-file-output.d.ts +46 -12
- package/dist/types/tools/image-gen.d.ts +1 -1
- package/dist/types/tools/index.d.ts +89 -8
- package/dist/types/tools/inspect-image.d.ts +1 -1
- package/dist/types/tools/irc.d.ts +79 -39
- package/dist/types/tools/job.d.ts +8 -2
- package/dist/types/tools/learn.d.ts +51 -0
- package/dist/types/tools/manage-skill.d.ts +40 -0
- package/dist/types/tools/memory-edit.d.ts +2 -2
- package/dist/types/tools/memory-recall.d.ts +1 -1
- package/dist/types/tools/memory-reflect.d.ts +1 -1
- package/dist/types/tools/memory-render.d.ts +4 -1
- package/dist/types/tools/memory-retain.d.ts +1 -1
- package/dist/types/tools/path-utils.d.ts +17 -5
- package/dist/types/tools/plan-mode-guard.d.ts +18 -9
- package/dist/types/tools/read.d.ts +3 -2
- package/dist/types/tools/render-mermaid.d.ts +1 -1
- package/dist/types/tools/render-utils.d.ts +47 -27
- package/dist/types/tools/renderers.d.ts +10 -2
- package/dist/types/tools/report-tool-issue.d.ts +6 -1
- package/dist/types/tools/resolve.d.ts +1 -1
- package/dist/types/tools/review.d.ts +1 -1
- package/dist/types/tools/search-tool-bm25.d.ts +1 -1
- package/dist/types/tools/search.d.ts +7 -3
- package/dist/types/tools/sqlite-reader.d.ts +4 -0
- package/dist/types/tools/ssh.d.ts +2 -1
- package/dist/types/tools/todo.d.ts +7 -15
- package/dist/types/tools/tool-result.d.ts +2 -0
- package/dist/types/tools/tool-timeouts.d.ts +1 -1
- package/dist/types/tools/tts.d.ts +26 -1
- package/dist/types/tools/write.d.ts +6 -3
- package/dist/types/tools/yield.d.ts +8 -0
- package/dist/types/tts/downloader.d.ts +20 -0
- package/dist/types/tts/index.d.ts +8 -0
- package/dist/types/tts/models.d.ts +82 -0
- package/dist/types/tts/player.d.ts +32 -0
- package/dist/types/tts/runtime.d.ts +6 -0
- package/dist/types/tts/streaming-player.d.ts +41 -0
- package/dist/types/tts/tts-client.d.ts +93 -0
- package/dist/types/tts/tts-protocol.d.ts +95 -0
- package/dist/types/tts/tts-worker.d.ts +2 -0
- package/dist/types/tts/vocalizer.d.ts +41 -0
- package/dist/types/tts/wav.d.ts +8 -0
- package/dist/types/tui/code-cell.d.ts +0 -2
- package/dist/types/tui/hyperlink.d.ts +13 -7
- package/dist/types/tui/output-block.d.ts +16 -22
- package/dist/types/tui/status-line.d.ts +3 -0
- package/dist/types/utils/block-context.d.ts +35 -0
- package/dist/types/utils/changelog.d.ts +8 -0
- package/dist/types/utils/clipboard.d.ts +4 -3
- package/dist/types/utils/enhanced-paste.d.ts +20 -0
- package/dist/types/utils/file-mentions.d.ts +7 -0
- package/dist/types/utils/git.d.ts +22 -3
- package/dist/types/utils/image-loading.d.ts +30 -1
- package/dist/types/utils/session-color.d.ts +15 -3
- package/dist/types/utils/thinking-display.d.ts +17 -0
- package/dist/types/utils/title-generator.d.ts +3 -2
- package/dist/types/utils/tool-choice.d.ts +8 -0
- package/dist/types/utils/tools-manager.d.ts +2 -1
- package/dist/types/web/kagi.d.ts +2 -2
- package/dist/types/web/parallel.d.ts +3 -0
- package/dist/types/web/scrapers/github.d.ts +22 -0
- package/dist/types/web/scrapers/readthedocs.d.ts +3 -0
- package/dist/types/web/scrapers/types.d.ts +12 -0
- package/dist/types/web/search/index.d.ts +1 -1
- package/dist/types/web/search/providers/anthropic.d.ts +2 -1
- package/dist/types/web/search/providers/base.d.ts +2 -1
- package/dist/types/web/search/providers/brave.d.ts +2 -1
- package/dist/types/web/search/providers/codex.d.ts +2 -1
- package/dist/types/web/search/providers/exa.d.ts +2 -1
- package/dist/types/web/search/providers/gemini.d.ts +10 -6
- package/dist/types/web/search/providers/jina.d.ts +7 -2
- package/dist/types/web/search/providers/kagi.d.ts +7 -2
- package/dist/types/web/search/providers/kimi.d.ts +7 -2
- package/dist/types/web/search/providers/parallel.d.ts +2 -1
- package/dist/types/web/search/providers/perplexity.d.ts +10 -2
- package/dist/types/web/search/providers/searxng.d.ts +2 -1
- package/dist/types/web/search/providers/synthetic.d.ts +7 -3
- package/dist/types/web/search/providers/tavily.d.ts +2 -1
- package/dist/types/web/search/providers/zai.d.ts +2 -1
- package/dist/types/web/search/types.d.ts +1 -1
- package/examples/extensions/api-demo.ts +2 -2
- package/package.json +41 -15
- package/scripts/bench-guard.ts +71 -0
- package/scripts/build-binary.ts +24 -25
- package/scripts/bundle-dist.ts +97 -0
- package/scripts/generate-share-viewer.ts +34 -0
- package/scripts/prometheus +42 -0
- package/scripts/prometheus.ts +20 -0
- package/src/async/index.ts +0 -1
- package/src/async/job-manager.ts +106 -3
- package/src/auto-thinking/classifier.ts +2 -1
- package/src/autolearn/controller.ts +139 -0
- package/src/autolearn/managed-skills.ts +257 -0
- package/src/autoresearch/dashboard.ts +1 -1
- package/src/autoresearch/prompt-setup.md +6 -6
- package/src/autoresearch/prompt.md +6 -6
- package/src/autoresearch/state.ts +1 -1
- package/src/autoresearch/storage.ts +2 -1
- package/src/autoresearch/tools/init-experiment.ts +1 -1
- package/src/autoresearch/tools/log-experiment.ts +1 -1
- package/src/autoresearch/tools/run-experiment.ts +1 -1
- package/src/autoresearch/tools/update-notes.ts +1 -1
- package/src/autoresearch/types.ts +1 -1
- package/src/capability/context-file.ts +0 -14
- package/src/capability/fs.ts +10 -0
- package/src/capability/index.ts +1 -6
- package/src/capability/mcp.ts +1 -0
- package/src/capability/rule-buckets.ts +4 -2
- package/src/capability/rule.ts +10 -1
- package/src/capability/types.ts +0 -4
- package/src/cli/args.ts +66 -13
- package/src/cli/auth-broker-cli.ts +6 -7
- package/src/cli/auth-gateway-cli.ts +8 -9
- package/src/cli/bench-cli.ts +437 -0
- package/src/cli/claude-trace-cli.ts +28 -50
- package/src/cli/completion-gen.ts +28 -28
- package/src/cli/dry-balance-cli.ts +56 -23
- package/src/cli/gallery-cli.ts +231 -0
- package/src/cli/gallery-fixtures/agentic.ts +407 -0
- package/src/cli/gallery-fixtures/codeintel.ts +187 -0
- package/src/cli/gallery-fixtures/edit.ts +194 -0
- package/src/cli/gallery-fixtures/fs.ts +220 -0
- package/src/cli/gallery-fixtures/index.ts +40 -0
- package/src/cli/gallery-fixtures/interaction.ts +49 -0
- package/src/cli/gallery-fixtures/memory.ts +81 -0
- package/src/cli/gallery-fixtures/misc.ts +250 -0
- package/src/cli/gallery-fixtures/search.ts +213 -0
- package/src/cli/gallery-fixtures/shell.ts +167 -0
- package/src/cli/gallery-fixtures/types.ts +57 -0
- package/src/cli/gallery-fixtures/web.ts +158 -0
- package/src/cli/gallery-screenshot.ts +279 -0
- package/src/cli/gateway-cli.ts +32 -2
- package/src/cli/grievances-cli.ts +1 -1
- package/src/cli/list-models.ts +16 -174
- package/src/cli/models-cli.ts +429 -0
- package/src/cli/session-picker.ts +2 -1
- package/src/cli/setup-cli.ts +148 -47
- package/src/cli/setup-model-picker.ts +43 -0
- package/src/cli/startup-cwd.ts +68 -0
- package/src/cli/update-cli.ts +144 -272
- package/src/cli/usage-cli.ts +774 -0
- package/src/cli-commands.ts +36 -0
- package/src/cli.ts +141 -32
- package/src/collab/crypto.ts +63 -0
- package/src/collab/guest.ts +451 -0
- package/src/collab/host.ts +565 -0
- package/src/collab/protocol.ts +241 -0
- package/src/collab/relay-client.ts +216 -0
- package/src/commands/bench.ts +42 -0
- package/src/commands/complete.ts +1 -1
- package/src/commands/gallery.ts +52 -0
- package/src/commands/gateway.ts +4 -0
- package/src/commands/install.ts +1 -1
- package/src/commands/join.ts +39 -0
- package/src/commands/launch.ts +8 -4
- package/src/commands/models.ts +61 -0
- package/src/commands/read.ts +6 -3
- package/src/commands/say.ts +102 -0
- package/src/commands/setup.ts +1 -1
- package/src/commands/token.ts +89 -0
- package/src/commands/usage.ts +43 -0
- package/src/commit/agentic/agent.ts +2 -1
- package/src/commit/agentic/tools/analyze-file.ts +42 -20
- package/src/commit/agentic/tools/git-file-diff.ts +1 -1
- package/src/commit/agentic/tools/git-hunk.ts +1 -1
- package/src/commit/agentic/tools/git-overview.ts +1 -1
- package/src/commit/agentic/tools/propose-changelog.ts +1 -1
- package/src/commit/agentic/tools/propose-commit.ts +1 -1
- package/src/commit/agentic/tools/recent-commits.ts +1 -1
- package/src/commit/agentic/tools/schemas.ts +1 -1
- package/src/commit/agentic/tools/split-commit.ts +9 -2
- package/src/commit/analysis/conventional.ts +2 -2
- package/src/commit/analysis/summary.ts +3 -3
- package/src/commit/changelog/generate.ts +3 -3
- package/src/commit/changelog/index.ts +2 -2
- package/src/commit/map-reduce/index.ts +3 -3
- package/src/commit/map-reduce/map-phase.ts +2 -2
- package/src/commit/map-reduce/reduce-phase.ts +2 -2
- package/src/commit/model-selection.ts +35 -12
- package/src/commit/pipeline.ts +4 -4
- package/src/commit/shared-llm.ts +1 -1
- package/src/config/api-key-resolver.ts +67 -0
- package/src/config/append-only-context-mode.ts +6 -12
- package/src/config/keybindings.ts +9 -4
- package/src/config/mcp-schema.json +4 -0
- package/src/config/model-discovery.ts +574 -0
- package/src/config/model-equivalence.ts +5 -4
- package/src/config/model-registry.ts +659 -1093
- package/src/config/model-resolver.ts +374 -174
- package/src/config/model-roles.ts +88 -0
- package/src/config/models-config-schema.ts +61 -9
- package/src/config/models-config.ts +130 -0
- package/src/config/settings-schema.ts +1445 -382
- package/src/config/settings.ts +261 -69
- package/src/dap/client.ts +138 -53
- package/src/dap/config.ts +41 -2
- package/src/dap/defaults.json +1 -0
- package/src/dap/session.ts +263 -161
- package/src/dap/types.ts +10 -0
- package/src/debug/index.ts +50 -60
- package/src/debug/log-viewer.ts +1 -1
- package/src/debug/protocol-probe.ts +1 -1
- package/src/debug/raw-sse-buffer.ts +7 -4
- package/src/debug/raw-sse.ts +1 -1
- package/src/debug/report-bundle.ts +9 -0
- package/src/debug/terminal-info.ts +0 -3
- package/src/discovery/agents-md.ts +25 -21
- package/src/discovery/agents.ts +9 -15
- package/src/discovery/at-imports.ts +273 -0
- package/src/discovery/builtin-rules/index.ts +4 -0
- package/src/discovery/builtin-rules/ts-no-test-timers.md +55 -0
- package/src/discovery/builtin-rules/ts-redundant-clear-guard.md +75 -0
- package/src/discovery/builtin.ts +45 -23
- package/src/discovery/claude-plugins.ts +44 -5
- package/src/discovery/helpers.ts +50 -9
- package/src/discovery/prometheus-extension-roots.ts +10 -10
- package/src/discovery/prometheus-plugins.ts +10 -10
- package/src/edit/diff.ts +191 -4
- package/src/edit/file-snapshot-store.ts +34 -1
- package/src/edit/hashline/block-resolver.ts +20 -1
- package/src/edit/hashline/diff.ts +123 -2
- package/src/edit/hashline/execute.ts +60 -4
- package/src/edit/hashline/filesystem.ts +2 -1
- package/src/edit/hashline/noop-loop-guard.ts +99 -0
- package/src/edit/hashline/params.ts +1 -1
- package/src/edit/index.ts +47 -18
- package/src/edit/modes/apply-patch.ts +1 -1
- package/src/edit/modes/patch.ts +59 -3
- package/src/edit/modes/replace.ts +58 -24
- package/src/edit/notebook.ts +22 -2
- package/src/edit/renderer.ts +315 -151
- package/src/eval/__tests__/agent-bridge.test.ts +105 -39
- package/src/eval/__tests__/budget-bridge.test.ts +1 -1
- package/src/eval/__tests__/completion-bridge.test.ts +412 -0
- package/src/eval/__tests__/helpers-local-roots.test.ts +58 -0
- package/src/eval/__tests__/js-context-manager.test.ts +241 -0
- package/src/eval/__tests__/llm-bridge.test.ts +6 -4
- package/src/eval/__tests__/shared-executors.test.ts +34 -92
- package/src/eval/agent-bridge.ts +39 -23
- package/src/eval/backend.ts +15 -2
- package/src/eval/bridge-timeout.ts +1 -1
- package/src/eval/completion-bridge.ts +203 -0
- package/src/eval/idle-timeout.ts +3 -10
- package/src/eval/js/context-manager.ts +108 -31
- package/src/eval/js/executor.ts +9 -2
- package/src/eval/js/index.ts +7 -3
- package/src/eval/js/shared/helpers.ts +59 -13
- package/src/eval/js/shared/local-module-loader.ts +2 -2
- package/src/eval/js/shared/prelude.txt +167 -30
- package/src/eval/js/shared/rewrite-imports.ts +58 -34
- package/src/eval/js/shared/runtime.ts +24 -16
- package/src/eval/js/tool-bridge.ts +4 -0
- package/src/eval/js/worker-core.ts +1 -0
- package/src/eval/js/worker-entry.ts +6 -0
- package/src/eval/js/worker-protocol.ts +6 -0
- package/src/eval/llm-bridge.ts +2 -1
- package/src/eval/py/__tests__/prelude.test.ts +19 -0
- package/src/eval/py/executor.ts +70 -26
- package/src/eval/py/index.ts +13 -4
- package/src/eval/py/kernel.ts +48 -9
- package/src/eval/py/prelude.py +73 -24
- package/src/eval/py/runner.py +133 -28
- package/src/eval/py/runtime.ts +38 -1
- package/src/exa/index.ts +1 -26
- package/src/exa/mcp-client.ts +10 -10
- package/src/exa/types.ts +0 -97
- package/src/exec/bash-executor.ts +104 -7
- package/src/export/custom-share.ts +1 -1
- package/src/export/html/index.ts +119 -17
- package/src/export/html/share-loader.js +102 -0
- package/src/export/html/template-js.ts +6 -0
- package/src/export/html/template.css +745 -459
- package/src/export/html/template.css.d.ts +2 -0
- package/src/export/html/template.html +6 -3
- package/src/export/html/template.js +277 -891
- package/src/export/html/tool-views.generated.d.ts +2 -0
- package/src/export/html/tool-views.generated.js +38 -0
- package/src/export/share.ts +269 -0
- package/src/export/ttsr.ts +122 -1
- package/src/extensibility/custom-commands/loader.ts +7 -4
- package/src/extensibility/custom-commands/types.ts +9 -4
- package/src/extensibility/custom-tools/loader.ts +51 -23
- package/src/extensibility/custom-tools/types.ts +16 -8
- package/src/extensibility/extensions/get-commands-handler.ts +2 -1
- package/src/extensibility/extensions/index.ts +1 -0
- package/src/extensibility/extensions/loader.ts +70 -20
- package/src/extensibility/extensions/model-api.ts +41 -0
- package/src/extensibility/extensions/runner.ts +12 -2
- package/src/extensibility/extensions/types.ts +83 -11
- package/src/extensibility/extensions/wrapper.ts +41 -5
- package/src/extensibility/hooks/index.ts +2 -1
- package/src/extensibility/hooks/loader.ts +6 -3
- package/src/extensibility/hooks/types.ts +11 -5
- package/src/extensibility/{legacy-pi-ai-shim.ts → legacy-package-ai-shim.ts} +2 -2
- package/src/extensibility/plugins/doctor.ts +1 -2
- package/src/extensibility/plugins/installer.ts +2 -2
- package/src/extensibility/plugins/{legacy-pi-compat.ts → legacy-package-compat.ts} +165 -77
- package/src/extensibility/plugins/loader.ts +34 -23
- package/src/extensibility/plugins/manager.ts +226 -95
- package/src/extensibility/plugins/marketplace-auto-update.ts +49 -0
- package/src/extensibility/plugins/types.ts +3 -3
- package/src/extensibility/shared-events.ts +3 -3
- package/src/extensibility/skills.ts +113 -9
- package/src/extensibility/slash-commands.ts +1 -97
- package/src/gateway/adapters/telegram/access.ts +39 -4
- package/src/gateway/adapters/telegram/normalize.ts +16 -1
- package/src/gateway/adapters/telegram/setup-api.ts +7 -1
- package/src/gateway/adapters/telegram/webhook.ts +26 -5
- package/src/gateway/context.ts +9 -1
- package/src/gateway/types.ts +1 -1
- package/src/goals/guided-setup.ts +133 -0
- package/src/goals/state.ts +1 -1
- package/src/goals/tools/goal-tool.ts +38 -28
- package/src/hindsight/bank.ts +17 -2
- package/src/hindsight/client.ts +27 -2
- package/src/hindsight/mental-models.ts +59 -12
- package/src/hindsight/state.ts +12 -3
- package/src/hindsight/transcript.ts +1 -1
- package/src/index.ts +5 -0
- package/src/internal-urls/artifact-protocol.ts +11 -2
- package/src/internal-urls/docs-index.generated.ts +11 -9
- package/src/internal-urls/history-protocol.ts +113 -0
- package/src/internal-urls/index.ts +1 -0
- package/src/internal-urls/issue-pr-protocol.ts +22 -9
- package/src/internal-urls/local-protocol.ts +42 -7
- package/src/internal-urls/memory-protocol.ts +4 -31
- package/src/internal-urls/router.ts +3 -1
- package/src/internal-urls/types.ts +1 -1
- package/src/irc/bus.ts +303 -0
- package/src/lib/xai-http.ts +3 -3
- package/src/lsp/client.ts +245 -104
- package/src/lsp/clients/biome-client.ts +101 -39
- package/src/lsp/clients/lsp-linter-client.ts +2 -10
- package/src/lsp/config.ts +15 -5
- package/src/lsp/defaults.json +6 -0
- package/src/lsp/edits.ts +143 -95
- package/src/lsp/format-options.ts +119 -0
- package/src/lsp/index.ts +233 -93
- package/src/lsp/render.ts +11 -35
- package/src/lsp/types.ts +13 -1
- package/src/lsp/utils.ts +31 -12
- package/src/main.ts +396 -216
- package/src/mcp/config-writer.ts +7 -3
- package/src/mcp/json-rpc.ts +35 -5
- package/src/mcp/manager.ts +31 -16
- package/src/mcp/oauth-discovery.ts +34 -4
- package/src/mcp/oauth-flow.ts +61 -8
- package/src/mcp/render.ts +7 -1
- package/src/mcp/startup-events.ts +21 -0
- package/src/mcp/tool-bridge.ts +2 -0
- package/src/mcp/transports/stdio.ts +224 -4
- package/src/mcp/types.ts +2 -0
- package/src/memories/index.ts +174 -1128
- package/src/memories/storage.ts +2 -41
- package/src/memory-backend/index.ts +14 -1
- package/src/memory-backend/local-backend.ts +18 -3
- package/src/memory-backend/off-backend.ts +9 -0
- package/src/memory-backend/resolve.ts +4 -6
- package/src/memory-backend/runtime.ts +66 -0
- package/src/memory-backend/types.ts +82 -2
- package/src/mnemopi/backend.ts +220 -28
- package/src/mnemopi/config.ts +138 -33
- package/src/mnemopi/state.ts +91 -11
- package/src/modes/acp/acp-agent.ts +149 -142
- package/src/modes/acp/acp-event-mapper.ts +5 -1
- package/src/modes/components/agent-dashboard.ts +17 -11
- package/src/modes/components/agent-hub.ts +1346 -0
- package/src/modes/components/assistant-message.ts +190 -80
- package/src/modes/components/bash-execution.ts +1 -1
- package/src/modes/components/btw-panel.ts +5 -1
- package/src/modes/components/chat-block.ts +111 -0
- package/src/modes/components/collab-prompt-message.ts +30 -0
- package/src/modes/components/compaction-summary-message.ts +168 -33
- package/src/modes/components/copy-selector.ts +2 -45
- package/src/modes/components/custom-editor.test.ts +96 -0
- package/src/modes/components/custom-editor.ts +405 -118
- package/src/modes/components/custom-message.ts +1 -3
- package/src/modes/components/diff.ts +13 -2
- package/src/modes/components/dynamic-border.ts +12 -3
- package/src/modes/components/execution-shared.ts +1 -2
- package/src/modes/components/extensions/extension-dashboard.ts +8 -5
- package/src/modes/components/extensions/extension-list.ts +1 -1
- package/src/modes/components/extensions/inspector-panel.ts +7 -3
- package/src/modes/components/extensions/state-manager.ts +36 -41
- package/src/modes/components/footer.ts +4 -2
- package/src/modes/components/history-search.ts +1 -1
- package/src/modes/components/hook-editor.ts +8 -0
- package/src/modes/components/hook-input.ts +8 -0
- package/src/modes/components/hook-message.ts +1 -3
- package/src/modes/components/hook-selector.ts +6 -7
- package/src/modes/components/index.ts +1 -0
- package/src/modes/components/late-diagnostics-message.ts +60 -0
- package/src/modes/components/login-dialog.ts +1 -1
- package/src/modes/components/logout-account-selector.ts +130 -0
- package/src/modes/components/mcp-add-wizard.ts +14 -1
- package/src/modes/components/model-selector.ts +177 -75
- package/src/modes/components/oauth-selector.ts +102 -16
- package/src/modes/components/overlay-box.ts +108 -0
- package/src/modes/components/plan-review-overlay.ts +845 -0
- package/src/modes/components/plan-toc.ts +138 -0
- package/src/modes/components/plugin-settings.ts +22 -5
- package/src/modes/components/read-tool-group.ts +442 -39
- package/src/modes/components/reset-usage-selector.ts +161 -0
- package/src/modes/components/segment-track.ts +44 -7
- package/src/modes/components/session-selector.ts +97 -37
- package/src/modes/components/settings-defs.ts +28 -6
- package/src/modes/components/settings-selector.ts +541 -93
- package/src/modes/components/skill-message.ts +0 -1
- package/src/modes/components/snapcompact-shape-preview-doc.md +11 -0
- package/src/modes/components/snapcompact-shape-preview.ts +193 -0
- package/src/modes/components/{status-line.ts → status-line/component.ts} +205 -168
- package/src/modes/components/status-line/index.ts +1 -0
- package/src/modes/components/status-line/presets.ts +3 -3
- package/src/modes/components/status-line/segments.ts +26 -7
- package/src/modes/components/status-line/types.ts +40 -9
- package/src/modes/components/tiny-title-download-progress.ts +1 -1
- package/src/modes/components/tips.txt +7 -3
- package/src/modes/components/todo-reminder.ts +0 -2
- package/src/modes/components/tool-execution.ts +236 -103
- package/src/modes/components/transcript-container.ts +724 -99
- package/src/modes/components/tree-selector.ts +19 -4
- package/src/modes/components/ttsr-notification.ts +72 -30
- package/src/modes/components/usage-row.ts +18 -0
- package/src/modes/components/user-message-selector.ts +1 -1
- package/src/modes/components/user-message.ts +28 -12
- package/src/modes/components/visual-truncate.ts +1 -1
- package/src/modes/components/welcome.ts +80 -22
- package/src/modes/controllers/command-controller-shared.ts +7 -6
- package/src/modes/controllers/command-controller.ts +210 -180
- package/src/modes/controllers/event-controller.ts +352 -142
- package/src/modes/controllers/extension-ui-controller.ts +167 -208
- package/src/modes/controllers/input-controller.ts +778 -162
- package/src/modes/controllers/mcp-command-controller.ts +232 -80
- package/src/modes/controllers/selector-controller.ts +284 -145
- package/src/modes/controllers/session-focus-controller.ts +112 -0
- package/src/modes/controllers/ssh-command-controller.ts +2 -2
- package/src/modes/controllers/streaming-reveal.ts +295 -0
- package/src/modes/controllers/tan-command-controller.ts +173 -0
- package/src/modes/controllers/tool-args-reveal.ts +174 -0
- package/src/modes/gradient-highlight.ts +21 -9
- package/src/modes/image-references.ts +33 -7
- package/src/modes/index.ts +8 -25
- package/src/modes/interactive-mode.ts +840 -186
- package/src/modes/magic-keywords.ts +28 -6
- package/src/modes/markdown-prose.ts +1 -1
- package/src/modes/oauth-manual-input.ts +30 -3
- package/src/modes/rpc/rpc-client.ts +186 -3
- package/src/modes/rpc/rpc-mode.ts +318 -24
- package/src/modes/rpc/rpc-subagents.ts +265 -0
- package/src/modes/rpc/rpc-types.ts +111 -2
- package/src/modes/runtime-init.ts +28 -3
- package/src/modes/session-observer-registry.ts +72 -3
- package/src/modes/setup-version.ts +11 -0
- package/src/modes/setup-wizard/index.ts +16 -4
- package/src/modes/setup-wizard/lazy.ts +16 -0
- package/src/modes/setup-wizard/scenes/glyph.ts +25 -7
- package/src/modes/setup-wizard/scenes/providers.ts +45 -12
- package/src/modes/setup-wizard/scenes/sign-in.ts +14 -13
- package/src/modes/setup-wizard/scenes/splash.ts +1 -1
- package/src/modes/setup-wizard/scenes/telegram.ts +77 -22
- package/src/modes/setup-wizard/scenes/theme.ts +29 -2
- package/src/modes/setup-wizard/scenes/types.ts +11 -2
- package/src/modes/setup-wizard/scenes/web-search.ts +26 -9
- package/src/modes/setup-wizard/wizard-overlay.ts +40 -3
- package/src/modes/shared.ts +2 -0
- package/src/modes/theme/defaults/dark-poimandres.json +1 -1
- package/src/modes/theme/defaults/light-poimandres.json +1 -1
- package/src/modes/theme/shimmer.ts +20 -9
- package/src/modes/theme/theme-schema.json +1 -1
- package/src/modes/theme/theme.ts +342 -82
- package/src/modes/types.ts +60 -18
- package/src/modes/utils/context-usage.ts +88 -8
- package/src/modes/utils/copy-targets.ts +133 -27
- package/src/modes/utils/hotkeys-markdown.ts +3 -2
- package/src/modes/utils/ui-helpers.ts +191 -110
- package/src/modes/workflow.ts +10 -10
- package/src/plan-mode/approved-plan.ts +66 -43
- package/src/plan-mode/plan-protection.ts +4 -4
- package/src/priority.json +5 -1
- package/src/prompts/agents/designer.md +1 -1
- package/src/prompts/agents/explore.md +3 -3
- package/src/prompts/agents/librarian.md +2 -3
- package/src/prompts/agents/oracle.md +2 -2
- package/src/prompts/agents/plan.md +6 -6
- package/src/prompts/agents/reviewer.md +1 -1
- package/src/prompts/agents/task.md +6 -5
- package/src/prompts/bench.md +12 -0
- package/src/prompts/ci-green-request.md +5 -7
- package/src/prompts/goals/goal-budget-limit.md +2 -2
- package/src/prompts/goals/goal-continuation.md +4 -4
- package/src/prompts/goals/goal-mode-active.md +1 -1
- package/src/prompts/goals/guided-goal-interview.md +8 -0
- package/src/prompts/goals/guided-goal-system.md +12 -0
- package/src/prompts/memories/consolidation.md +2 -7
- package/src/prompts/memories/consolidation_system.md +4 -0
- package/src/prompts/memories/identity_review.md +2 -2
- package/src/prompts/memories/read-path.md +11 -10
- package/src/prompts/memories/stage_one_system.md +2 -2
- package/src/prompts/review-custom-request.md +1 -1
- package/src/prompts/system/agent-creation-architect.md +2 -2
- package/src/prompts/system/auto-continue.md +1 -1
- package/src/prompts/system/autolearn-guidance-learn.md +1 -0
- package/src/prompts/system/autolearn-guidance.md +7 -0
- package/src/prompts/system/autolearn-nudge.md +3 -0
- package/src/prompts/system/background-tan-dispatch.md +8 -0
- package/src/prompts/system/btw-user.md +2 -2
- package/src/prompts/system/commit-message-system.md +13 -1
- package/src/prompts/system/custom-system-prompt.md +1 -1
- package/src/prompts/system/eager-task.md +7 -0
- package/src/prompts/system/eager-todo.md +11 -6
- package/src/prompts/system/empty-stop-retry.md +4 -6
- package/src/prompts/system/irc-autoreply.md +6 -0
- package/src/prompts/system/irc-incoming.md +3 -4
- package/src/prompts/system/manual-continue.md +7 -0
- package/src/prompts/system/omfg-user.md +3 -4
- package/src/prompts/system/orchestrate-notice.md +10 -10
- package/src/prompts/system/personalities/default.md +26 -0
- package/src/prompts/system/personalities/friendly.md +17 -0
- package/src/prompts/system/personalities/pragmatic.md +15 -0
- package/src/prompts/system/plan-mode-active.md +70 -77
- package/src/prompts/system/plan-mode-approved.md +1 -1
- package/src/prompts/system/plan-mode-subagent.md +4 -5
- package/src/prompts/system/plan-mode-tool-decision-reminder.md +1 -1
- package/src/prompts/system/project-prompt.md +2 -2
- package/src/prompts/system/snapcompact-context-frames-note.md +1 -0
- package/src/prompts/system/snapcompact-context-stub.md +1 -0
- package/src/prompts/system/snapcompact-system-frames-note.md +1 -0
- package/src/prompts/system/snapcompact-system-stub.md +1 -0
- package/src/prompts/system/snapcompact-toolresult-note.md +1 -0
- package/src/prompts/system/subagent-system-prompt.md +7 -8
- package/src/prompts/system/system-prompt.md +28 -57
- package/src/prompts/system/tiny-title-system.md +1 -1
- package/src/prompts/system/title-marker-instruction.md +1 -0
- package/src/prompts/system/title-system-marker.md +16 -0
- package/src/prompts/system/title-system.md +16 -3
- package/src/prompts/system/ttsr-tool-reminder.md +1 -1
- package/src/prompts/system/workflow-notice.md +4 -4
- package/src/prompts/tools/ast-edit.md +1 -1
- package/src/prompts/tools/ast-grep.md +2 -2
- package/src/prompts/tools/bash.md +16 -8
- package/src/prompts/tools/browser.md +33 -43
- package/src/prompts/tools/debug.md +1 -1
- package/src/prompts/tools/eval.md +31 -51
- package/src/prompts/tools/find.md +0 -1
- package/src/prompts/tools/github.md +8 -7
- package/src/prompts/tools/goal.md +1 -1
- package/src/prompts/tools/image-gen.md +1 -1
- package/src/prompts/tools/inspect-image-system.md +1 -1
- package/src/prompts/tools/irc.md +39 -31
- package/src/prompts/tools/job.md +2 -1
- package/src/prompts/tools/learn.md +7 -0
- package/src/prompts/tools/lsp-late-diagnostic.md +8 -0
- package/src/prompts/tools/lsp.md +2 -2
- package/src/prompts/tools/manage-skill.md +9 -0
- package/src/prompts/tools/memory-edit.md +1 -1
- package/src/prompts/tools/patch.md +2 -2
- package/src/prompts/tools/read.md +31 -39
- package/src/prompts/tools/recall.md +1 -1
- package/src/prompts/tools/reflect.md +1 -1
- package/src/prompts/tools/render-mermaid.md +2 -2
- package/src/prompts/tools/replace.md +4 -10
- package/src/prompts/tools/rewind.md +2 -2
- package/src/prompts/tools/search-tool-bm25.md +1 -9
- package/src/prompts/tools/search.md +0 -1
- package/src/prompts/tools/ssh.md +0 -4
- package/src/prompts/tools/task-summary.md +5 -16
- package/src/prompts/tools/task.md +47 -31
- package/src/prompts/tools/todo.md +6 -3
- package/src/registry/agent-lifecycle.ts +218 -0
- package/src/registry/agent-registry.ts +46 -5
- package/src/sdk.ts +692 -219
- package/src/secrets/index.ts +8 -1
- package/src/secrets/obfuscator.ts +40 -19
- package/src/session/agent-session.ts +1577 -806
- package/src/session/agent-storage.ts +18 -9
- package/src/session/auth-broker-config.ts +30 -1
- package/src/session/auth-storage.ts +6 -0
- package/src/session/codex-auto-reset.ts +202 -0
- package/src/session/history-storage.ts +3 -2
- package/src/session/indexed-session-storage.ts +7 -10
- package/src/session/messages.ts +59 -95
- package/src/session/session-context.ts +352 -0
- package/src/session/session-dump-format.ts +12 -3
- package/src/session/session-entries.ts +194 -0
- package/src/session/session-history-format.ts +246 -0
- package/src/session/session-listing.ts +588 -0
- package/src/session/session-loader.ts +106 -0
- package/src/session/session-manager.ts +1003 -2920
- package/src/session/session-migrations.ts +78 -0
- package/src/session/session-paths.ts +193 -0
- package/src/session/session-persistence.ts +131 -0
- package/src/session/session-storage.ts +91 -30
- package/src/session/snapcompact-inline.ts +542 -0
- package/src/session/snapcompact-savings-journal.ts +113 -0
- package/src/session/streaming-output.ts +248 -11
- package/src/session/tool-choice-queue.ts +23 -11
- package/src/session/yield-queue.ts +20 -2
- package/src/slash-commands/acp-builtins.ts +25 -1
- package/src/slash-commands/available-commands.ts +105 -0
- package/src/slash-commands/builtin-registry.ts +575 -49
- package/src/slash-commands/helpers/active-oauth-account.ts +44 -0
- package/src/slash-commands/helpers/context-report.ts +28 -1
- package/src/slash-commands/helpers/logout.ts +88 -0
- package/src/slash-commands/helpers/reset-usage.ts +66 -0
- package/src/slash-commands/helpers/stats-dashboard.ts +85 -0
- package/src/slash-commands/helpers/usage-report.ts +38 -3
- package/src/slash-commands/types.ts +5 -9
- package/src/ssh/connection-manager.ts +27 -0
- package/src/ssh/ssh-executor.ts +60 -4
- package/src/stt/asr-client.ts +520 -0
- package/src/stt/asr-protocol.ts +65 -0
- package/src/stt/asr-worker.ts +790 -0
- package/src/stt/downloader.ts +107 -47
- package/src/stt/endpointer.ts +259 -0
- package/src/stt/index.ts +5 -1
- package/src/stt/models.ts +150 -0
- package/src/stt/recorder.ts +254 -67
- package/src/stt/stt-controller.ts +201 -22
- package/src/stt/transcriber.ts +37 -68
- package/src/stt/wav.ts +173 -0
- package/src/system-prompt.ts +52 -10
- package/src/task/agents.ts +3 -4
- package/src/task/commands.ts +3 -2
- package/src/task/discovery.ts +17 -24
- package/src/task/executor.ts +1054 -529
- package/src/task/index.ts +862 -757
- package/src/task/output-manager.ts +0 -11
- package/src/task/parallel.ts +3 -3
- package/src/task/prometheus-command.ts +2 -2
- package/src/task/render.ts +529 -182
- package/src/task/repair-args.ts +21 -9
- package/src/task/types.ts +144 -66
- package/src/task/worktree.ts +64 -56
- package/src/telemetry-export.ts +27 -9
- package/src/thinking.ts +9 -7
- package/src/tiny/models.ts +2 -2
- package/src/tiny/text.ts +5 -1
- package/src/tiny/title-client.ts +72 -20
- package/src/tiny/title-protocol.ts +1 -1
- package/src/tiny/worker.ts +23 -99
- package/src/tool-discovery/tool-index.ts +2 -0
- package/src/tools/archive-reader.ts +94 -2
- package/src/tools/ask.ts +234 -177
- package/src/tools/ast-edit.ts +136 -80
- package/src/tools/ast-grep.ts +41 -45
- package/src/tools/auto-generated-guard.ts +20 -3
- package/src/tools/bash-interactive.ts +28 -8
- package/src/tools/bash.ts +198 -35
- package/src/tools/browser/attach.ts +26 -7
- package/src/tools/browser/cmux/cmux-tab.ts +1264 -0
- package/src/tools/browser/cmux/rpc.ts +156 -0
- package/src/tools/browser/cmux/socket-client.ts +309 -0
- package/src/tools/browser/launch.ts +11 -2
- package/src/tools/browser/readable.ts +19 -2
- package/src/tools/browser/registry.ts +52 -5
- package/src/tools/browser/render.ts +13 -5
- package/src/tools/browser/tab-protocol.ts +2 -0
- package/src/tools/browser/tab-supervisor.ts +256 -34
- package/src/tools/browser/tab-worker.ts +259 -91
- package/src/tools/browser.ts +44 -2
- package/src/tools/checkpoint.ts +1 -1
- package/src/tools/conflict-detect.ts +50 -4
- package/src/tools/debug.ts +27 -12
- package/src/tools/eval-render.ts +32 -35
- package/src/tools/eval.ts +26 -12
- package/src/tools/fetch.ts +450 -99
- package/src/tools/find.ts +182 -142
- package/src/tools/gh-cache-invalidation.ts +255 -0
- package/src/tools/gh-renderer.ts +104 -51
- package/src/tools/gh.ts +232 -37
- package/src/tools/github-cache.ts +97 -7
- package/src/tools/grouped-file-output.ts +159 -52
- package/src/tools/image-gen.ts +237 -132
- package/src/tools/index.ts +147 -26
- package/src/tools/inspect-image-renderer.ts +74 -45
- package/src/tools/inspect-image.ts +12 -6
- package/src/tools/irc.ts +626 -173
- package/src/tools/job.ts +106 -29
- package/src/tools/learn.ts +144 -0
- package/src/tools/manage-skill.ts +104 -0
- package/src/tools/memory-edit.ts +4 -4
- package/src/tools/memory-recall.ts +7 -9
- package/src/tools/memory-reflect.ts +5 -9
- package/src/tools/memory-render.ts +23 -6
- package/src/tools/memory-retain.ts +4 -4
- package/src/tools/path-utils.ts +102 -48
- package/src/tools/plan-mode-guard.ts +101 -40
- package/src/tools/read.ts +475 -120
- package/src/tools/render-mermaid.ts +1 -1
- package/src/tools/render-utils.ts +132 -76
- package/src/tools/renderers.ts +12 -1
- package/src/tools/report-tool-issue.ts +14 -6
- package/src/tools/resolve.ts +20 -3
- package/src/tools/review.ts +2 -2
- package/src/tools/search-tool-bm25.ts +37 -24
- package/src/tools/search.ts +233 -115
- package/src/tools/sqlite-reader.ts +26 -17
- package/src/tools/ssh.ts +20 -14
- package/src/tools/todo.ts +197 -191
- package/src/tools/tool-result.ts +8 -0
- package/src/tools/tool-timeouts.ts +1 -1
- package/src/tools/tts.ts +205 -74
- package/src/tools/write.ts +291 -155
- package/src/tools/yield.ts +10 -1
- package/src/tts/downloader.ts +64 -0
- package/src/tts/index.ts +8 -0
- package/src/tts/models.ts +137 -0
- package/src/tts/player.ts +137 -0
- package/src/tts/runtime.ts +21 -0
- package/src/tts/streaming-player.ts +266 -0
- package/src/tts/tts-client.ts +647 -0
- package/src/tts/tts-protocol.ts +60 -0
- package/src/tts/tts-worker.ts +505 -0
- package/src/tts/vocalizer.ts +162 -0
- package/src/tts/wav.ts +58 -0
- package/src/tui/code-cell.ts +2 -7
- package/src/tui/hyperlink.ts +40 -26
- package/src/tui/output-block.ts +60 -108
- package/src/tui/status-line.ts +5 -1
- package/src/utils/block-context.ts +312 -0
- package/src/utils/changelog.ts +27 -1
- package/src/utils/clipboard.ts +91 -22
- package/src/utils/commit-message-generator.ts +8 -3
- package/src/utils/enhanced-paste.ts +230 -0
- package/src/utils/file-mentions.ts +3 -1
- package/src/utils/git.ts +315 -15
- package/src/utils/image-loading.ts +65 -4
- package/src/utils/session-color.ts +83 -9
- package/src/utils/thinking-display.ts +37 -0
- package/src/utils/title-generator.ts +73 -10
- package/src/utils/tool-choice.ts +16 -0
- package/src/utils/tools-manager.ts +19 -1
- package/src/web/kagi.ts +28 -26
- package/src/web/parallel.ts +7 -3
- package/src/web/scrapers/arxiv.ts +1 -1
- package/src/web/scrapers/github.ts +351 -3
- package/src/web/scrapers/go-pkg.ts +1 -1
- package/src/web/scrapers/iacr.ts +1 -1
- package/src/web/scrapers/readthedocs.ts +1 -1
- package/src/web/scrapers/twitter.ts +2 -1
- package/src/web/scrapers/types.ts +87 -8
- package/src/web/scrapers/wikipedia.ts +1 -1
- package/src/web/scrapers/youtube.ts +9 -3
- package/src/web/search/index.ts +15 -2
- package/src/web/search/providers/anthropic.ts +62 -21
- package/src/web/search/providers/base.ts +2 -1
- package/src/web/search/providers/brave.ts +5 -2
- package/src/web/search/providers/codex.ts +87 -51
- package/src/web/search/providers/exa.ts +101 -10
- package/src/web/search/providers/gemini.ts +49 -24
- package/src/web/search/providers/jina.ts +15 -5
- package/src/web/search/providers/kagi.ts +9 -2
- package/src/web/search/providers/kimi.ts +45 -20
- package/src/web/search/providers/parallel.ts +39 -24
- package/src/web/search/providers/perplexity.ts +226 -63
- package/src/web/search/providers/searxng.ts +19 -3
- package/src/web/search/providers/synthetic.ts +16 -11
- package/src/web/search/providers/tavily.ts +12 -9
- package/src/web/search/providers/zai.ts +22 -9
- package/src/web/search/render.ts +59 -64
- package/src/web/search/types.ts +5 -1
- package/dist/types/discovery/context-files.d.ts +0 -17
- package/dist/types/exa/factory.d.ts +0 -13
- package/dist/types/exa/render.d.ts +0 -19
- package/dist/types/exa/researcher.d.ts +0 -9
- package/dist/types/exa/search.d.ts +0 -9
- package/dist/types/exa/websets.d.ts +0 -9
- package/dist/types/export/html/template.generated.d.ts +0 -1
- package/dist/types/modes/components/session-observer-overlay.d.ts +0 -11
- package/dist/types/modes/components/status-line.d.ts +0 -77
- package/dist/types/slash-commands/headless-plan.d.ts +0 -3
- package/dist/types/stt/setup.d.ts +0 -18
- package/scripts/generate-template.ts +0 -33
- package/src/discovery/context-files.ts +0 -49
- package/src/exa/factory.ts +0 -60
- package/src/exa/render.ts +0 -244
- package/src/exa/researcher.ts +0 -36
- package/src/exa/search.ts +0 -47
- package/src/exa/websets.ts +0 -248
- package/src/export/html/template.generated.ts +0 -2
- package/src/modes/components/session-observer-overlay.ts +0 -852
- package/src/slash-commands/headless-plan.ts +0 -142
- package/src/stt/setup.ts +0 -52
- package/src/stt/transcribe.py +0 -70
- /package/dist/types/extensibility/{legacy-pi-coding-agent-shim.d.ts → legacy-package-agent-shim.d.ts} +0 -0
- /package/src/extensibility/{legacy-pi-coding-agent-shim.ts → legacy-package-agent-shim.ts} +0 -0
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
* Interactive mode for the coding agent.
|
|
3
3
|
* Handles TUI rendering and user interaction, delegating business logic to AgentSession.
|
|
4
4
|
*/
|
|
5
|
+
|
|
5
6
|
import * as fs from "node:fs/promises";
|
|
6
7
|
import * as path from "node:path";
|
|
7
8
|
import {
|
|
@@ -12,15 +13,16 @@ import {
|
|
|
12
13
|
ThinkingLevel,
|
|
13
14
|
} from "@prometheus-ai/agent-core";
|
|
14
15
|
import type { CompactionOutcome } from "@prometheus-ai/agent-core/compaction";
|
|
15
|
-
import {
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
16
|
+
import type { AssistantMessage, ImageContent, Message, Model, UsageReport } from "@prometheus-ai/ai";
|
|
17
|
+
import { modelsAreEqual } from "@prometheus-ai/catalog/models";
|
|
18
|
+
import type {
|
|
19
|
+
Component,
|
|
20
|
+
EditorTheme,
|
|
21
|
+
LoaderMessageColorFn,
|
|
22
|
+
NativeScrollbackLiveRegion,
|
|
23
|
+
OverlayHandle,
|
|
24
|
+
SlashCommand,
|
|
25
|
+
} from "@prometheus-ai/tui";
|
|
24
26
|
import {
|
|
25
27
|
Container,
|
|
26
28
|
clearRenderCache,
|
|
@@ -48,9 +50,10 @@ import {
|
|
|
48
50
|
} from "@prometheus-ai/utils";
|
|
49
51
|
import chalk from "chalk";
|
|
50
52
|
import { reset as resetCapabilities } from "../capability";
|
|
53
|
+
import type { CollabGuestLink } from "../collab/guest";
|
|
54
|
+
import type { CollabHost } from "../collab/host";
|
|
51
55
|
import { KeybindingsManager } from "../config/keybindings";
|
|
52
|
-
import {
|
|
53
|
-
import { isSettingsInitialized, Settings, settings } from "../config/settings";
|
|
56
|
+
import { isSettingsInitialized, onStatusLineSessionAccentChanged, Settings, settings } from "../config/settings";
|
|
54
57
|
import { clearClaudePluginRootsCache } from "../discovery/helpers";
|
|
55
58
|
import type {
|
|
56
59
|
ContextUsage,
|
|
@@ -61,14 +64,17 @@ import type {
|
|
|
61
64
|
ExtensionWidgetOptions,
|
|
62
65
|
} from "../extensibility/extensions";
|
|
63
66
|
import type { CompactOptions } from "../extensibility/extensions/types";
|
|
64
|
-
import {
|
|
67
|
+
import { loadSlashCommands } from "../extensibility/slash-commands";
|
|
68
|
+
import { type GuidedGoalMessage, runGuidedGoalTurn } from "../goals/guided-setup";
|
|
65
69
|
import type { Goal, GoalModeState } from "../goals/state";
|
|
66
70
|
import { resolveLocalUrlToPath } from "../internal-urls";
|
|
67
71
|
import { LSP_STARTUP_EVENT_CHANNEL, type LspStartupEvent } from "../lsp/startup-events";
|
|
72
|
+
import type { MCPManager } from "../mcp";
|
|
73
|
+
import { formatMCPConnectingMessage, isMcpConnectingEvent, MCP_CONNECTING_EVENT_CHANNEL } from "../mcp/startup-events";
|
|
68
74
|
import {
|
|
69
75
|
humanizePlanTitle,
|
|
70
76
|
type PlanApprovalDetails,
|
|
71
|
-
|
|
77
|
+
resolveApprovedPlan,
|
|
72
78
|
resolvePlanTitle,
|
|
73
79
|
} from "../plan-mode/approved-plan";
|
|
74
80
|
import planModeApprovedPrompt from "../prompts/system/plan-mode-approved.md" with { type: "text" };
|
|
@@ -77,23 +83,30 @@ import planModeCompactInstructionsPrompt from "../prompts/system/plan-mode-compa
|
|
|
77
83
|
};
|
|
78
84
|
import type { AgentSession, AgentSessionEvent, ResolvedRoleModel } from "../session/agent-session";
|
|
79
85
|
import { HistoryStorage } from "../session/history-storage";
|
|
80
|
-
import type { SessionContext
|
|
81
|
-
import { getRecentSessions } from "../session/session-
|
|
86
|
+
import type { SessionContext } from "../session/session-context";
|
|
87
|
+
import { getRecentSessions } from "../session/session-listing";
|
|
88
|
+
import type { SessionManager } from "../session/session-manager";
|
|
82
89
|
import type { ShakeMode } from "../session/shake-types";
|
|
90
|
+
import { BUILTIN_SLASH_COMMAND_RESERVED_NAMES, BUILTIN_SLASH_COMMANDS } from "../slash-commands/builtin-registry";
|
|
83
91
|
import { formatDuration } from "../slash-commands/helpers/format";
|
|
84
92
|
import { STTController, type SttState } from "../stt";
|
|
93
|
+
import { discoverTitleSystemPromptFile, resolvePromptInput } from "../system-prompt";
|
|
94
|
+
import { formatTaskId } from "../task/render";
|
|
85
95
|
import type { LspStartupServerInfo } from "../tools";
|
|
86
96
|
import { normalizeLocalScheme } from "../tools/path-utils";
|
|
97
|
+
import { replaceTabs, TRUNCATE_LENGTHS, truncateToWidth } from "../tools/render-utils";
|
|
87
98
|
import { setAutoQaConsentHandler } from "../tools/report-tool-issue";
|
|
88
99
|
import { type ResolveToolDetails, runResolveInvocation } from "../tools/resolve";
|
|
89
100
|
import { formatPhaseDisplayName, selectStickyTodoWindow, todoMatchesAnyDescription } from "../tools/todo";
|
|
90
101
|
import { ToolError } from "../tools/tool-errors";
|
|
102
|
+
import { vocalizer } from "../tts/vocalizer";
|
|
91
103
|
import type { EventBus } from "../utils/event-bus";
|
|
92
104
|
import { getEditorCommand, openInEditor } from "../utils/external-editor";
|
|
93
105
|
import { getSessionAccentAnsi, getSessionAccentHex } from "../utils/session-color";
|
|
94
106
|
import { popTerminalTitle, pushTerminalTitle, setSessionTerminalTitle } from "../utils/title-generator";
|
|
95
107
|
import type { AssistantMessageComponent } from "./components/assistant-message";
|
|
96
108
|
import type { BashExecutionComponent } from "./components/bash-execution";
|
|
109
|
+
import { ChatBlock, type ChatBlockHost } from "./components/chat-block";
|
|
97
110
|
import { CustomEditor } from "./components/custom-editor";
|
|
98
111
|
import { DynamicBorder } from "./components/dynamic-border";
|
|
99
112
|
import { ErrorBannerComponent } from "./components/error-banner";
|
|
@@ -101,6 +114,7 @@ import type { EvalExecutionComponent } from "./components/eval-execution";
|
|
|
101
114
|
import type { HookEditorComponent } from "./components/hook-editor";
|
|
102
115
|
import type { HookInputComponent } from "./components/hook-input";
|
|
103
116
|
import type { HookSelectorComponent, HookSelectorSlider } from "./components/hook-selector";
|
|
117
|
+
import { PlanReviewOverlay } from "./components/plan-review-overlay";
|
|
104
118
|
import { StatusLineComponent } from "./components/status-line";
|
|
105
119
|
import type { ToolExecutionHandle } from "./components/tool-execution";
|
|
106
120
|
import { TranscriptContainer } from "./components/transcript-container";
|
|
@@ -113,7 +127,9 @@ import { InputController } from "./controllers/input-controller";
|
|
|
113
127
|
import { MCPCommandController } from "./controllers/mcp-command-controller";
|
|
114
128
|
import { OmfgController } from "./controllers/omfg-controller";
|
|
115
129
|
import { SelectorController } from "./controllers/selector-controller";
|
|
130
|
+
import { SessionFocusController } from "./controllers/session-focus-controller";
|
|
116
131
|
import { SSHCommandController } from "./controllers/ssh-command-controller";
|
|
132
|
+
import { TanCommandController } from "./controllers/tan-command-controller";
|
|
117
133
|
import { TodoCommandController } from "./controllers/todo-command-controller";
|
|
118
134
|
import {
|
|
119
135
|
consumeLoopLimitIteration,
|
|
@@ -125,9 +141,11 @@ import {
|
|
|
125
141
|
parseLoopLimitArgs,
|
|
126
142
|
} from "./loop-limit";
|
|
127
143
|
import { OAuthManualInputManager } from "./oauth-manual-input";
|
|
144
|
+
import type { ObservableSession } from "./session-observer-registry";
|
|
128
145
|
import { SessionObserverRegistry } from "./session-observer-registry";
|
|
146
|
+
import { runProviderSetupWizard } from "./setup-wizard/lazy";
|
|
129
147
|
import { interruptHint } from "./shared";
|
|
130
|
-
import { type ShimmerPalette, shimmerSegments, shimmerText } from "./theme/shimmer";
|
|
148
|
+
import { type ShimmerPalette, shimmerEnabled, shimmerSegments, shimmerText } from "./theme/shimmer";
|
|
131
149
|
import type { Theme } from "./theme/theme";
|
|
132
150
|
import {
|
|
133
151
|
getEditorTheme,
|
|
@@ -159,6 +177,12 @@ interface WorkingMessageAccent {
|
|
|
159
177
|
dim: string;
|
|
160
178
|
}
|
|
161
179
|
|
|
180
|
+
interface WorkingMessageAccentCacheKey {
|
|
181
|
+
sessionName: string | undefined;
|
|
182
|
+
accentSurfaceLuminance: number | undefined;
|
|
183
|
+
sessionAccentEnabled: boolean;
|
|
184
|
+
}
|
|
185
|
+
|
|
162
186
|
function renderWorkingMessage(message: string, accent?: WorkingMessageAccent): string {
|
|
163
187
|
const palette = accent
|
|
164
188
|
? ({
|
|
@@ -191,6 +215,25 @@ const EDITOR_MAX_HEIGHT_MIN = 6;
|
|
|
191
215
|
const EDITOR_MAX_HEIGHT_MAX = 18;
|
|
192
216
|
const EDITOR_RESERVED_ROWS = 12;
|
|
193
217
|
const EDITOR_FALLBACK_ROWS = 24;
|
|
218
|
+
const EDITOR_MIN_CHROME_ROWS = 4; // rows reserved for transcript + status on small terms
|
|
219
|
+
const EDITOR_MIN_RENDERED_ROWS = 3; // bordered editor floor: top+bottom border + 1 content row
|
|
220
|
+
|
|
221
|
+
/**
|
|
222
|
+
* Editor max-height cap for a terminal of `terminalRows` rows.
|
|
223
|
+
*
|
|
224
|
+
* Roomy terminals get the comfortable [6, 18] band. Small terminals shrink the
|
|
225
|
+
* cap so the editor leaves at least EDITOR_MIN_CHROME_ROWS rows for the
|
|
226
|
+
* transcript + status line. The editor is bordered, so it never renders fewer
|
|
227
|
+
* than EDITOR_MIN_RENDERED_ROWS rows; once the terminal is too small for both
|
|
228
|
+
* (terminalRows < EDITOR_MIN_RENDERED_ROWS + EDITOR_MIN_CHROME_ROWS) the cap is
|
|
229
|
+
* pinned to that floor — returning a smaller number would not shrink the editor
|
|
230
|
+
* any further, it would only misreport the rows it actually occupies.
|
|
231
|
+
*/
|
|
232
|
+
export function computeEditorMaxHeight(terminalRows: number): number {
|
|
233
|
+
const rows = Number.isFinite(terminalRows) && terminalRows > 0 ? terminalRows : EDITOR_FALLBACK_ROWS;
|
|
234
|
+
const comfortable = Math.max(EDITOR_MAX_HEIGHT_MIN, Math.min(EDITOR_MAX_HEIGHT_MAX, rows - EDITOR_RESERVED_ROWS));
|
|
235
|
+
return Math.max(EDITOR_MIN_RENDERED_ROWS, Math.min(comfortable, rows - EDITOR_MIN_CHROME_ROWS));
|
|
236
|
+
}
|
|
194
237
|
|
|
195
238
|
const HUD_NOTE_SUP_DIGITS: Record<string, string> = {
|
|
196
239
|
"0": "\u2070",
|
|
@@ -250,6 +293,63 @@ export interface InteractiveModeOptions {
|
|
|
250
293
|
initialMessages?: string[];
|
|
251
294
|
}
|
|
252
295
|
|
|
296
|
+
/**
|
|
297
|
+
* Hosts the working loader and transient status rows. While anything is
|
|
298
|
+
* mounted, every row is live: report a seam at 0 so the engine never commits
|
|
299
|
+
* a still-animating loader to native scrollback (stale `Working…` rows would
|
|
300
|
+
* otherwise pile up above the live one). The transcript's own seam, when
|
|
301
|
+
* present, sits higher and wins (topmost-seam merge in TUI.render).
|
|
302
|
+
*/
|
|
303
|
+
class StatusContainer extends Container implements NativeScrollbackLiveRegion {
|
|
304
|
+
getNativeScrollbackLiveRegionStart(): number | undefined {
|
|
305
|
+
return this.children.length > 0 ? 0 : undefined;
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
/** How long the ctrl+p model-role cycle chip track lingers above the editor
|
|
310
|
+
* before it auto-clears, mirroring the todo HUD's auto-clear timer. */
|
|
311
|
+
const MODEL_CYCLE_TRACK_CLEAR_MS = 4000;
|
|
312
|
+
|
|
313
|
+
/**
|
|
314
|
+
* Build the anchored subagent HUD block: a bold accent "Subagents" header plus
|
|
315
|
+
* one hooked row per running agent in the same `Id: description` shape the
|
|
316
|
+
* inline task rows use (muted task preview when no description was given).
|
|
317
|
+
* Only detached background spawns are listed: a sync task call blocks the
|
|
318
|
+
* parent turn and its inline tool block already renders progress live, and
|
|
319
|
+
* eval `agent()` spawns are rendered by their own eval cell tree.
|
|
320
|
+
* Returns an empty array when nothing is running so the container can clear.
|
|
321
|
+
*/
|
|
322
|
+
export function renderSubagentHudLines(sessions: ObservableSession[], columns: number): string[] {
|
|
323
|
+
const running = sessions.filter(
|
|
324
|
+
session => session.kind === "subagent" && session.status === "active" && session.detached === true,
|
|
325
|
+
);
|
|
326
|
+
if (running.length === 0) return [];
|
|
327
|
+
|
|
328
|
+
const indent = " ";
|
|
329
|
+
const hook = theme.tree.hook;
|
|
330
|
+
const dot = theme.styledSymbol("status.done", "accent");
|
|
331
|
+
const lines = ["", indent + theme.bold(theme.fg("accent", "Subagents"))];
|
|
332
|
+
running.forEach((session, index) => {
|
|
333
|
+
const prefix = `${indent}${index === 0 ? hook : " "} `;
|
|
334
|
+
const displayId = formatTaskId(session.id);
|
|
335
|
+
let line = `${prefix}${dot} ${theme.fg("accent", theme.bold(displayId))}`;
|
|
336
|
+
const description = session.description?.trim() || session.progress?.description?.trim();
|
|
337
|
+
if (description) {
|
|
338
|
+
const budget = Math.max(TRUNCATE_LENGTHS.SHORT, columns - visibleWidth(prefix) - visibleWidth(displayId) - 6);
|
|
339
|
+
line += `${theme.fg("accent", ":")} ${theme.fg("accent", truncateToWidth(replaceTabs(description), budget))}`;
|
|
340
|
+
} else {
|
|
341
|
+
// No spawn description: fall back to a muted task preview, same as
|
|
342
|
+
// the inline task rows when a row has no label.
|
|
343
|
+
const taskPreview = session.progress?.task?.trim();
|
|
344
|
+
if (taskPreview) {
|
|
345
|
+
line += ` ${theme.fg("muted", truncateToWidth(replaceTabs(taskPreview), TRUNCATE_LENGTHS.SHORT))}`;
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
lines.push(line);
|
|
349
|
+
});
|
|
350
|
+
return lines;
|
|
351
|
+
}
|
|
352
|
+
|
|
253
353
|
export class InteractiveMode implements InteractiveModeContext {
|
|
254
354
|
session: AgentSession;
|
|
255
355
|
sessionManager: SessionManager;
|
|
@@ -257,15 +357,18 @@ export class InteractiveMode implements InteractiveModeContext {
|
|
|
257
357
|
keybindings: KeybindingsManager;
|
|
258
358
|
agent: Agent;
|
|
259
359
|
historyStorage?: HistoryStorage;
|
|
360
|
+
titleSystemPrompt?: string;
|
|
260
361
|
|
|
261
362
|
ui: TUI;
|
|
262
363
|
chatContainer: TranscriptContainer;
|
|
263
364
|
pendingMessagesContainer: Container;
|
|
264
365
|
statusContainer: Container;
|
|
265
366
|
todoContainer: Container;
|
|
367
|
+
subagentContainer: Container;
|
|
266
368
|
btwContainer: Container;
|
|
267
369
|
omfgContainer: Container;
|
|
268
370
|
errorBannerContainer: Container;
|
|
371
|
+
modelCycleContainer: Container;
|
|
269
372
|
editor: CustomEditor;
|
|
270
373
|
editorContainer: Container;
|
|
271
374
|
hookWidgetContainerAbove: Container;
|
|
@@ -273,7 +376,6 @@ export class InteractiveMode implements InteractiveModeContext {
|
|
|
273
376
|
statusLine: StatusLineComponent;
|
|
274
377
|
|
|
275
378
|
isInitialized = false;
|
|
276
|
-
isBackgrounded = false;
|
|
277
379
|
isBashMode = false;
|
|
278
380
|
toolOutputExpanded = false;
|
|
279
381
|
todoExpanded = false;
|
|
@@ -287,6 +389,7 @@ export class InteractiveMode implements InteractiveModeContext {
|
|
|
287
389
|
loopLimit: LoopLimitRuntime | undefined = undefined;
|
|
288
390
|
#loopAutoSubmitTimer: NodeJS.Timeout | undefined;
|
|
289
391
|
#todoAutoClearTimer: NodeJS.Timeout | undefined;
|
|
392
|
+
#modelCycleClearTimer: NodeJS.Timeout | undefined;
|
|
290
393
|
todoPhases: TodoPhase[] = [];
|
|
291
394
|
hideThinkingBlock = false;
|
|
292
395
|
pendingImages: ImageContent[] = [];
|
|
@@ -304,11 +407,12 @@ export class InteractiveMode implements InteractiveModeContext {
|
|
|
304
407
|
autoCompactionLoader: Loader | undefined = undefined;
|
|
305
408
|
retryLoader: Loader | undefined = undefined;
|
|
306
409
|
#pendingWorkingMessage: string | undefined;
|
|
410
|
+
#workingMessageAccentCacheKey?: WorkingMessageAccentCacheKey;
|
|
411
|
+
#workingMessageAccentCacheValue?: WorkingMessageAccent;
|
|
412
|
+
#workingMessageAccentCacheHasValue = false;
|
|
307
413
|
get #defaultWorkingMessage(): string {
|
|
308
414
|
return `Working…${interruptHint()}`;
|
|
309
415
|
}
|
|
310
|
-
autoCompactionEscapeHandler?: () => void;
|
|
311
|
-
retryEscapeHandler?: () => void;
|
|
312
416
|
unsubscribe?: () => void;
|
|
313
417
|
onInputCallback?: (input: SubmittedUserInput) => void;
|
|
314
418
|
optimisticUserMessageSignature: string | undefined = undefined;
|
|
@@ -317,6 +421,7 @@ export class InteractiveMode implements InteractiveModeContext {
|
|
|
317
421
|
#pendingSubmissionDispose: (() => void) | undefined;
|
|
318
422
|
lastSigintTime = 0;
|
|
319
423
|
lastEscapeTime = 0;
|
|
424
|
+
lastLeftTapTime = 0;
|
|
320
425
|
shutdownRequested = false;
|
|
321
426
|
#isShuttingDown = false;
|
|
322
427
|
hookSelector: HookSelectorComponent | undefined = undefined;
|
|
@@ -327,6 +432,8 @@ export class InteractiveMode implements InteractiveModeContext {
|
|
|
327
432
|
fileSlashCommands: Set<string> = new Set();
|
|
328
433
|
skillCommands: Map<string, string> = new Map();
|
|
329
434
|
oauthManualInput: OAuthManualInputManager = new OAuthManualInputManager();
|
|
435
|
+
collabHost?: CollabHost;
|
|
436
|
+
collabGuest?: CollabGuestLink;
|
|
330
437
|
|
|
331
438
|
#pendingSlashCommands: SlashCommand[] = [];
|
|
332
439
|
#cleanupUnsubscribe?: () => void;
|
|
@@ -341,19 +448,57 @@ export class InteractiveMode implements InteractiveModeContext {
|
|
|
341
448
|
#planModePreviousModelState: { model: Model; thinkingLevel?: ThinkingLevel } | undefined;
|
|
342
449
|
#pendingModelSwitch: { model: Model; thinkingLevel?: ThinkingLevel } | undefined;
|
|
343
450
|
#planModeHasEntered = false;
|
|
344
|
-
#
|
|
451
|
+
#planReviewOverlay: PlanReviewOverlay | undefined;
|
|
452
|
+
#planReviewOverlayHandle: OverlayHandle | undefined;
|
|
345
453
|
readonly lspServers: LspStartupServerInfo[] | undefined = undefined;
|
|
346
|
-
mcpManager?:
|
|
454
|
+
mcpManager?: MCPManager;
|
|
347
455
|
readonly #toolUiContextSetter: (uiContext: ExtensionUIContext, hasUI: boolean) => void;
|
|
348
456
|
|
|
349
457
|
readonly #btwController: BtwController;
|
|
458
|
+
readonly #tanCommandController: TanCommandController;
|
|
350
459
|
readonly #omfgController: OmfgController;
|
|
351
460
|
readonly #commandController: CommandController;
|
|
352
461
|
readonly #todoCommandController: TodoCommandController;
|
|
353
462
|
readonly #eventController: EventController;
|
|
463
|
+
get eventController(): EventController {
|
|
464
|
+
return this.#eventController;
|
|
465
|
+
}
|
|
466
|
+
get eventBus(): EventBus | undefined {
|
|
467
|
+
return this.#eventBus;
|
|
468
|
+
}
|
|
354
469
|
readonly #extensionUiController: ExtensionUiController;
|
|
355
470
|
readonly #inputController: InputController;
|
|
356
471
|
readonly #selectorController: SelectorController;
|
|
472
|
+
readonly #focusController: SessionFocusController;
|
|
473
|
+
get viewSession(): AgentSession {
|
|
474
|
+
return this.#focusController.target ?? this.session;
|
|
475
|
+
}
|
|
476
|
+
get focusedAgentId(): string | undefined {
|
|
477
|
+
return this.#focusController.focusedAgentId;
|
|
478
|
+
}
|
|
479
|
+
focusAgentSession(id: string): Promise<void> {
|
|
480
|
+
return this.#focusController.focusAgent(id);
|
|
481
|
+
}
|
|
482
|
+
focusParentSession(): Promise<void> {
|
|
483
|
+
return this.#focusController.focusParent();
|
|
484
|
+
}
|
|
485
|
+
unfocusSession(): Promise<void> {
|
|
486
|
+
return this.#focusController.unfocus();
|
|
487
|
+
}
|
|
488
|
+
clearTransientSessionUi(): void {
|
|
489
|
+
if (this.loadingAnimation) {
|
|
490
|
+
this.loadingAnimation.stop();
|
|
491
|
+
this.loadingAnimation = undefined;
|
|
492
|
+
}
|
|
493
|
+
this.statusContainer.clear();
|
|
494
|
+
this.pendingMessagesContainer.clear();
|
|
495
|
+
this.#cancelModelCycleClearTimer();
|
|
496
|
+
this.modelCycleContainer.clear();
|
|
497
|
+
this.compactionQueuedMessages = [];
|
|
498
|
+
this.streamingComponent = undefined;
|
|
499
|
+
this.streamingMessage = undefined;
|
|
500
|
+
this.pendingTools.clear();
|
|
501
|
+
}
|
|
357
502
|
readonly #uiHelpers: UiHelpers;
|
|
358
503
|
#sttController: STTController | undefined;
|
|
359
504
|
#voiceAnimationInterval: NodeJS.Timeout | undefined;
|
|
@@ -365,6 +510,7 @@ export class InteractiveMode implements InteractiveModeContext {
|
|
|
365
510
|
#eventBus?: EventBus;
|
|
366
511
|
#eventBusUnsubscribers: Array<() => void> = [];
|
|
367
512
|
#welcomeComponent?: WelcomeComponent;
|
|
513
|
+
readonly #chatHost: ChatBlockHost = { requestRender: () => this.ui.requestRender() };
|
|
368
514
|
|
|
369
515
|
constructor(
|
|
370
516
|
session: AgentSession,
|
|
@@ -372,8 +518,9 @@ export class InteractiveMode implements InteractiveModeContext {
|
|
|
372
518
|
changelogMarkdown: string | undefined = undefined,
|
|
373
519
|
setToolUIContext: (uiContext: ExtensionUIContext, hasUI: boolean) => void = () => {},
|
|
374
520
|
lspServers: LspStartupServerInfo[] | undefined = undefined,
|
|
375
|
-
mcpManager?:
|
|
521
|
+
mcpManager?: MCPManager,
|
|
376
522
|
eventBus?: EventBus,
|
|
523
|
+
titleSystemPrompt?: string,
|
|
377
524
|
) {
|
|
378
525
|
this.session = session;
|
|
379
526
|
this.sessionManager = session.sessionManager;
|
|
@@ -386,16 +533,25 @@ export class InteractiveMode implements InteractiveModeContext {
|
|
|
386
533
|
this.lspServers = lspServers;
|
|
387
534
|
this.mcpManager = mcpManager;
|
|
388
535
|
this.#eventBus = eventBus;
|
|
536
|
+
this.titleSystemPrompt = titleSystemPrompt;
|
|
389
537
|
if (eventBus) {
|
|
390
538
|
this.#eventBusUnsubscribers.push(
|
|
391
539
|
eventBus.on(LSP_STARTUP_EVENT_CHANNEL, data => {
|
|
392
540
|
this.#handleLspStartupEvent(data as LspStartupEvent);
|
|
393
541
|
}),
|
|
394
542
|
);
|
|
543
|
+
this.#eventBusUnsubscribers.push(
|
|
544
|
+
eventBus.on(MCP_CONNECTING_EVENT_CHANNEL, data => {
|
|
545
|
+
if (!isMcpConnectingEvent(data)) {
|
|
546
|
+
logger.warn("Ignoring malformed mcp:connecting event", { data });
|
|
547
|
+
return;
|
|
548
|
+
}
|
|
549
|
+
this.showStatus(formatMCPConnectingMessage(data.serverNames));
|
|
550
|
+
}),
|
|
551
|
+
);
|
|
395
552
|
}
|
|
396
553
|
|
|
397
554
|
this.ui = new TUI(new ProcessTerminal(), settings.get("showHardwareCursor"));
|
|
398
|
-
this.ui.setClearOnShrink(settings.get("clearOnShrink"));
|
|
399
555
|
this.ui.setMaxInlineImages(settings.get("tui.maxInlineImages"));
|
|
400
556
|
// OSC 66 text-sizing is Kitty-only; resolve the setting against the terminal's
|
|
401
557
|
// capability (`TERMINAL.textSizing` defaults on for Kitty) so it stays off
|
|
@@ -403,11 +559,13 @@ export class InteractiveMode implements InteractiveModeContext {
|
|
|
403
559
|
setTerminalTextSizing(settings.get("tui.textSizing") && TERMINAL.textSizing);
|
|
404
560
|
this.chatContainer = new TranscriptContainer();
|
|
405
561
|
this.pendingMessagesContainer = new Container();
|
|
406
|
-
this.statusContainer = new
|
|
562
|
+
this.statusContainer = new StatusContainer();
|
|
407
563
|
this.todoContainer = new Container();
|
|
564
|
+
this.subagentContainer = new Container();
|
|
408
565
|
this.btwContainer = new Container();
|
|
409
566
|
this.omfgContainer = new Container();
|
|
410
567
|
this.errorBannerContainer = new Container();
|
|
568
|
+
this.modelCycleContainer = new Container();
|
|
411
569
|
this.editor = new CustomEditor(getEditorTheme());
|
|
412
570
|
this.editor.setUseTerminalCursor(this.ui.getShowHardwareCursor());
|
|
413
571
|
this.editor.setAutocompleteMaxVisible(settings.get("autocompleteMaxVisible"));
|
|
@@ -415,8 +573,9 @@ export class InteractiveMode implements InteractiveModeContext {
|
|
|
415
573
|
this.ui.requestRender(true);
|
|
416
574
|
};
|
|
417
575
|
this.editor.onAutocompleteUpdate = () => {
|
|
418
|
-
this.ui.requestRender(
|
|
576
|
+
this.ui.requestRender();
|
|
419
577
|
};
|
|
578
|
+
this.editor.setShimmerRepaintHandler(() => this.ui.requestComponentRender(this.editor));
|
|
420
579
|
this.#syncEditorMaxHeight();
|
|
421
580
|
this.#resizeHandler = () => {
|
|
422
581
|
this.#syncEditorMaxHeight();
|
|
@@ -440,9 +599,8 @@ export class InteractiveMode implements InteractiveModeContext {
|
|
|
440
599
|
|
|
441
600
|
this.hideThinkingBlock = settings.get("hideThinkingBlock");
|
|
442
601
|
|
|
443
|
-
const builtinCommandNames = new Set(BUILTIN_SLASH_COMMANDS.map(c => c.name));
|
|
444
602
|
const hookCommands: SlashCommand[] = (
|
|
445
|
-
this.session.extensionRunner?.getRegisteredCommands(
|
|
603
|
+
this.session.extensionRunner?.getRegisteredCommands(BUILTIN_SLASH_COMMAND_RESERVED_NAMES) ?? []
|
|
446
604
|
).map(cmd => ({
|
|
447
605
|
name: cmd.name,
|
|
448
606
|
description: cmd.description ?? "(hook command)",
|
|
@@ -470,19 +628,25 @@ export class InteractiveMode implements InteractiveModeContext {
|
|
|
470
628
|
|
|
471
629
|
this.#uiHelpers = new UiHelpers(this);
|
|
472
630
|
this.#btwController = new BtwController(this);
|
|
631
|
+
this.#tanCommandController = new TanCommandController(this);
|
|
473
632
|
this.#omfgController = new OmfgController(this);
|
|
474
633
|
this.#extensionUiController = new ExtensionUiController(this);
|
|
475
634
|
this.#eventController = new EventController(this);
|
|
476
635
|
this.#commandController = new CommandController(this);
|
|
477
636
|
this.#todoCommandController = new TodoCommandController(this);
|
|
478
637
|
this.#selectorController = new SelectorController(this);
|
|
638
|
+
this.#focusController = new SessionFocusController(this);
|
|
479
639
|
this.#inputController = new InputController(this);
|
|
480
640
|
this.#observerRegistry = new SessionObserverRegistry();
|
|
481
641
|
}
|
|
482
642
|
|
|
483
643
|
playWelcomeIntro(): void {
|
|
484
|
-
this.#welcomeComponent
|
|
644
|
+
const welcome = this.#welcomeComponent;
|
|
645
|
+
// Component-scoped: the intro only mutates the welcome box's own rows,
|
|
646
|
+
// so a resumed long transcript is not re-walked per animation frame.
|
|
647
|
+
welcome?.playIntro(() => this.ui.requestComponentRender(welcome));
|
|
485
648
|
}
|
|
649
|
+
|
|
486
650
|
async init(options: InteractiveModeInitOptions = {}): Promise<void> {
|
|
487
651
|
if (this.isInitialized) return;
|
|
488
652
|
|
|
@@ -567,9 +731,11 @@ export class InteractiveMode implements InteractiveModeContext {
|
|
|
567
731
|
this.ui.addChild(this.pendingMessagesContainer);
|
|
568
732
|
this.ui.addChild(this.statusContainer);
|
|
569
733
|
this.ui.addChild(this.todoContainer);
|
|
734
|
+
this.ui.addChild(this.subagentContainer);
|
|
570
735
|
this.ui.addChild(this.btwContainer);
|
|
571
736
|
this.ui.addChild(this.omfgContainer);
|
|
572
737
|
this.ui.addChild(this.errorBannerContainer);
|
|
738
|
+
this.ui.addChild(this.modelCycleContainer);
|
|
573
739
|
this.ui.addChild(this.statusLine); // Only renders hook statuses (main status in editor border)
|
|
574
740
|
this.ui.addChild(this.hookWidgetContainerAbove);
|
|
575
741
|
this.ui.addChild(this.editorContainer);
|
|
@@ -593,14 +759,16 @@ export class InteractiveMode implements InteractiveModeContext {
|
|
|
593
759
|
this.#reconcileTodosWithSubagents();
|
|
594
760
|
this.#syncTodoAutoClearTimer();
|
|
595
761
|
this.#renderTodoList();
|
|
762
|
+
this.#renderSubagentList();
|
|
596
763
|
this.ui.requestRender();
|
|
597
764
|
});
|
|
598
765
|
|
|
599
766
|
// Load initial todos
|
|
600
767
|
await this.#loadTodoList();
|
|
601
768
|
|
|
602
|
-
// Start the UI
|
|
603
|
-
|
|
769
|
+
// Start the UI. Cold `prometheus` launch opts into clearing on the first paint so
|
|
770
|
+
// the initial welcome frame does not append over the previous run's scrollback.
|
|
771
|
+
this.ui.start({ clearScrollback: options.clearInitialTerminalHistory === true });
|
|
604
772
|
pushTerminalTitle();
|
|
605
773
|
setSessionTerminalTitle(this.sessionManager.getSessionName(), this.sessionManager.getCwd());
|
|
606
774
|
this.updateEditorBorderColor();
|
|
@@ -636,9 +804,17 @@ export class InteractiveMode implements InteractiveModeContext {
|
|
|
636
804
|
this.session.subscribe(event => {
|
|
637
805
|
void this.#handleGoalSessionEvent(event);
|
|
638
806
|
}),
|
|
807
|
+
this.sessionManager.onSessionNameChanged(() => {
|
|
808
|
+
this.#handleSessionAccentInputsChanged();
|
|
809
|
+
}),
|
|
810
|
+
onStatusLineSessionAccentChanged(() => {
|
|
811
|
+
this.#syncStatusLineSettings();
|
|
812
|
+
this.#handleSessionAccentInputsChanged();
|
|
813
|
+
}),
|
|
639
814
|
);
|
|
640
815
|
// Set up theme file watcher
|
|
641
816
|
onThemeChange(() => {
|
|
817
|
+
this.#clearWorkingMessageAccentCache();
|
|
642
818
|
clearRenderCache();
|
|
643
819
|
this.ui.invalidate();
|
|
644
820
|
this.updateEditorBorderColor();
|
|
@@ -662,6 +838,13 @@ export class InteractiveMode implements InteractiveModeContext {
|
|
|
662
838
|
this.updateEditorTopBorder();
|
|
663
839
|
}
|
|
664
840
|
|
|
841
|
+
/** Reload the title-generation system prompt override for the provided working directory. */
|
|
842
|
+
async refreshTitleSystemPrompt(cwd?: string): Promise<void> {
|
|
843
|
+
const basePath = cwd ?? this.sessionManager.getCwd();
|
|
844
|
+
const titleSystemPromptSource = discoverTitleSystemPromptFile(basePath);
|
|
845
|
+
this.titleSystemPrompt = await resolvePromptInput(titleSystemPromptSource, "title system prompt");
|
|
846
|
+
}
|
|
847
|
+
|
|
665
848
|
/** Reload slash commands and autocomplete for the provided working directory. */
|
|
666
849
|
async refreshSlashCommandState(cwd?: string): Promise<void> {
|
|
667
850
|
const basePath = cwd ?? this.sessionManager.getCwd();
|
|
@@ -671,8 +854,30 @@ export class InteractiveMode implements InteractiveModeContext {
|
|
|
671
854
|
name: cmd.name,
|
|
672
855
|
description: cmd.description,
|
|
673
856
|
}));
|
|
857
|
+
// Surface discovered prompt templates in the picker. AgentSession.prompt() expands
|
|
858
|
+
// `expandSlashCommand` before `expandPromptTemplate`, and builtin command
|
|
859
|
+
// execution resolves aliases before template expansion. Mirror that command
|
|
860
|
+
// resolution order by skipping templates whose names already appear in any
|
|
861
|
+
// builtin/hook/custom/skill/file command token.
|
|
862
|
+
const reservedNames = new Set<string>();
|
|
863
|
+
for (const command of this.#pendingSlashCommands) {
|
|
864
|
+
reservedNames.add(command.name);
|
|
865
|
+
for (const alias of command.aliases ?? []) reservedNames.add(alias);
|
|
866
|
+
}
|
|
867
|
+
for (const command of fileSlashCommands) {
|
|
868
|
+
reservedNames.add(command.name);
|
|
869
|
+
for (const alias of command.aliases ?? []) reservedNames.add(alias);
|
|
870
|
+
}
|
|
871
|
+
const promptTemplateCommands: SlashCommand[] = this.session.promptTemplates
|
|
872
|
+
.filter(template => !reservedNames.has(template.name))
|
|
873
|
+
.map(template => ({
|
|
874
|
+
name: template.name,
|
|
875
|
+
// `PromptTemplate.description` from `loadTemplatesFromDir` already includes the
|
|
876
|
+
// source suffix (e.g. "Review code (project)"), so pass it through verbatim.
|
|
877
|
+
description: template.description,
|
|
878
|
+
}));
|
|
674
879
|
const autocompleteProvider = this.#inputController.createAutocompleteProvider(
|
|
675
|
-
[...this.#pendingSlashCommands, ...fileSlashCommands],
|
|
880
|
+
[...this.#pendingSlashCommands, ...fileSlashCommands, ...promptTemplateCommands],
|
|
676
881
|
basePath,
|
|
677
882
|
);
|
|
678
883
|
this.editor.setAutocompleteProvider(autocompleteProvider);
|
|
@@ -696,6 +901,7 @@ export class InteractiveMode implements InteractiveModeContext {
|
|
|
696
901
|
// Re-warm plugin roots, capabilities, slash commands, and the ssh tool so
|
|
697
902
|
// the next prompt sees everything scoped to the new project directory.
|
|
698
903
|
clearClaudePluginRootsCache();
|
|
904
|
+
await this.refreshTitleSystemPrompt(newCwd);
|
|
699
905
|
resetCapabilities();
|
|
700
906
|
await this.refreshSlashCommandState(newCwd);
|
|
701
907
|
await this.session.refreshSshTool({ activateIfAvailable: true });
|
|
@@ -765,6 +971,14 @@ export class InteractiveMode implements InteractiveModeContext {
|
|
|
765
971
|
this.#goalContinuationTimer = undefined;
|
|
766
972
|
if (!this.onInputCallback) return;
|
|
767
973
|
if (!this.goalModeEnabled || this.goalModePaused) return;
|
|
974
|
+
// The 800ms timer can outlive the idle window that scheduled it: a
|
|
975
|
+
// `/goal set` taken via the streaming branch (or any extension/hook
|
|
976
|
+
// path that starts a turn while we wait) leaves the agent busy. Firing
|
|
977
|
+
// the continuation now would route through `submitInteractiveInput` →
|
|
978
|
+
// `promptCustomMessage` with no `streamingBehavior` and resurface
|
|
979
|
+
// `AgentBusyError`. Drop this tick; `#handleGoalSessionEvent` reschedules
|
|
980
|
+
// on the next `agent_end`.
|
|
981
|
+
if (this.#isAutoSubmitBlocked()) return;
|
|
768
982
|
if (this.#pendingSubmittedInput) return;
|
|
769
983
|
if (this.editor.getText().trim().length > 0) return;
|
|
770
984
|
if ((this.pendingImages?.length ?? 0) > 0) return;
|
|
@@ -788,7 +1002,7 @@ export class InteractiveMode implements InteractiveModeContext {
|
|
|
788
1002
|
}
|
|
789
1003
|
}
|
|
790
1004
|
|
|
791
|
-
#
|
|
1005
|
+
#isAutoSubmitBlocked(): boolean {
|
|
792
1006
|
return this.session.isStreaming || this.session.isCompacting || this.session.hasPostPromptWork;
|
|
793
1007
|
}
|
|
794
1008
|
|
|
@@ -798,7 +1012,7 @@ export class InteractiveMode implements InteractiveModeContext {
|
|
|
798
1012
|
this.disableLoopMode("Loop time limit reached. Loop mode disabled.");
|
|
799
1013
|
return;
|
|
800
1014
|
}
|
|
801
|
-
if (this.#
|
|
1015
|
+
if (this.#isAutoSubmitBlocked()) {
|
|
802
1016
|
this.#deferLoopAutoSubmit(() => this.#submitLoopPromptWhenReady(prompt));
|
|
803
1017
|
return;
|
|
804
1018
|
}
|
|
@@ -807,7 +1021,7 @@ export class InteractiveMode implements InteractiveModeContext {
|
|
|
807
1021
|
|
|
808
1022
|
async #runLoopIteration(action: "prompt" | "compact" | "reset", prompt: string): Promise<void> {
|
|
809
1023
|
if (!this.loopModeEnabled || this.loopPrompt !== prompt || !this.onInputCallback) return;
|
|
810
|
-
if (this.#
|
|
1024
|
+
if (this.#isAutoSubmitBlocked()) {
|
|
811
1025
|
this.#deferLoopAutoSubmit(() => {
|
|
812
1026
|
void this.#runLoopIteration(action, prompt);
|
|
813
1027
|
});
|
|
@@ -935,13 +1149,6 @@ export class InteractiveMode implements InteractiveModeContext {
|
|
|
935
1149
|
}
|
|
936
1150
|
this.editor.setText("");
|
|
937
1151
|
this.editor.imageLinks = undefined;
|
|
938
|
-
// Reconciliation checkpoint: only retire frozen block snapshots after TUI
|
|
939
|
-
// proves the native viewport is at the tail and replays scrollback safely.
|
|
940
|
-
// Unknown host viewports stay frozen; thawing them would expose live rows
|
|
941
|
-
// over stale native history and can yank or duplicate when ED3 is unsafe.
|
|
942
|
-
if (this.ui.refreshNativeScrollbackIfDirty()) {
|
|
943
|
-
this.chatContainer.thaw();
|
|
944
|
-
}
|
|
945
1152
|
this.ensureLoadingAnimation();
|
|
946
1153
|
this.ui.requestRender();
|
|
947
1154
|
return submission;
|
|
@@ -963,9 +1170,7 @@ export class InteractiveMode implements InteractiveModeContext {
|
|
|
963
1170
|
this.#goalContinuationTurnInFlight = false;
|
|
964
1171
|
}
|
|
965
1172
|
if (this.loadingAnimation) {
|
|
966
|
-
this
|
|
967
|
-
this.loadingAnimation = undefined;
|
|
968
|
-
this.statusContainer.clear();
|
|
1173
|
+
this.#stopLoadingAnimation(true);
|
|
969
1174
|
}
|
|
970
1175
|
if (!submission.customType) {
|
|
971
1176
|
this.pendingImages = submission.images ? [...submission.images] : [];
|
|
@@ -1003,24 +1208,38 @@ export class InteractiveMode implements InteractiveModeContext {
|
|
|
1003
1208
|
pendingSubmissionDispose?.();
|
|
1004
1209
|
this.#pendingWorkingMessage = undefined;
|
|
1005
1210
|
if (this.loadingAnimation) {
|
|
1006
|
-
this
|
|
1007
|
-
this.loadingAnimation = undefined;
|
|
1008
|
-
this.statusContainer.clear();
|
|
1211
|
+
this.#stopLoadingAnimation(true);
|
|
1009
1212
|
}
|
|
1010
1213
|
}
|
|
1011
1214
|
}
|
|
1012
1215
|
|
|
1013
1216
|
#computeEditorMaxHeight(): number {
|
|
1014
|
-
|
|
1015
|
-
const terminalRows = Number.isFinite(rows) && rows > 0 ? rows : EDITOR_FALLBACK_ROWS;
|
|
1016
|
-
const maxHeight = terminalRows - EDITOR_RESERVED_ROWS;
|
|
1017
|
-
return Math.max(EDITOR_MAX_HEIGHT_MIN, Math.min(EDITOR_MAX_HEIGHT_MAX, maxHeight));
|
|
1217
|
+
return computeEditorMaxHeight(this.ui.terminal.rows);
|
|
1018
1218
|
}
|
|
1019
1219
|
|
|
1020
1220
|
#syncEditorMaxHeight(): void {
|
|
1021
1221
|
this.editor.setMaxHeight(this.#computeEditorMaxHeight());
|
|
1022
1222
|
}
|
|
1023
1223
|
|
|
1224
|
+
#syncStatusLineSettings(): void {
|
|
1225
|
+
this.statusLine.updateSettings({
|
|
1226
|
+
preset: settings.get("statusLine.preset"),
|
|
1227
|
+
leftSegments: settings.get("statusLine.leftSegments"),
|
|
1228
|
+
rightSegments: settings.get("statusLine.rightSegments"),
|
|
1229
|
+
separator: settings.get("statusLine.separator"),
|
|
1230
|
+
showHookStatus: settings.get("statusLine.showHookStatus"),
|
|
1231
|
+
sessionAccent: settings.get("statusLine.sessionAccent"),
|
|
1232
|
+
transparent: settings.get("statusLine.transparent"),
|
|
1233
|
+
segmentOptions: settings.get("statusLine.segmentOptions"),
|
|
1234
|
+
});
|
|
1235
|
+
}
|
|
1236
|
+
|
|
1237
|
+
#handleSessionAccentInputsChanged(): void {
|
|
1238
|
+
this.#clearWorkingMessageAccentCache();
|
|
1239
|
+
this.statusLine.invalidate();
|
|
1240
|
+
this.updateEditorBorderColor();
|
|
1241
|
+
}
|
|
1242
|
+
|
|
1024
1243
|
updateEditorBorderColor(): void {
|
|
1025
1244
|
if (this.isBashMode) {
|
|
1026
1245
|
this.editor.borderColor = theme.getBashModeBorderColor();
|
|
@@ -1029,7 +1248,9 @@ export class InteractiveMode implements InteractiveModeContext {
|
|
|
1029
1248
|
} else {
|
|
1030
1249
|
const accentEnabled = !isSettingsInitialized() || settings.get("statusLine.sessionAccent") !== false;
|
|
1031
1250
|
const sessionName = accentEnabled ? this.sessionManager.getSessionName() : undefined;
|
|
1032
|
-
const hex = sessionName
|
|
1251
|
+
const hex = sessionName
|
|
1252
|
+
? getSessionAccentHex(sessionName, theme.getMajorThemeColorHexes(), theme.accentSurfaceLuminance)
|
|
1253
|
+
: undefined;
|
|
1033
1254
|
const ansi = getSessionAccentAnsi(hex);
|
|
1034
1255
|
if (ansi) {
|
|
1035
1256
|
this.editor.borderColor = (str: string) => `${ansi}${str}\x1b[39m`;
|
|
@@ -1038,6 +1259,12 @@ export class InteractiveMode implements InteractiveModeContext {
|
|
|
1038
1259
|
this.editor.borderColor = theme.getThinkingBorderColor(level);
|
|
1039
1260
|
}
|
|
1040
1261
|
}
|
|
1262
|
+
if (this.focusedAgentId) {
|
|
1263
|
+
// Focused subagent view: faint the outline so the borrowed session is
|
|
1264
|
+
// visually distinct from the main one.
|
|
1265
|
+
const base = this.editor.borderColor;
|
|
1266
|
+
this.editor.borderColor = (str: string) => `\x1b[2m${base(str)}\x1b[22m`;
|
|
1267
|
+
}
|
|
1041
1268
|
this.updateEditorTopBorder();
|
|
1042
1269
|
this.ui.requestRender();
|
|
1043
1270
|
}
|
|
@@ -1050,8 +1277,34 @@ export class InteractiveMode implements InteractiveModeContext {
|
|
|
1050
1277
|
|
|
1051
1278
|
rebuildChatFromMessages(): void {
|
|
1052
1279
|
this.chatContainer.clear();
|
|
1053
|
-
|
|
1280
|
+
// Full-history transcript: compactions render as inline dividers instead
|
|
1281
|
+
// of restarting the visible conversation (the LLM context still resets).
|
|
1282
|
+
const context = this.viewSession.buildTranscriptSessionContext();
|
|
1054
1283
|
this.renderSessionContext(context);
|
|
1284
|
+
// During the pre-streaming window — after `startPendingSubmission` has
|
|
1285
|
+
// optimistically rendered the user's message but before the user
|
|
1286
|
+
// `message_start` event lands it in `session` entries — any rebuild
|
|
1287
|
+
// (e.g. Ctrl+T toggleThinkingBlockVisibility, theme selector) would
|
|
1288
|
+
// otherwise erase the user's just-submitted message until the first
|
|
1289
|
+
// assistant token arrived (#2372). Once `message_start` fires the
|
|
1290
|
+
// signature is cleared by `EventController`, so this replay is a no-op
|
|
1291
|
+
// post-streaming and cannot duplicate.
|
|
1292
|
+
this.#replayOptimisticUserMessage();
|
|
1293
|
+
}
|
|
1294
|
+
|
|
1295
|
+
#replayOptimisticUserMessage(): void {
|
|
1296
|
+
if (!this.optimisticUserMessageSignature) return;
|
|
1297
|
+
const submission = this.#pendingSubmittedInput;
|
|
1298
|
+
if (!submission || submission.cancelled || submission.customType) return;
|
|
1299
|
+
this.addMessageToChat(
|
|
1300
|
+
{
|
|
1301
|
+
role: "user",
|
|
1302
|
+
content: [{ type: "text", text: submission.text }, ...(submission.images ?? [])],
|
|
1303
|
+
attribution: "user",
|
|
1304
|
+
timestamp: Date.now(),
|
|
1305
|
+
},
|
|
1306
|
+
{ imageLinks: submission.imageLinks },
|
|
1307
|
+
);
|
|
1055
1308
|
}
|
|
1056
1309
|
|
|
1057
1310
|
#formatTodoLine(todo: TodoItem, prefix: string, matched: boolean): string {
|
|
@@ -1161,6 +1414,41 @@ export class InteractiveMode implements InteractiveModeContext {
|
|
|
1161
1414
|
this.#todoAutoClearTimer.unref?.();
|
|
1162
1415
|
}
|
|
1163
1416
|
|
|
1417
|
+
/**
|
|
1418
|
+
* Render the ctrl+p model-role cycle chip track into its own anchored
|
|
1419
|
+
* container (just above the editor), mirroring the todo HUD: the container is
|
|
1420
|
+
* cleared and rebuilt in place on every cycle, so rapid presses or concurrent
|
|
1421
|
+
* chat activity can never stack duplicate tracks into the scrollback.
|
|
1422
|
+
*/
|
|
1423
|
+
showModelCycleTrack(track: string): void {
|
|
1424
|
+
this.#renderModelCycleTrack(track);
|
|
1425
|
+
this.#syncModelCycleClearTimer();
|
|
1426
|
+
this.ui.requestRender();
|
|
1427
|
+
}
|
|
1428
|
+
|
|
1429
|
+
#renderModelCycleTrack(track: string | null): void {
|
|
1430
|
+
this.modelCycleContainer.clear();
|
|
1431
|
+
if (!track) return;
|
|
1432
|
+
this.modelCycleContainer.addChild(new Spacer(1));
|
|
1433
|
+
this.modelCycleContainer.addChild(new Text(track, 1, 0));
|
|
1434
|
+
}
|
|
1435
|
+
|
|
1436
|
+
#cancelModelCycleClearTimer(): void {
|
|
1437
|
+
if (!this.#modelCycleClearTimer) return;
|
|
1438
|
+
clearTimeout(this.#modelCycleClearTimer);
|
|
1439
|
+
this.#modelCycleClearTimer = undefined;
|
|
1440
|
+
}
|
|
1441
|
+
|
|
1442
|
+
#syncModelCycleClearTimer(): void {
|
|
1443
|
+
this.#cancelModelCycleClearTimer();
|
|
1444
|
+
this.#modelCycleClearTimer = setTimeout(() => {
|
|
1445
|
+
this.#modelCycleClearTimer = undefined;
|
|
1446
|
+
this.#renderModelCycleTrack(null);
|
|
1447
|
+
this.ui.requestRender();
|
|
1448
|
+
}, MODEL_CYCLE_TRACK_CLEAR_MS);
|
|
1449
|
+
this.#modelCycleClearTimer.unref?.();
|
|
1450
|
+
}
|
|
1451
|
+
|
|
1164
1452
|
#getActivePhase(phases: TodoPhase[]): TodoPhase | undefined {
|
|
1165
1453
|
const nonEmpty = phases.filter(phase => phase.tasks.length > 0);
|
|
1166
1454
|
const active = nonEmpty.find(phase =>
|
|
@@ -1214,6 +1502,19 @@ export class InteractiveMode implements InteractiveModeContext {
|
|
|
1214
1502
|
this.todoContainer.addChild(new Text(lines.join("\n"), 1, 0));
|
|
1215
1503
|
}
|
|
1216
1504
|
|
|
1505
|
+
/**
|
|
1506
|
+
* Anchored HUD of in-flight subagents, mirroring the Todos block above the
|
|
1507
|
+
* editor. Driven entirely by observer-registry change events, so rows appear
|
|
1508
|
+
* on spawn and the whole block clears itself once the last subagent leaves
|
|
1509
|
+
* the "active" state.
|
|
1510
|
+
*/
|
|
1511
|
+
#renderSubagentList(): void {
|
|
1512
|
+
this.subagentContainer.clear();
|
|
1513
|
+
const lines = renderSubagentHudLines(this.#observerRegistry.getSessions(), this.ui.terminal.columns);
|
|
1514
|
+
if (lines.length === 0) return;
|
|
1515
|
+
this.subagentContainer.addChild(new Text(lines.join("\n"), 1, 0));
|
|
1516
|
+
}
|
|
1517
|
+
|
|
1217
1518
|
async #loadTodoList(): Promise<void> {
|
|
1218
1519
|
this.todoPhases = this.session.getTodoPhases();
|
|
1219
1520
|
this.#syncTodoAutoClearTimer();
|
|
@@ -1522,22 +1823,15 @@ export class InteractiveMode implements InteractiveModeContext {
|
|
|
1522
1823
|
if (!state?.enabled) {
|
|
1523
1824
|
throw new ToolError("Plan mode is not active.");
|
|
1524
1825
|
}
|
|
1525
|
-
const planFilePath =
|
|
1526
|
-
const planContent = await this.#readPlanFile(planFilePath);
|
|
1527
|
-
if (planContent === null) {
|
|
1528
|
-
throw new ToolError(
|
|
1529
|
-
`Plan file not found at ${planFilePath}. Write the finalized plan to ${planFilePath} before requesting approval.`,
|
|
1530
|
-
);
|
|
1531
|
-
}
|
|
1532
|
-
const normalized = resolvePlanTitle({
|
|
1826
|
+
const { planFilePath, title } = await resolveApprovedPlan({
|
|
1533
1827
|
suppliedTitle: extra?.title,
|
|
1534
|
-
|
|
1535
|
-
|
|
1828
|
+
statePlanFilePath: state.planFilePath,
|
|
1829
|
+
readPlan: url => this.#readPlanFile(url),
|
|
1830
|
+
listPlanFiles: () => this.#listLocalPlanFiles(),
|
|
1536
1831
|
});
|
|
1537
1832
|
const details: PlanApprovalDetails = {
|
|
1538
1833
|
planFilePath,
|
|
1539
|
-
|
|
1540
|
-
title: normalized.title,
|
|
1834
|
+
title,
|
|
1541
1835
|
planExists: true,
|
|
1542
1836
|
};
|
|
1543
1837
|
return {
|
|
@@ -1548,7 +1842,40 @@ export class InteractiveMode implements InteractiveModeContext {
|
|
|
1548
1842
|
});
|
|
1549
1843
|
}
|
|
1550
1844
|
|
|
1551
|
-
async #
|
|
1845
|
+
async #restorePlanPreviousModel(prev: { model: Model; thinkingLevel?: ThinkingLevel }): Promise<void> {
|
|
1846
|
+
if (modelsAreEqual(this.session.model, prev.model)) {
|
|
1847
|
+
// Same model — only thinking level may differ. Avoid setModelTemporary()
|
|
1848
|
+
// which would reset provider-side sessions and break continuity.
|
|
1849
|
+
this.session.setThinkingLevel(prev.thinkingLevel);
|
|
1850
|
+
} else if (this.session.isStreaming) {
|
|
1851
|
+
this.#pendingModelSwitch = { model: prev.model, thinkingLevel: prev.thinkingLevel };
|
|
1852
|
+
} else {
|
|
1853
|
+
await this.session.setModelTemporary(prev.model, prev.thinkingLevel);
|
|
1854
|
+
}
|
|
1855
|
+
}
|
|
1856
|
+
|
|
1857
|
+
/**
|
|
1858
|
+
* Idempotent post-compaction model transition for the plan-approval compact
|
|
1859
|
+
* path. The deferred pre-plan state is consumed on first application, so a
|
|
1860
|
+
* second call (the before-flush hook vs. the short-circuit fallback) is a
|
|
1861
|
+
* no-op. "failed" intentionally stays on the plan model — the context is
|
|
1862
|
+
* intact and we dispatch best-effort.
|
|
1863
|
+
*/
|
|
1864
|
+
async #applyDeferredPlanModelTransition(
|
|
1865
|
+
outcome: CompactionOutcome | undefined,
|
|
1866
|
+
executionModel: ResolvedRoleModel | undefined,
|
|
1867
|
+
): Promise<void> {
|
|
1868
|
+
const deferredPrev = this.#planModePreviousModelState;
|
|
1869
|
+
if (deferredPrev === undefined || outcome === "failed") return;
|
|
1870
|
+
this.#planModePreviousModelState = undefined;
|
|
1871
|
+
if (executionModel) {
|
|
1872
|
+
await this.#applyPlanExecutionModel(executionModel);
|
|
1873
|
+
} else {
|
|
1874
|
+
await this.#restorePlanPreviousModel(deferredPrev);
|
|
1875
|
+
}
|
|
1876
|
+
}
|
|
1877
|
+
|
|
1878
|
+
async #exitPlanMode(options?: { silent?: boolean; paused?: boolean; deferModelRestore?: boolean }): Promise<void> {
|
|
1552
1879
|
if (!this.planModeEnabled) {
|
|
1553
1880
|
return;
|
|
1554
1881
|
}
|
|
@@ -1558,23 +1885,18 @@ export class InteractiveMode implements InteractiveModeContext {
|
|
|
1558
1885
|
await this.session.setActiveToolsByName(previousTools);
|
|
1559
1886
|
}
|
|
1560
1887
|
if (this.#planModePreviousModelState) {
|
|
1561
|
-
|
|
1562
|
-
|
|
1563
|
-
// Same model — only thinking level may differ. Avoid setModelTemporary()
|
|
1564
|
-
// which would reset provider-side sessions (openai-responses/Codex) and
|
|
1565
|
-
// break conversation continuity.
|
|
1566
|
-
this.session.setThinkingLevel(prev.thinkingLevel);
|
|
1567
|
-
} else if (this.session.isStreaming) {
|
|
1568
|
-
this.#pendingModelSwitch = { model: prev.model, thinkingLevel: prev.thinkingLevel };
|
|
1569
|
-
} else {
|
|
1570
|
-
await this.session.setModelTemporary(prev.model, prev.thinkingLevel);
|
|
1888
|
+
if (!options?.deferModelRestore) {
|
|
1889
|
+
await this.#restorePlanPreviousModel(this.#planModePreviousModelState);
|
|
1571
1890
|
}
|
|
1572
1891
|
// If #applyPlanModeModel queued a deferred switch to the plan-role model
|
|
1573
1892
|
// (because the session was streaming on entry), drop it now: we are
|
|
1574
1893
|
// leaving plan mode, so flushing it on the next agent_end would land the
|
|
1575
1894
|
// session on the plan-role model after the user has exited plan mode
|
|
1576
|
-
// (issue #816).
|
|
1577
|
-
//
|
|
1895
|
+
// (issue #816). This runs even when deferModelRestore is set
|
|
1896
|
+
// (compact-approval path): otherwise the stale plan switch survives and
|
|
1897
|
+
// flushPendingModelSwitch() later clobbers the restored/execution model.
|
|
1898
|
+
// Only clear when the pending target matches the plan-role model — leave
|
|
1899
|
+
// any unrelated user-queued switch intact.
|
|
1578
1900
|
const pending = this.#pendingModelSwitch;
|
|
1579
1901
|
if (pending) {
|
|
1580
1902
|
const planResolution = this.session.resolveRoleModelWithThinking("plan");
|
|
@@ -1589,7 +1911,7 @@ export class InteractiveMode implements InteractiveModeContext {
|
|
|
1589
1911
|
this.planModePaused = options?.paused ?? false;
|
|
1590
1912
|
this.planModePlanFilePath = undefined;
|
|
1591
1913
|
this.#planModePreviousTools = undefined;
|
|
1592
|
-
this.#planModePreviousModelState = undefined;
|
|
1914
|
+
if (!options?.deferModelRestore) this.#planModePreviousModelState = undefined;
|
|
1593
1915
|
this.#updatePlanModeStatus();
|
|
1594
1916
|
const paused = options?.paused ?? false;
|
|
1595
1917
|
this.sessionManager.appendModeChange(paused ? "plan_paused" : "none");
|
|
@@ -1677,22 +1999,97 @@ export class InteractiveMode implements InteractiveModeContext {
|
|
|
1677
1999
|
}
|
|
1678
2000
|
}
|
|
1679
2001
|
|
|
1680
|
-
#
|
|
1681
|
-
const
|
|
1682
|
-
const
|
|
1683
|
-
|
|
1684
|
-
|
|
1685
|
-
|
|
1686
|
-
|
|
1687
|
-
|
|
1688
|
-
|
|
1689
|
-
|
|
1690
|
-
|
|
1691
|
-
|
|
1692
|
-
|
|
2002
|
+
async #hasPlanModeDraftContent(planFilePath: string): Promise<boolean> {
|
|
2003
|
+
const candidates = new Set<string>([planFilePath, ...(await this.#listLocalPlanFiles())]);
|
|
2004
|
+
for (const candidate of candidates) {
|
|
2005
|
+
const content = await this.#readPlanFile(candidate);
|
|
2006
|
+
if (content !== null && content.trim().length > 0) return true;
|
|
2007
|
+
}
|
|
2008
|
+
return false;
|
|
2009
|
+
}
|
|
2010
|
+
|
|
2011
|
+
/** `local://` URLs of plan files in the session-local root, newest first.
|
|
2012
|
+
* A fallback for `resolveApprovedPlan` when the agent dropped `extra.title`,
|
|
2013
|
+
* so the plan it wrote is still found by scanning recent `*-plan.md` files. */
|
|
2014
|
+
async #listLocalPlanFiles(): Promise<string[]> {
|
|
2015
|
+
const localRoot = this.#resolvePlanFilePath("local://");
|
|
2016
|
+
try {
|
|
2017
|
+
const entries = await fs.readdir(localRoot, { withFileTypes: true });
|
|
2018
|
+
const plans = await Promise.all(
|
|
2019
|
+
entries
|
|
2020
|
+
.filter(entry => entry.isFile() && /plan\.md$/i.test(entry.name))
|
|
2021
|
+
.map(async name => {
|
|
2022
|
+
const stat = await fs.stat(path.join(localRoot, name.name)).catch(() => null);
|
|
2023
|
+
return { url: `local://${name.name}`, mtime: stat?.mtimeMs ?? 0 };
|
|
2024
|
+
}),
|
|
2025
|
+
);
|
|
2026
|
+
return plans.sort((a, b) => b.mtime - a.mtime).map(plan => plan.url);
|
|
2027
|
+
} catch {
|
|
2028
|
+
return [];
|
|
1693
2029
|
}
|
|
1694
|
-
|
|
2030
|
+
}
|
|
2031
|
+
|
|
2032
|
+
showPlanReview(
|
|
2033
|
+
planContent: string,
|
|
2034
|
+
title: string,
|
|
2035
|
+
options: string[],
|
|
2036
|
+
dialogOptions?: {
|
|
2037
|
+
helpText?: string;
|
|
2038
|
+
disabledIndices?: number[];
|
|
2039
|
+
onExternalEditor?: () => void;
|
|
2040
|
+
onPlanEdited?: (content: string) => void;
|
|
2041
|
+
onFeedbackChange?: (feedback: string) => void;
|
|
2042
|
+
initialIndex?: number;
|
|
2043
|
+
},
|
|
2044
|
+
extra?: { slider?: HookSelectorSlider },
|
|
2045
|
+
): Promise<string | undefined> {
|
|
2046
|
+
this.#hidePlanReview();
|
|
2047
|
+
const { promise, resolve } = Promise.withResolvers<string | undefined>();
|
|
2048
|
+
let settled = false;
|
|
2049
|
+
const finish = (choice: string | undefined): void => {
|
|
2050
|
+
if (settled) return;
|
|
2051
|
+
settled = true;
|
|
2052
|
+
this.#hidePlanReview();
|
|
2053
|
+
this.ui.requestRender();
|
|
2054
|
+
resolve(choice);
|
|
2055
|
+
};
|
|
2056
|
+
const overlay = new PlanReviewOverlay(
|
|
2057
|
+
planContent,
|
|
2058
|
+
{
|
|
2059
|
+
promptTitle: title,
|
|
2060
|
+
options,
|
|
2061
|
+
disabledIndices: dialogOptions?.disabledIndices,
|
|
2062
|
+
helpText: dialogOptions?.helpText,
|
|
2063
|
+
initialIndex: dialogOptions?.initialIndex,
|
|
2064
|
+
slider: extra?.slider,
|
|
2065
|
+
externalEditorLabel: this.keybindings.getDisplayString("app.editor.external") || undefined,
|
|
2066
|
+
},
|
|
2067
|
+
{
|
|
2068
|
+
onPick: choice => finish(choice),
|
|
2069
|
+
onCancel: () => finish(undefined),
|
|
2070
|
+
onExternalEditor: dialogOptions?.onExternalEditor,
|
|
2071
|
+
onAnnotationExternalEditor: (draft, commit) => this.#openPlanAnnotationInExternalEditor(draft, commit),
|
|
2072
|
+
onPlanEdited: dialogOptions?.onPlanEdited,
|
|
2073
|
+
onFeedbackChange: dialogOptions?.onFeedbackChange,
|
|
2074
|
+
},
|
|
2075
|
+
);
|
|
2076
|
+
this.#planReviewOverlay = overlay;
|
|
2077
|
+
this.#planReviewOverlayHandle = this.ui.showOverlay(overlay, {
|
|
2078
|
+
anchor: "bottom-center",
|
|
2079
|
+
width: "100%",
|
|
2080
|
+
maxHeight: "100%",
|
|
2081
|
+
margin: 0,
|
|
2082
|
+
fullscreen: true,
|
|
2083
|
+
});
|
|
2084
|
+
this.ui.setFocus(overlay);
|
|
1695
2085
|
this.ui.requestRender();
|
|
2086
|
+
return promise;
|
|
2087
|
+
}
|
|
2088
|
+
|
|
2089
|
+
#hidePlanReview(): void {
|
|
2090
|
+
this.#planReviewOverlayHandle?.hide();
|
|
2091
|
+
this.#planReviewOverlayHandle = undefined;
|
|
2092
|
+
this.#planReviewOverlay = undefined;
|
|
1696
2093
|
}
|
|
1697
2094
|
|
|
1698
2095
|
#getEditorTerminalPath(): string | null {
|
|
@@ -1714,14 +2111,6 @@ export class InteractiveMode implements InteractiveModeContext {
|
|
|
1714
2111
|
}
|
|
1715
2112
|
}
|
|
1716
2113
|
|
|
1717
|
-
#getPlanReviewHelpText(): string {
|
|
1718
|
-
const externalEditorKey = this.keybindings.getDisplayString("app.editor.external");
|
|
1719
|
-
if (!externalEditorKey) {
|
|
1720
|
-
return "up/down navigate enter select esc cancel";
|
|
1721
|
-
}
|
|
1722
|
-
return `up/down navigate enter select ${externalEditorKey.toLowerCase()} open in editor esc cancel`;
|
|
1723
|
-
}
|
|
1724
|
-
|
|
1725
2114
|
#getPlanApprovalContextUsage(): ContextUsage | undefined {
|
|
1726
2115
|
const executionModel = this.#planModePreviousModelState?.model ?? this.session.model;
|
|
1727
2116
|
const contextWindow = executionModel?.contextWindow;
|
|
@@ -1780,7 +2169,7 @@ export class InteractiveMode implements InteractiveModeContext {
|
|
|
1780
2169
|
});
|
|
1781
2170
|
if (result !== null) {
|
|
1782
2171
|
await Bun.write(resolvedPath, result);
|
|
1783
|
-
this.#
|
|
2172
|
+
this.#planReviewOverlay?.setPlanContent(result);
|
|
1784
2173
|
this.showStatus("Plan updated in external editor.");
|
|
1785
2174
|
}
|
|
1786
2175
|
} catch (error) {
|
|
@@ -1794,6 +2183,37 @@ export class InteractiveMode implements InteractiveModeContext {
|
|
|
1794
2183
|
}
|
|
1795
2184
|
}
|
|
1796
2185
|
|
|
2186
|
+
async #openPlanAnnotationInExternalEditor(draft: string, commit: (text: string | null) => void): Promise<void> {
|
|
2187
|
+
const editorCmd = getEditorCommand();
|
|
2188
|
+
if (!editorCmd) {
|
|
2189
|
+
this.showWarning("No editor configured. Set $VISUAL or $EDITOR environment variable.");
|
|
2190
|
+
return;
|
|
2191
|
+
}
|
|
2192
|
+
|
|
2193
|
+
let ttyHandle: fs.FileHandle | null = null;
|
|
2194
|
+
try {
|
|
2195
|
+
ttyHandle = await this.#openEditorTerminalHandle();
|
|
2196
|
+
this.ui.stop();
|
|
2197
|
+
|
|
2198
|
+
const stdio: [number | "inherit", number | "inherit", number | "inherit"] = ttyHandle
|
|
2199
|
+
? [ttyHandle.fd, ttyHandle.fd, ttyHandle.fd]
|
|
2200
|
+
: ["inherit", "inherit", "inherit"];
|
|
2201
|
+
|
|
2202
|
+
const result = await openInEditor(editorCmd, draft, { extension: ".md", stdio });
|
|
2203
|
+
if (result !== null) {
|
|
2204
|
+
commit(result);
|
|
2205
|
+
}
|
|
2206
|
+
} catch (error) {
|
|
2207
|
+
this.showWarning(`Failed to open external editor: ${error instanceof Error ? error.message : String(error)}`);
|
|
2208
|
+
} finally {
|
|
2209
|
+
if (ttyHandle) {
|
|
2210
|
+
await ttyHandle.close();
|
|
2211
|
+
}
|
|
2212
|
+
this.ui.start();
|
|
2213
|
+
this.ui.requestRender(true);
|
|
2214
|
+
}
|
|
2215
|
+
}
|
|
2216
|
+
|
|
1797
2217
|
async #applyPlanExecutionModel(entry: ResolvedRoleModel | undefined): Promise<void> {
|
|
1798
2218
|
if (!entry) return;
|
|
1799
2219
|
try {
|
|
@@ -1812,19 +2232,12 @@ export class InteractiveMode implements InteractiveModeContext {
|
|
|
1812
2232
|
planContent: string,
|
|
1813
2233
|
options: {
|
|
1814
2234
|
planFilePath: string;
|
|
1815
|
-
finalPlanFilePath: string;
|
|
1816
2235
|
title: string;
|
|
1817
2236
|
preserveContext?: boolean;
|
|
1818
2237
|
compactBeforeExecute?: boolean;
|
|
1819
2238
|
executionModel?: ResolvedRoleModel;
|
|
1820
2239
|
},
|
|
1821
2240
|
): Promise<void> {
|
|
1822
|
-
await renameApprovedPlanFile({
|
|
1823
|
-
planFilePath: options.planFilePath,
|
|
1824
|
-
finalPlanFilePath: options.finalPlanFilePath,
|
|
1825
|
-
getArtifactsDir: () => this.sessionManager.getArtifactsDir(),
|
|
1826
|
-
getSessionId: () => this.sessionManager.getSessionId(),
|
|
1827
|
-
});
|
|
1828
2241
|
const previousTools = this.#planModePreviousTools ?? this.session.getActiveToolNames();
|
|
1829
2242
|
|
|
1830
2243
|
// Mark the pending abort caused by the plan-mode → compaction transition as
|
|
@@ -1838,13 +2251,17 @@ export class InteractiveMode implements InteractiveModeContext {
|
|
|
1838
2251
|
}
|
|
1839
2252
|
let compactOutcome: CompactionOutcome | undefined;
|
|
1840
2253
|
try {
|
|
1841
|
-
await this.#exitPlanMode({
|
|
2254
|
+
await this.#exitPlanMode({
|
|
2255
|
+
silent: true,
|
|
2256
|
+
paused: false,
|
|
2257
|
+
deferModelRestore: options.compactBeforeExecute === true,
|
|
2258
|
+
});
|
|
1842
2259
|
|
|
1843
2260
|
if (!options.preserveContext) {
|
|
1844
2261
|
await this.handleClearCommand();
|
|
1845
2262
|
// The new session has a fresh local:// root — persist the approved plan there
|
|
1846
|
-
// so `local://<
|
|
1847
|
-
const newLocalPath = resolveLocalUrlToPath(options.
|
|
2263
|
+
// so `local://<slug>-plan.md` resolves correctly in the execution session.
|
|
2264
|
+
const newLocalPath = resolveLocalUrlToPath(options.planFilePath, {
|
|
1848
2265
|
getArtifactsDir: () => this.sessionManager.getArtifactsDir(),
|
|
1849
2266
|
getSessionId: () => this.sessionManager.getSessionId(),
|
|
1850
2267
|
});
|
|
@@ -1858,7 +2275,7 @@ export class InteractiveMode implements InteractiveModeContext {
|
|
|
1858
2275
|
// Cancellation skips the synthetic-prompt dispatch (operator's explicit
|
|
1859
2276
|
// abort is honored); failure proceeds best-effort — approval intent stands.
|
|
1860
2277
|
const compactionPrompt = prompt.render(planModeCompactInstructionsPrompt, {
|
|
1861
|
-
planFilePath: options.
|
|
2278
|
+
planFilePath: options.planFilePath,
|
|
1862
2279
|
});
|
|
1863
2280
|
// Pin the plan reference path BEFORE compaction so any user messages
|
|
1864
2281
|
// queued during the compaction await (which `handleCompactCommand`
|
|
@@ -1866,8 +2283,10 @@ export class InteractiveMode implements InteractiveModeContext {
|
|
|
1866
2283
|
// approved plan in `#buildPlanReferenceMessage`. Reassignment after
|
|
1867
2284
|
// the try/finally is idempotent and kept for the !compactBeforeExecute
|
|
1868
2285
|
// branch.
|
|
1869
|
-
this.session.setPlanReferencePath(options.
|
|
1870
|
-
compactOutcome = await this.handleCompactCommand(compactionPrompt
|
|
2286
|
+
this.session.setPlanReferencePath(options.planFilePath);
|
|
2287
|
+
compactOutcome = await this.handleCompactCommand(compactionPrompt, outcome =>
|
|
2288
|
+
this.#applyDeferredPlanModelTransition(outcome, options.executionModel),
|
|
2289
|
+
);
|
|
1871
2290
|
}
|
|
1872
2291
|
} finally {
|
|
1873
2292
|
// Unconditional clear. Idempotent: a no-op when the flag was never set
|
|
@@ -1882,24 +2301,35 @@ export class InteractiveMode implements InteractiveModeContext {
|
|
|
1882
2301
|
if (previousTools.length > 0) {
|
|
1883
2302
|
await this.session.setActiveToolsByName(previousTools);
|
|
1884
2303
|
}
|
|
1885
|
-
this.session.setPlanReferencePath(options.
|
|
2304
|
+
this.session.setPlanReferencePath(options.planFilePath);
|
|
2305
|
+
|
|
2306
|
+
// Resolve the deferred plan-approval model transition. On the compact path
|
|
2307
|
+
// the before-flush hook passed to handleCompactCommand already ran this (so
|
|
2308
|
+
// any input queued during compaction executed on the post-compaction
|
|
2309
|
+
// model); the re-run here is idempotent and covers the short-circuit where
|
|
2310
|
+
// compaction never executed. It runs for "cancelled" too — the operator
|
|
2311
|
+
// aborted only the compaction, not the approval — so the next turn no longer
|
|
2312
|
+
// lands on the plan model. "failed" stays on the plan model (context
|
|
2313
|
+
// intact) and dispatches best-effort.
|
|
2314
|
+
if (options.compactBeforeExecute) {
|
|
2315
|
+
await this.#applyDeferredPlanModelTransition(compactOutcome, options.executionModel);
|
|
2316
|
+
} else {
|
|
2317
|
+
await this.#applyPlanExecutionModel(options.executionModel);
|
|
2318
|
+
}
|
|
1886
2319
|
|
|
1887
2320
|
if (compactOutcome === "cancelled") {
|
|
1888
2321
|
// Explicit abort: honor it. `executeCompaction` already surfaced
|
|
1889
|
-
// `showError("Compaction cancelled")
|
|
1890
|
-
//
|
|
1891
|
-
//
|
|
1892
|
-
// `AgentSession.#buildPlanReferenceMessage`
|
|
1893
|
-
//
|
|
1894
|
-
// sent here, the executor's first turn would have no plan context.
|
|
2322
|
+
// `showError("Compaction cancelled")`; we add the deferred-dispatch
|
|
2323
|
+
// warning and exit without dispatching the synthetic plan-approved
|
|
2324
|
+
// prompt. `markPlanReferenceSent` stays unset so
|
|
2325
|
+
// `AgentSession.#buildPlanReferenceMessage` injects the plan reference
|
|
2326
|
+
// on the operator's next `prompt()` call.
|
|
1895
2327
|
this.showWarning(
|
|
1896
2328
|
"Plan approved, but compaction was cancelled — execution not dispatched. Submit a turn to continue.",
|
|
1897
2329
|
);
|
|
1898
2330
|
return;
|
|
1899
2331
|
}
|
|
1900
2332
|
|
|
1901
|
-
await this.#applyPlanExecutionModel(options.executionModel);
|
|
1902
|
-
|
|
1903
2333
|
// Approved plans land in a fresh (or compacted) session whose first user-visible
|
|
1904
2334
|
// turn is the synthetic plan-approved prompt — that path bypasses the
|
|
1905
2335
|
// input-controller's title generation. Seed an auto-name from the plan title
|
|
@@ -1919,9 +2349,18 @@ export class InteractiveMode implements InteractiveModeContext {
|
|
|
1919
2349
|
this.session.markPlanReferenceSent();
|
|
1920
2350
|
const planModePrompt = prompt.render(planModeApprovedPrompt, {
|
|
1921
2351
|
planContent,
|
|
1922
|
-
|
|
2352
|
+
planFilePath: options.planFilePath,
|
|
1923
2353
|
contextPreserved: options.preserveContext === true,
|
|
1924
2354
|
});
|
|
2355
|
+
// The executor's first turn must start on an idle session. The agent may still
|
|
2356
|
+
// be streaming the post-`resolve` continuation (Agent.#emit is fire-and-forget)
|
|
2357
|
+
// or a turn kicked off by the compaction/clear above; prompt() would then throw
|
|
2358
|
+
// AgentBusyError ("Failed to finalize approved plan"). Abort the now-irrelevant
|
|
2359
|
+
// in-flight turn first — abort() bumps the prompt generation and cancels pending
|
|
2360
|
+
// continuations, so nothing re-streams in the synchronous gap before prompt().
|
|
2361
|
+
if (this.session.isStreaming) {
|
|
2362
|
+
await this.session.abort();
|
|
2363
|
+
}
|
|
1925
2364
|
await this.session.prompt(planModePrompt, { synthetic: true });
|
|
1926
2365
|
}
|
|
1927
2366
|
|
|
@@ -1931,14 +2370,30 @@ export class InteractiveMode implements InteractiveModeContext {
|
|
|
1931
2370
|
return;
|
|
1932
2371
|
}
|
|
1933
2372
|
if (this.planModeEnabled) {
|
|
1934
|
-
const
|
|
1935
|
-
|
|
1936
|
-
|
|
1937
|
-
|
|
1938
|
-
|
|
2373
|
+
const planFilePath = this.planModePlanFilePath ?? (await this.#getPlanFilePath());
|
|
2374
|
+
if (await this.#hasPlanModeDraftContent(planFilePath)) {
|
|
2375
|
+
const confirmed = await this.showHookConfirm(
|
|
2376
|
+
"Exit plan mode?",
|
|
2377
|
+
"This exits plan mode without approving a plan.",
|
|
2378
|
+
);
|
|
2379
|
+
if (!confirmed) return;
|
|
2380
|
+
}
|
|
1939
2381
|
await this.#exitPlanMode({ paused: true });
|
|
1940
2382
|
return;
|
|
1941
2383
|
}
|
|
2384
|
+
if (this.planModePaused && !initialPrompt) {
|
|
2385
|
+
// No-arg third toggle: paused → off. Tools, model, and plan state were
|
|
2386
|
+
// already restored by the prior #exitPlanMode({ paused: true }); only the
|
|
2387
|
+
// paused flag, the reentry marker, and the session mode entry remain.
|
|
2388
|
+
// Prompted /plan invocations fall through to #enterPlanMode below so the
|
|
2389
|
+
// supplied prompt is still submitted as the first plan-mode turn.
|
|
2390
|
+
this.planModePaused = false;
|
|
2391
|
+
this.#planModeHasEntered = false;
|
|
2392
|
+
this.#updatePlanModeStatus();
|
|
2393
|
+
this.sessionManager.appendModeChange("none");
|
|
2394
|
+
this.showStatus("Plan mode disabled.");
|
|
2395
|
+
return;
|
|
2396
|
+
}
|
|
1942
2397
|
if (!this.session.settings.get("plan.enabled")) {
|
|
1943
2398
|
this.showWarning("Plan mode is disabled. Enable it in settings (plan.enabled).");
|
|
1944
2399
|
return;
|
|
@@ -2020,6 +2475,70 @@ export class InteractiveMode implements InteractiveModeContext {
|
|
|
2020
2475
|
this.showError(error instanceof Error ? error.message : String(error));
|
|
2021
2476
|
}
|
|
2022
2477
|
}
|
|
2478
|
+
async handleGuidedGoalCommand(rest?: string): Promise<void> {
|
|
2479
|
+
try {
|
|
2480
|
+
if (this.planModeEnabled || this.planModePaused) {
|
|
2481
|
+
this.showWarning("Exit plan mode first.");
|
|
2482
|
+
return;
|
|
2483
|
+
}
|
|
2484
|
+
if (!this.session.settings.get("goal.enabled")) {
|
|
2485
|
+
this.showWarning("Goal mode is disabled. Enable it in settings (goal.enabled).");
|
|
2486
|
+
return;
|
|
2487
|
+
}
|
|
2488
|
+
if (this.goalModeEnabled) {
|
|
2489
|
+
this.showStatus("Goal mode is already active. Use /goal to manage it, or /goal drop to start over.");
|
|
2490
|
+
return;
|
|
2491
|
+
}
|
|
2492
|
+
if (this.#getPausedGoalState()) {
|
|
2493
|
+
this.showWarning("Resume the current goal first, or drop it before setting a new objective.");
|
|
2494
|
+
return;
|
|
2495
|
+
}
|
|
2496
|
+
|
|
2497
|
+
const initial = rest?.trim()
|
|
2498
|
+
? rest.trim()
|
|
2499
|
+
: (await this.showHookEditor("Guided goal", undefined, undefined, { promptStyle: true }))?.trim();
|
|
2500
|
+
if (!initial) return;
|
|
2501
|
+
|
|
2502
|
+
const messages: GuidedGoalMessage[] = [{ role: "user", content: initial }];
|
|
2503
|
+
let latestDraftObjective: string | undefined;
|
|
2504
|
+
for (let turn = 0; turn < 6; turn++) {
|
|
2505
|
+
const result = await runGuidedGoalTurn(this.session, { messages });
|
|
2506
|
+
if (result.objective?.trim()) latestDraftObjective = result.objective.trim();
|
|
2507
|
+
if (result.kind === "question") {
|
|
2508
|
+
messages.push({ role: "assistant", content: result.question });
|
|
2509
|
+
const answer = (
|
|
2510
|
+
await this.showHookEditor(result.question, undefined, undefined, { promptStyle: true })
|
|
2511
|
+
)?.trim();
|
|
2512
|
+
if (!answer) return;
|
|
2513
|
+
messages.push({ role: "user", content: answer });
|
|
2514
|
+
continue;
|
|
2515
|
+
}
|
|
2516
|
+
|
|
2517
|
+
const finalObjective = (
|
|
2518
|
+
await this.showHookEditor("Review guided goal", result.objective, undefined, { promptStyle: true })
|
|
2519
|
+
)?.trim();
|
|
2520
|
+
if (!finalObjective) return;
|
|
2521
|
+
await this.#startGoalFromObjective(finalObjective);
|
|
2522
|
+
return;
|
|
2523
|
+
}
|
|
2524
|
+
|
|
2525
|
+
// Hit the turn cap without an explicit `ready`. Rather than discard the whole interview,
|
|
2526
|
+
// salvage the latest non-empty model objective draft seen on any earlier turn. A final
|
|
2527
|
+
// question turn may omit `objective`; that must not erase a usable draft.
|
|
2528
|
+
if (latestDraftObjective) {
|
|
2529
|
+
const finalObjective = (
|
|
2530
|
+
await this.showHookEditor("Review guided goal", latestDraftObjective, undefined, { promptStyle: true })
|
|
2531
|
+
)?.trim();
|
|
2532
|
+
if (finalObjective) {
|
|
2533
|
+
await this.#startGoalFromObjective(finalObjective);
|
|
2534
|
+
return;
|
|
2535
|
+
}
|
|
2536
|
+
}
|
|
2537
|
+
this.showWarning("Guided goal setup needs more detail. Run /guided-goal again with a narrower objective.");
|
|
2538
|
+
} catch (error) {
|
|
2539
|
+
this.showError(error instanceof Error ? error.message : String(error));
|
|
2540
|
+
}
|
|
2541
|
+
}
|
|
2023
2542
|
|
|
2024
2543
|
async #dispatchGoalSubcommand(sub: GoalSubcommand, rest: string): Promise<void> {
|
|
2025
2544
|
switch (sub) {
|
|
@@ -2153,7 +2672,7 @@ export class InteractiveMode implements InteractiveModeContext {
|
|
|
2153
2672
|
async #startGoalFromObjective(objective: string): Promise<void> {
|
|
2154
2673
|
await this.#enterGoalMode({ objective, silent: true });
|
|
2155
2674
|
this.#resetGoalContinuationSuppression();
|
|
2156
|
-
if (this.onInputCallback) {
|
|
2675
|
+
if (!this.session.isStreaming && this.onInputCallback) {
|
|
2157
2676
|
this.onInputCallback(this.startPendingSubmission({ text: objective }));
|
|
2158
2677
|
}
|
|
2159
2678
|
}
|
|
@@ -2168,7 +2687,7 @@ export class InteractiveMode implements InteractiveModeContext {
|
|
|
2168
2687
|
if (this.session.isStreaming) {
|
|
2169
2688
|
await this.session.sendGoalModeContext({ deliverAs: "steer" });
|
|
2170
2689
|
}
|
|
2171
|
-
if (this.onInputCallback) {
|
|
2690
|
+
if (!this.session.isStreaming && this.onInputCallback) {
|
|
2172
2691
|
this.onInputCallback(this.startPendingSubmission({ text: objective }));
|
|
2173
2692
|
}
|
|
2174
2693
|
}
|
|
@@ -2189,6 +2708,33 @@ export class InteractiveMode implements InteractiveModeContext {
|
|
|
2189
2708
|
await this.#startGoalFromObjective(objective);
|
|
2190
2709
|
}
|
|
2191
2710
|
|
|
2711
|
+
/** Manually (re-)open the plan-review overlay — bound to `/plan-review`. Lets
|
|
2712
|
+
* the operator pull the review back up after dismissing it, or review a plan
|
|
2713
|
+
* the agent wrote without calling `resolve`. There is no fixed plan filename:
|
|
2714
|
+
* `getPlanReferencePath()` is empty until a plan is actually approved (and does
|
|
2715
|
+
* not survive a restart), so this drives off the newest `local://<slug>-plan.md`
|
|
2716
|
+
* the agent wrote — the files persist in the session artifacts dir, so the scan
|
|
2717
|
+
* works before any review and across restarts. */
|
|
2718
|
+
async openPlanReview(): Promise<void> {
|
|
2719
|
+
if (!this.planModeEnabled) {
|
|
2720
|
+
this.showWarning("Plan mode is not active.");
|
|
2721
|
+
return;
|
|
2722
|
+
}
|
|
2723
|
+
const noPlan = "No plan to review yet — write one to a local://<slug>-plan.md file first.";
|
|
2724
|
+
const [planFilePath] = await this.#listLocalPlanFiles();
|
|
2725
|
+
if (!planFilePath) {
|
|
2726
|
+
this.showWarning(noPlan);
|
|
2727
|
+
return;
|
|
2728
|
+
}
|
|
2729
|
+
const planContent = await this.#readPlanFile(planFilePath);
|
|
2730
|
+
if (planContent === null) {
|
|
2731
|
+
this.showWarning(noPlan);
|
|
2732
|
+
return;
|
|
2733
|
+
}
|
|
2734
|
+
const { title } = resolvePlanTitle({ planContent, planFilePath });
|
|
2735
|
+
await this.handlePlanApproval({ planFilePath, title, planExists: true });
|
|
2736
|
+
}
|
|
2737
|
+
|
|
2192
2738
|
async handlePlanApproval(details: PlanApprovalDetails): Promise<void> {
|
|
2193
2739
|
if (!this.planModeEnabled) {
|
|
2194
2740
|
this.showWarning("Plan mode is not active.");
|
|
@@ -2209,7 +2755,6 @@ export class InteractiveMode implements InteractiveModeContext {
|
|
|
2209
2755
|
return;
|
|
2210
2756
|
}
|
|
2211
2757
|
|
|
2212
|
-
this.#renderPlanPreview(planContent, { append: true });
|
|
2213
2758
|
const contextUsage = this.#getPlanApprovalContextUsage();
|
|
2214
2759
|
const keepContextLabel = this.#formatKeepContextLabel(contextUsage);
|
|
2215
2760
|
const keepContextDisabled = this.#isKeepContextDisabled(contextUsage);
|
|
@@ -2231,7 +2776,6 @@ export class InteractiveMode implements InteractiveModeContext {
|
|
|
2231
2776
|
index: startTierIndex,
|
|
2232
2777
|
segments: cycle.models.map(entry => ({
|
|
2233
2778
|
label: entry.role,
|
|
2234
|
-
color: MODEL_ROLES[entry.role as ModelRole]?.color,
|
|
2235
2779
|
detail: entry.model.name || entry.model.id,
|
|
2236
2780
|
})),
|
|
2237
2781
|
onChange: index => {
|
|
@@ -2239,33 +2783,52 @@ export class InteractiveMode implements InteractiveModeContext {
|
|
|
2239
2783
|
},
|
|
2240
2784
|
}
|
|
2241
2785
|
: undefined;
|
|
2242
|
-
|
|
2243
|
-
|
|
2244
|
-
const
|
|
2786
|
+
// The overlay now owns the dynamic, focus-aware help line; the caller only
|
|
2787
|
+
// supplies the trailing cancel hint.
|
|
2788
|
+
const helpText = "esc cancel";
|
|
2789
|
+
// In-overlay edits (section deletes/undo) and section annotations. Deletes
|
|
2790
|
+
// update `editedContent` (and mirror to disk); annotations build `feedback`
|
|
2791
|
+
// that the Refine branch re-prompts the model with.
|
|
2792
|
+
let editedContent: string | undefined;
|
|
2793
|
+
let feedback = "";
|
|
2794
|
+
|
|
2795
|
+
const choice = await this.showPlanReview(
|
|
2796
|
+
planContent,
|
|
2245
2797
|
"Plan mode - next step",
|
|
2246
2798
|
["Approve and execute", "Approve and compact context", keepContextLabel, "Refine plan"],
|
|
2247
2799
|
{
|
|
2248
2800
|
helpText,
|
|
2249
2801
|
onExternalEditor: () => void this.#openPlanInExternalEditor(planFilePath),
|
|
2802
|
+
onPlanEdited: content => {
|
|
2803
|
+
editedContent = content;
|
|
2804
|
+
void Bun.write(this.#resolvePlanFilePath(planFilePath), content);
|
|
2805
|
+
},
|
|
2806
|
+
onFeedbackChange: value => {
|
|
2807
|
+
feedback = value;
|
|
2808
|
+
},
|
|
2250
2809
|
disabledIndices: keepContextDisabled ? [PLAN_KEEP_CONTEXT_OPTION_INDEX] : undefined,
|
|
2251
2810
|
},
|
|
2252
2811
|
{ slider },
|
|
2253
2812
|
);
|
|
2254
2813
|
|
|
2255
2814
|
if (choice === "Approve and execute" || choice === "Approve and compact context" || choice === keepContextLabel) {
|
|
2256
|
-
const finalPlanFilePath = details.finalPlanFilePath || planFilePath;
|
|
2257
2815
|
try {
|
|
2258
|
-
|
|
2816
|
+
// Prefer in-overlay edits (already in memory) over a disk re-read; the
|
|
2817
|
+
// `onPlanEdited` write is fire-and-forget, so reading the file here could
|
|
2818
|
+
// race ahead of it.
|
|
2819
|
+
const latestPlanContent = editedContent ?? (await this.#readPlanFile(planFilePath));
|
|
2259
2820
|
if (!latestPlanContent) {
|
|
2260
2821
|
this.showError(`Plan file not found at ${planFilePath}`);
|
|
2261
2822
|
return;
|
|
2262
2823
|
}
|
|
2263
2824
|
// Capture the operator's tier choice and hand it to #approvePlan, which
|
|
2264
|
-
// applies it AFTER #exitPlanMode. #exitPlanMode restores
|
|
2825
|
+
// applies it AFTER #exitPlanMode. #exitPlanMode normally restores
|
|
2265
2826
|
// #planModePreviousModelState (the model from before plan mode), so
|
|
2266
2827
|
// applying the slider choice any earlier would be silently reverted —
|
|
2267
2828
|
// the bug that made "continue with slow" keep executing on the default
|
|
2268
|
-
// model.
|
|
2829
|
+
// model. For compact-context approval, the plan model is kept through
|
|
2830
|
+
// compaction, then a successful compaction transitions to the slider model
|
|
2831
|
+
// (or restores the pre-plan model when no slider choice was made).
|
|
2269
2832
|
// `cycle.currentIndex` is exactly that restored model, so any chosen tier
|
|
2270
2833
|
// differing from it needs an explicit executionModel — this also covers
|
|
2271
2834
|
// leaving the slider on its `default` anchor while planning ran elsewhere.
|
|
@@ -2273,7 +2836,6 @@ export class InteractiveMode implements InteractiveModeContext {
|
|
|
2273
2836
|
cycle && selectedTierIndex !== cycle.currentIndex ? cycle.models[selectedTierIndex] : undefined;
|
|
2274
2837
|
await this.#approvePlan(latestPlanContent, {
|
|
2275
2838
|
planFilePath,
|
|
2276
|
-
finalPlanFilePath,
|
|
2277
2839
|
title: details.title,
|
|
2278
2840
|
preserveContext: choice !== "Approve and execute",
|
|
2279
2841
|
compactBeforeExecute: choice === "Approve and compact context",
|
|
@@ -2286,6 +2848,16 @@ export class InteractiveMode implements InteractiveModeContext {
|
|
|
2286
2848
|
}
|
|
2287
2849
|
return;
|
|
2288
2850
|
}
|
|
2851
|
+
|
|
2852
|
+
if (choice === "Refine plan") {
|
|
2853
|
+
// Section annotations entered in the overlay become a refinement prompt
|
|
2854
|
+
// re-submitted to the model. With no annotations, fall back to today's
|
|
2855
|
+
// behavior: close the overlay and let the operator type their own.
|
|
2856
|
+
if (feedback.trim() && this.onInputCallback) {
|
|
2857
|
+
this.onInputCallback(this.startPendingSubmission({ text: feedback }));
|
|
2858
|
+
}
|
|
2859
|
+
return;
|
|
2860
|
+
}
|
|
2289
2861
|
}
|
|
2290
2862
|
|
|
2291
2863
|
/**
|
|
@@ -2346,8 +2918,7 @@ export class InteractiveMode implements InteractiveModeContext {
|
|
|
2346
2918
|
|
|
2347
2919
|
stop(): void {
|
|
2348
2920
|
if (this.loadingAnimation) {
|
|
2349
|
-
this
|
|
2350
|
-
this.loadingAnimation = undefined;
|
|
2921
|
+
this.#stopLoadingAnimation(false);
|
|
2351
2922
|
}
|
|
2352
2923
|
this.#cleanupMicAnimation();
|
|
2353
2924
|
this.#cancelTodoAutoClearTimer();
|
|
@@ -2402,6 +2973,7 @@ export class InteractiveMode implements InteractiveModeContext {
|
|
|
2402
2973
|
}
|
|
2403
2974
|
this.#btwController.dispose();
|
|
2404
2975
|
this.#omfgController.dispose();
|
|
2976
|
+
this.#focusController.dispose();
|
|
2405
2977
|
|
|
2406
2978
|
// Emit shutdown event to hooks
|
|
2407
2979
|
await this.session.dispose();
|
|
@@ -2439,9 +3011,6 @@ export class InteractiveMode implements InteractiveModeContext {
|
|
|
2439
3011
|
initializeHookRunner(uiContext: ExtensionUIContext, hasUI: boolean): void {
|
|
2440
3012
|
this.#extensionUiController.initializeHookRunner(uiContext, hasUI);
|
|
2441
3013
|
}
|
|
2442
|
-
createBackgroundUiContext(): ExtensionUIContext {
|
|
2443
|
-
return this.#extensionUiController.createBackgroundUiContext();
|
|
2444
|
-
}
|
|
2445
3014
|
|
|
2446
3015
|
setEditorComponent(
|
|
2447
3016
|
factory: ((tui: TUI, theme: EditorTheme, keybindings: KeybindingsManager) => CustomEditor) | undefined,
|
|
@@ -2458,8 +3027,9 @@ export class InteractiveMode implements InteractiveModeContext {
|
|
|
2458
3027
|
this.ui.requestRender(true);
|
|
2459
3028
|
};
|
|
2460
3029
|
nextEditor.onAutocompleteUpdate = () => {
|
|
2461
|
-
this.ui.requestRender(
|
|
3030
|
+
this.ui.requestRender();
|
|
2462
3031
|
};
|
|
3032
|
+
nextEditor.setShimmerRepaintHandler(() => this.ui.requestComponentRender(this.editor));
|
|
2463
3033
|
nextEditor.setMaxHeight(this.#computeEditorMaxHeight());
|
|
2464
3034
|
if (this.historyStorage) {
|
|
2465
3035
|
nextEditor.setHistoryStorage(this.historyStorage);
|
|
@@ -2483,12 +3053,26 @@ export class InteractiveMode implements InteractiveModeContext {
|
|
|
2483
3053
|
this.ui.requestRender();
|
|
2484
3054
|
}
|
|
2485
3055
|
|
|
2486
|
-
//
|
|
2487
|
-
|
|
2488
|
-
|
|
3056
|
+
// UI helpers
|
|
3057
|
+
present(content: Component | readonly Component[]): void {
|
|
3058
|
+
if (Array.isArray(content)) {
|
|
3059
|
+
for (const item of content) this.#mountChatChild(item);
|
|
3060
|
+
} else {
|
|
3061
|
+
this.#mountChatChild(content as Component);
|
|
3062
|
+
}
|
|
3063
|
+
this.ui.requestRender();
|
|
3064
|
+
}
|
|
3065
|
+
|
|
3066
|
+
#mountChatChild(item: Component): void {
|
|
3067
|
+
this.chatContainer.addChild(item);
|
|
3068
|
+
if (item instanceof ChatBlock) item.mount(this.#chatHost);
|
|
3069
|
+
}
|
|
3070
|
+
|
|
3071
|
+
resetTranscript(): void {
|
|
3072
|
+
this.chatContainer.dispose();
|
|
3073
|
+
this.chatContainer.clear();
|
|
2489
3074
|
}
|
|
2490
3075
|
|
|
2491
|
-
// UI helpers
|
|
2492
3076
|
showStatus(message: string, options?: { dim?: boolean }): void {
|
|
2493
3077
|
this.#uiHelpers.showStatus(message, options);
|
|
2494
3078
|
}
|
|
@@ -2500,15 +3084,12 @@ export class InteractiveMode implements InteractiveModeContext {
|
|
|
2500
3084
|
this.#pendingSubmissionDispose = undefined;
|
|
2501
3085
|
this.#pendingWorkingMessage = undefined;
|
|
2502
3086
|
if (this.loadingAnimation) {
|
|
2503
|
-
this
|
|
2504
|
-
this.loadingAnimation = undefined;
|
|
2505
|
-
this.statusContainer.clear();
|
|
3087
|
+
this.#stopLoadingAnimation(true);
|
|
2506
3088
|
}
|
|
2507
3089
|
this.#uiHelpers.showError(message);
|
|
2508
3090
|
}
|
|
2509
3091
|
|
|
2510
3092
|
showPinnedError(message: string): void {
|
|
2511
|
-
if (this.isBackgrounded) return;
|
|
2512
3093
|
this.errorBannerContainer.clear();
|
|
2513
3094
|
this.errorBannerContainer.addChild(new ErrorBannerComponent(message));
|
|
2514
3095
|
this.ui.requestRender();
|
|
@@ -2566,26 +3147,76 @@ export class InteractiveMode implements InteractiveModeContext {
|
|
|
2566
3147
|
this.ui.requestRender();
|
|
2567
3148
|
}
|
|
2568
3149
|
|
|
3150
|
+
#clearWorkingMessageAccentCache(): void {
|
|
3151
|
+
this.#workingMessageAccentCacheKey = undefined;
|
|
3152
|
+
this.#workingMessageAccentCacheValue = undefined;
|
|
3153
|
+
this.#workingMessageAccentCacheHasValue = false;
|
|
3154
|
+
}
|
|
3155
|
+
|
|
3156
|
+
#buildWorkingMessageAccentCacheKey(): WorkingMessageAccentCacheKey {
|
|
3157
|
+
const sessionAccentEnabled = !isSettingsInitialized() || settings.get("statusLine.sessionAccent") !== false;
|
|
3158
|
+
return {
|
|
3159
|
+
sessionAccentEnabled,
|
|
3160
|
+
sessionName: sessionAccentEnabled ? this.sessionManager.getSessionName() : undefined,
|
|
3161
|
+
accentSurfaceLuminance: theme.accentSurfaceLuminance,
|
|
3162
|
+
};
|
|
3163
|
+
}
|
|
3164
|
+
|
|
3165
|
+
#workingMessageAccentCacheKeyEquals(a: WorkingMessageAccentCacheKey, b: WorkingMessageAccentCacheKey): boolean {
|
|
3166
|
+
return (
|
|
3167
|
+
a.sessionName === b.sessionName &&
|
|
3168
|
+
a.accentSurfaceLuminance === b.accentSurfaceLuminance &&
|
|
3169
|
+
a.sessionAccentEnabled === b.sessionAccentEnabled
|
|
3170
|
+
);
|
|
3171
|
+
}
|
|
3172
|
+
|
|
3173
|
+
#cacheWorkingMessageAccent(
|
|
3174
|
+
key: WorkingMessageAccentCacheKey,
|
|
3175
|
+
value: WorkingMessageAccent | undefined,
|
|
3176
|
+
): WorkingMessageAccent | undefined {
|
|
3177
|
+
this.#workingMessageAccentCacheKey = key;
|
|
3178
|
+
this.#workingMessageAccentCacheValue = value;
|
|
3179
|
+
this.#workingMessageAccentCacheHasValue = true;
|
|
3180
|
+
return value;
|
|
3181
|
+
}
|
|
3182
|
+
|
|
2569
3183
|
#getWorkingMessageAccent(): WorkingMessageAccent | undefined {
|
|
2570
|
-
const
|
|
2571
|
-
|
|
2572
|
-
|
|
2573
|
-
|
|
3184
|
+
const key = this.#buildWorkingMessageAccentCacheKey();
|
|
3185
|
+
if (
|
|
3186
|
+
this.#workingMessageAccentCacheHasValue &&
|
|
3187
|
+
this.#workingMessageAccentCacheKey &&
|
|
3188
|
+
this.#workingMessageAccentCacheKeyEquals(key, this.#workingMessageAccentCacheKey)
|
|
3189
|
+
) {
|
|
3190
|
+
return this.#workingMessageAccentCacheValue;
|
|
3191
|
+
}
|
|
3192
|
+
if (!key.sessionAccentEnabled || !key.sessionName) {
|
|
3193
|
+
return this.#cacheWorkingMessageAccent(key, undefined);
|
|
3194
|
+
}
|
|
3195
|
+
const hex = getSessionAccentHex(key.sessionName, theme.getMajorThemeColorHexes(), key.accentSurfaceLuminance);
|
|
2574
3196
|
const main = getSessionAccentAnsi(hex);
|
|
2575
3197
|
const dim = getSessionAccentAnsi(adjustHsv(hex, { s: 0.55, v: 0.65 }));
|
|
2576
|
-
return main && dim ? { main, dim } : undefined;
|
|
3198
|
+
return this.#cacheWorkingMessageAccent(key, main && dim ? { main, dim } : undefined);
|
|
2577
3199
|
}
|
|
2578
3200
|
|
|
2579
3201
|
ensureLoadingAnimation(): void {
|
|
2580
3202
|
if (!this.loadingAnimation) {
|
|
3203
|
+
this.#clearWorkingMessageAccentCache();
|
|
2581
3204
|
this.statusContainer.clear();
|
|
3205
|
+
const messageColorFn = ((message: string) =>
|
|
3206
|
+
renderWorkingMessage(message, this.#getWorkingMessageAccent())) as LoaderMessageColorFn & {
|
|
3207
|
+
animated?: true;
|
|
3208
|
+
};
|
|
3209
|
+
// Shimmer drives the 30fps redraw; when it is disabled the working
|
|
3210
|
+
// message is static, so leave `animated` unset and let the loader use
|
|
3211
|
+
// the spinner-only ~12.5fps cadence instead of repainting a frozen line.
|
|
3212
|
+
if (shimmerEnabled()) messageColorFn.animated = true;
|
|
2582
3213
|
this.loadingAnimation = new Loader(
|
|
2583
3214
|
this.ui,
|
|
2584
3215
|
spinner => {
|
|
2585
3216
|
const accent = this.#getWorkingMessageAccent();
|
|
2586
3217
|
return accent ? `${accent.main}${spinner}\x1b[39m` : theme.fg("accent", spinner);
|
|
2587
3218
|
},
|
|
2588
|
-
|
|
3219
|
+
messageColorFn,
|
|
2589
3220
|
this.#defaultWorkingMessage,
|
|
2590
3221
|
getSymbolTheme().spinnerFrames,
|
|
2591
3222
|
);
|
|
@@ -2595,6 +3226,16 @@ export class InteractiveMode implements InteractiveModeContext {
|
|
|
2595
3226
|
this.applyPendingWorkingMessage();
|
|
2596
3227
|
}
|
|
2597
3228
|
|
|
3229
|
+
#stopLoadingAnimation(clearStatusContainer: boolean): void {
|
|
3230
|
+
if (!this.loadingAnimation) return;
|
|
3231
|
+
this.loadingAnimation.stop();
|
|
3232
|
+
this.loadingAnimation = undefined;
|
|
3233
|
+
this.#clearWorkingMessageAccentCache();
|
|
3234
|
+
if (clearStatusContainer) {
|
|
3235
|
+
this.statusContainer.clear();
|
|
3236
|
+
}
|
|
3237
|
+
}
|
|
3238
|
+
|
|
2598
3239
|
setWorkingMessage(message?: string): void {
|
|
2599
3240
|
if (message === undefined) {
|
|
2600
3241
|
this.#pendingWorkingMessage = undefined;
|
|
@@ -2634,8 +3275,8 @@ export class InteractiveMode implements InteractiveModeContext {
|
|
|
2634
3275
|
this.#uiHelpers.updatePendingMessagesDisplay();
|
|
2635
3276
|
}
|
|
2636
3277
|
|
|
2637
|
-
queueCompactionMessage(text: string, mode: "steer" | "followUp"): void {
|
|
2638
|
-
this.#uiHelpers.queueCompactionMessage(text, mode);
|
|
3278
|
+
queueCompactionMessage(text: string, mode: "steer" | "followUp", images?: ImageContent[]): void {
|
|
3279
|
+
this.#uiHelpers.queueCompactionMessage(text, mode, images);
|
|
2639
3280
|
}
|
|
2640
3281
|
|
|
2641
3282
|
flushCompactionQueue(options?: { willRetry?: boolean }): Promise<void> {
|
|
@@ -2664,11 +3305,8 @@ export class InteractiveMode implements InteractiveModeContext {
|
|
|
2664
3305
|
this.#uiHelpers.renderSessionContext(sessionContext, options);
|
|
2665
3306
|
}
|
|
2666
3307
|
|
|
2667
|
-
renderInitialMessages(
|
|
2668
|
-
|
|
2669
|
-
options?: { preserveExistingChat?: boolean; clearTerminalHistory?: boolean },
|
|
2670
|
-
): void {
|
|
2671
|
-
this.#uiHelpers.renderInitialMessages(prebuiltContext, options);
|
|
3308
|
+
renderInitialMessages(options?: { preserveExistingChat?: boolean; clearTerminalHistory?: boolean }): void {
|
|
3309
|
+
this.#uiHelpers.renderInitialMessages(options);
|
|
2672
3310
|
}
|
|
2673
3311
|
|
|
2674
3312
|
getUserMessageText(message: Message): string {
|
|
@@ -2737,7 +3375,7 @@ export class InteractiveMode implements InteractiveModeContext {
|
|
|
2737
3375
|
this.#omfgController.dispose();
|
|
2738
3376
|
this.#extensionUiController.clearExtensionTerminalInputListeners();
|
|
2739
3377
|
this.clearPinnedError();
|
|
2740
|
-
this.#
|
|
3378
|
+
this.#hidePlanReview();
|
|
2741
3379
|
}
|
|
2742
3380
|
|
|
2743
3381
|
handleClearCommand(): Promise<void> {
|
|
@@ -2745,6 +3383,10 @@ export class InteractiveMode implements InteractiveModeContext {
|
|
|
2745
3383
|
return this.#commandController.handleClearCommand();
|
|
2746
3384
|
}
|
|
2747
3385
|
|
|
3386
|
+
handleFreshCommand(): Promise<void> {
|
|
3387
|
+
return this.#commandController.handleFreshCommand();
|
|
3388
|
+
}
|
|
3389
|
+
|
|
2748
3390
|
handleDropCommand(): Promise<void> {
|
|
2749
3391
|
this.#prepareSessionSwitch();
|
|
2750
3392
|
return this.#commandController.handleDropCommand();
|
|
@@ -2779,7 +3421,11 @@ export class InteractiveMode implements InteractiveModeContext {
|
|
|
2779
3421
|
await this.#sttController.toggle(this.editor, {
|
|
2780
3422
|
showWarning: (msg: string) => this.showWarning(msg),
|
|
2781
3423
|
showStatus: (msg: string) => this.showStatus(msg),
|
|
3424
|
+
requestRender: () => this.ui.requestRender(),
|
|
2782
3425
|
onStateChange: (state: SttState) => {
|
|
3426
|
+
// Duck assistant speech while the user is talking (push-to-talk); restore after.
|
|
3427
|
+
if (state === "recording") vocalizer.duck();
|
|
3428
|
+
else vocalizer.unduck();
|
|
2783
3429
|
if (state === "recording") {
|
|
2784
3430
|
this.#voicePreviousShowHardwareCursor = this.ui.getShowHardwareCursor();
|
|
2785
3431
|
this.#voicePreviousUseTerminalCursor = this.editor.getUseTerminalCursor();
|
|
@@ -2816,7 +3462,9 @@ export class InteractiveMode implements InteractiveModeContext {
|
|
|
2816
3462
|
this.#voiceAnimationInterval = setInterval(() => {
|
|
2817
3463
|
this.#voiceHue = (this.#voiceHue + 8) % 360;
|
|
2818
3464
|
this.#updateMicIcon();
|
|
2819
|
-
|
|
3465
|
+
// Component-scoped: the hue sweep only recolors the editor's cursor
|
|
3466
|
+
// glyph, so the transcript subtree is reused per animation frame.
|
|
3467
|
+
this.ui.requestComponentRender(this.editor);
|
|
2820
3468
|
}, 60);
|
|
2821
3469
|
}
|
|
2822
3470
|
|
|
@@ -2844,17 +3492,12 @@ export class InteractiveMode implements InteractiveModeContext {
|
|
|
2844
3492
|
}
|
|
2845
3493
|
}
|
|
2846
3494
|
|
|
2847
|
-
showDebugSelector(): void {
|
|
2848
|
-
this.#selectorController.showDebugSelector();
|
|
3495
|
+
async showDebugSelector(): Promise<void> {
|
|
3496
|
+
await this.#selectorController.showDebugSelector();
|
|
2849
3497
|
}
|
|
2850
3498
|
|
|
2851
|
-
|
|
2852
|
-
|
|
2853
|
-
if (sessions.length <= 1) {
|
|
2854
|
-
this.showStatus("No active subagent sessions");
|
|
2855
|
-
return;
|
|
2856
|
-
}
|
|
2857
|
-
this.#selectorController.showSessionObserver(this.#observerRegistry);
|
|
3499
|
+
showAgentHub(options?: { requireContent?: boolean }): void {
|
|
3500
|
+
this.#selectorController.showAgentHub(this.#observerRegistry, options);
|
|
2858
3501
|
}
|
|
2859
3502
|
|
|
2860
3503
|
resetObserverRegistry(): void {
|
|
@@ -2880,8 +3523,11 @@ export class InteractiveMode implements InteractiveModeContext {
|
|
|
2880
3523
|
await controller.handle(text);
|
|
2881
3524
|
}
|
|
2882
3525
|
|
|
2883
|
-
handleCompactCommand(
|
|
2884
|
-
|
|
3526
|
+
handleCompactCommand(
|
|
3527
|
+
customInstructions?: string,
|
|
3528
|
+
beforeFlush?: (outcome: CompactionOutcome) => void | Promise<void>,
|
|
3529
|
+
): Promise<CompactionOutcome> {
|
|
3530
|
+
return this.#commandController.handleCompactCommand(customInstructions, beforeFlush);
|
|
2885
3531
|
}
|
|
2886
3532
|
|
|
2887
3533
|
handleHandoffCommand(customInstructions?: string): Promise<void> {
|
|
@@ -2959,6 +3605,14 @@ export class InteractiveMode implements InteractiveModeContext {
|
|
|
2959
3605
|
return this.#selectorController.showOAuthSelector(mode, providerId);
|
|
2960
3606
|
}
|
|
2961
3607
|
|
|
3608
|
+
showResetUsageSelector(): Promise<void> {
|
|
3609
|
+
return this.#selectorController.showResetUsageSelector();
|
|
3610
|
+
}
|
|
3611
|
+
|
|
3612
|
+
showProviderSetup(): Promise<void> {
|
|
3613
|
+
return runProviderSetupWizard(this);
|
|
3614
|
+
}
|
|
3615
|
+
|
|
2962
3616
|
showHookConfirm(title: string, message: string): Promise<boolean> {
|
|
2963
3617
|
return this.#extensionUiController.showHookConfirm(title, message);
|
|
2964
3618
|
}
|
|
@@ -2980,10 +3634,6 @@ export class InteractiveMode implements InteractiveModeContext {
|
|
|
2980
3634
|
this.#inputController.handleDequeue();
|
|
2981
3635
|
}
|
|
2982
3636
|
|
|
2983
|
-
handleBackgroundCommand(): void {
|
|
2984
|
-
this.#inputController.handleBackgroundCommand();
|
|
2985
|
-
}
|
|
2986
|
-
|
|
2987
3637
|
handleImagePaste(): Promise<boolean> {
|
|
2988
3638
|
return this.#inputController.handleImagePaste();
|
|
2989
3639
|
}
|
|
@@ -2992,6 +3642,10 @@ export class InteractiveMode implements InteractiveModeContext {
|
|
|
2992
3642
|
return this.#btwController.start(question);
|
|
2993
3643
|
}
|
|
2994
3644
|
|
|
3645
|
+
handleTanCommand(work: string): Promise<void> {
|
|
3646
|
+
return this.#tanCommandController.start(work);
|
|
3647
|
+
}
|
|
3648
|
+
|
|
2995
3649
|
hasActiveBtw(): boolean {
|
|
2996
3650
|
return this.#btwController.hasActiveRequest();
|
|
2997
3651
|
}
|