@prometheus-ai/agent 0.5.4 → 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 +30 -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/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/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 +1202 -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/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/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/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 +1441 -387
- 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/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 +9 -7
- 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/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
|
@@ -1,24 +1,29 @@
|
|
|
1
1
|
import * as fs from "node:fs/promises";
|
|
2
|
-
import
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
2
|
+
import * as path from "node:path";
|
|
3
|
+
import type { ImageContent } from "@prometheus-ai/ai";
|
|
4
|
+
import { type AutocompleteProvider, matchesKey, type SlashCommand } from "@prometheus-ai/tui";
|
|
5
|
+
import { $env, isEnoent, logger, sanitizeText } from "@prometheus-ai/utils";
|
|
5
6
|
import { isSettingsInitialized, settings } from "../../config/settings";
|
|
7
|
+
import { resolveLocalRoot } from "../../internal-urls";
|
|
8
|
+
import { AssistantMessageComponent } from "../../modes/components/assistant-message";
|
|
6
9
|
import { renderSegmentTrack } from "../../modes/components/segment-track";
|
|
7
10
|
import { TinyTitleDownloadProgressComponent } from "../../modes/components/tiny-title-download-progress";
|
|
8
11
|
import { expandEmoticons } from "../../modes/emoji-autocomplete";
|
|
9
|
-
import { materializeImageReferenceLinks } from "../../modes/image-references";
|
|
12
|
+
import { materializeImageReferenceLinks, shiftImageMarkers } from "../../modes/image-references";
|
|
10
13
|
import { createPromptActionAutocompleteProvider } from "../../modes/prompt-action-autocomplete";
|
|
11
14
|
import type { InteractiveModeContext } from "../../modes/types";
|
|
12
|
-
import
|
|
13
|
-
import { SKILL_PROMPT_MESSAGE_TYPE, type SkillPromptDetails } from "../../session/messages";
|
|
15
|
+
import manualContinuePrompt from "../../prompts/system/manual-continue.md" with { type: "text" };
|
|
16
|
+
import { SKILL_PROMPT_MESSAGE_TYPE, type SkillPromptDetails, USER_INTERRUPT_LABEL } from "../../session/messages";
|
|
14
17
|
import { executeBuiltinSlashCommand } from "../../slash-commands/builtin-registry";
|
|
15
18
|
import { isTinyTitleLocalModelKey } from "../../tiny/models";
|
|
16
19
|
import { isLowSignalTitleInput } from "../../tiny/text";
|
|
17
20
|
import { tinyTitleClient } from "../../tiny/title-client";
|
|
18
21
|
import type { TinyTitleProgressEvent } from "../../tiny/title-protocol";
|
|
22
|
+
import { shortenPath, TRUNCATE_LENGTHS, truncateToWidth } from "../../tools/render-utils";
|
|
19
23
|
import { copyToClipboard, readImageFromClipboard, readTextFromClipboard } from "../../utils/clipboard";
|
|
24
|
+
import { EnhancedPasteController } from "../../utils/enhanced-paste";
|
|
20
25
|
import { getEditorCommand, openInEditor } from "../../utils/external-editor";
|
|
21
|
-
import { ensureSupportedImageInput } from "../../utils/image-loading";
|
|
26
|
+
import { ensureSupportedImageInput, ImageInputTooLargeError, loadImageInput } from "../../utils/image-loading";
|
|
22
27
|
import { resizeImage } from "../../utils/image-resize";
|
|
23
28
|
import { generateSessionTitle, setSessionTerminalTitle } from "../../utils/title-generator";
|
|
24
29
|
|
|
@@ -30,18 +35,76 @@ function isExpandable(obj: unknown): obj is Expandable {
|
|
|
30
35
|
return typeof obj === "object" && obj !== null && "setExpanded" in obj && typeof obj.setExpanded === "function";
|
|
31
36
|
}
|
|
32
37
|
|
|
38
|
+
/** Minimal contract for any component that can receive a paste payload directly. */
|
|
39
|
+
interface PasteTarget {
|
|
40
|
+
pasteText(text: string): void;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function hasPasteText(value: unknown): value is PasteTarget {
|
|
44
|
+
return typeof value === "object" && value !== null && typeof (value as PasteTarget).pasteText === "function";
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/** Wrap pasted text in a fenced code block, using a backtick fence longer than any run of
|
|
48
|
+
* backticks already in the content so an embedded fence cannot terminate the block early. */
|
|
49
|
+
function wrapPasteInCodeBlock(content: string): string {
|
|
50
|
+
let longestRun = 0;
|
|
51
|
+
let run = 0;
|
|
52
|
+
for (let i = 0; i < content.length; i++) {
|
|
53
|
+
if (content.charCodeAt(i) === 96 /* backtick */) {
|
|
54
|
+
run++;
|
|
55
|
+
if (run > longestRun) longestRun = run;
|
|
56
|
+
} else {
|
|
57
|
+
run = 0;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
const fence = "`".repeat(Math.max(3, longestRun + 1));
|
|
61
|
+
return `${fence}\n${content}\n${fence}`;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/** Wrap pasted text in `<pasted_text>` tags so the model treats it as one quoted block. */
|
|
65
|
+
function wrapPasteInXml(content: string): string {
|
|
66
|
+
return `<pasted_text>\n${content}\n</pasted_text>`;
|
|
67
|
+
}
|
|
68
|
+
|
|
33
69
|
const TINY_TITLE_PROGRESS_DONE_TTL_MS = 3_000;
|
|
34
70
|
// A cached model fires its file-load events in a short burst and then goes silent
|
|
35
71
|
// while onnxruntime builds the session; a genuine download keeps streaming progress
|
|
36
72
|
// events for seconds. Only reveal the bar once a still-incomplete event arrives after
|
|
37
73
|
// this grace window, so an already-downloaded model never flashes the bar.
|
|
38
74
|
const TINY_TITLE_PROGRESS_REVEAL_DELAY_MS = 1_000;
|
|
75
|
+
// Double-tap ← on an empty editor opens the Agent Hub (and, in a focused
|
|
76
|
+
// subagent view, ←← returns to the main session). The second tap must land
|
|
77
|
+
// inside this window. The lower bound rejects terminal-synthesized arrow-key
|
|
78
|
+
// bursts: "click to move cursor" / pointer features in iTerm2, WezTerm, kitty,
|
|
79
|
+
// and tmux emit several arrow keys in a single stdin read (sub-millisecond
|
|
80
|
+
// apart) on a stray click, which used to pop the hub with no key ever pressed.
|
|
81
|
+
// Three or more rapid taps are likewise treated as a burst, not a gesture. A
|
|
82
|
+
// deliberate human double-tap is always tens of milliseconds apart.
|
|
83
|
+
const LEFT_DOUBLE_TAP_MIN_GAP_MS = 40;
|
|
84
|
+
const LEFT_DOUBLE_TAP_MAX_GAP_MS = 500;
|
|
39
85
|
|
|
40
86
|
export class InputController {
|
|
41
|
-
constructor(
|
|
87
|
+
constructor(
|
|
88
|
+
private ctx: InteractiveModeContext,
|
|
89
|
+
/** Injectable clipboard reads so tests can drive paste flows without a real clipboard. */
|
|
90
|
+
private clipboard: {
|
|
91
|
+
readImage: typeof readImageFromClipboard;
|
|
92
|
+
readText: typeof readTextFromClipboard;
|
|
93
|
+
} = { readImage: readImageFromClipboard, readText: readTextFromClipboard },
|
|
94
|
+
) {}
|
|
95
|
+
|
|
96
|
+
#enhancedPaste?: EnhancedPasteController;
|
|
97
|
+
#focusedLeftTapListenerInstalled = false;
|
|
98
|
+
// Tap counter for the double-← gesture; reset whenever a quiet gap
|
|
99
|
+
// (>= LEFT_DOUBLE_TAP_MAX_GAP_MS) starts a fresh sequence. See
|
|
100
|
+
// #detectLeftDoubleTap.
|
|
101
|
+
#leftTapCount = 0;
|
|
102
|
+
// Sequential index for `local://attachment-N` references created by the large-paste "attach as
|
|
103
|
+
// file" action. Seeded from 0 and bumped past any existing attachment files in #attachPasteAsFile.
|
|
104
|
+
#attachmentCounter = 0;
|
|
42
105
|
|
|
43
106
|
#showTinyTitleDownloadProgress(modelKey: string): void {
|
|
44
|
-
if (!isTinyTitleLocalModelKey(modelKey)
|
|
107
|
+
if (!isTinyTitleLocalModelKey(modelKey)) return;
|
|
45
108
|
const component = new TinyTitleDownloadProgressComponent(modelKey);
|
|
46
109
|
let added = false;
|
|
47
110
|
let disposed = false;
|
|
@@ -87,11 +150,50 @@ export class InputController {
|
|
|
87
150
|
|
|
88
151
|
setupKeyHandlers(): void {
|
|
89
152
|
this.ctx.editor.setActionKeys("app.interrupt", this.ctx.keybindings.getKeys("app.interrupt"));
|
|
153
|
+
if (!this.#focusedLeftTapListenerInstalled) {
|
|
154
|
+
this.#focusedLeftTapListenerInstalled = true;
|
|
155
|
+
this.ctx.ui.addInputListener(data => {
|
|
156
|
+
if (!this.ctx.focusedAgentId) return undefined;
|
|
157
|
+
if (!matchesKey(data, "left")) return undefined;
|
|
158
|
+
if (this.ctx.editor.getText().trim()) return undefined;
|
|
159
|
+
this.#handleFocusedLeftTap();
|
|
160
|
+
return { consume: true };
|
|
161
|
+
});
|
|
162
|
+
}
|
|
90
163
|
this.ctx.editor.onEscape = () => {
|
|
164
|
+
// Active context maintenance owns Esc: auto/manual compaction,
|
|
165
|
+
// handoff generation, and auto-retry backoff all advertise
|
|
166
|
+
// "(esc to cancel)". Dispatch on live session state instead of
|
|
167
|
+
// swapping onEscape handlers — interleaved start/end events used
|
|
168
|
+
// to clobber the single saved-handler slot (auto-compaction start
|
|
169
|
+
// → /compact → auto end → manual finally), leaving Esc wired to a
|
|
170
|
+
// stale no-op closure until restart.
|
|
171
|
+
const viewSession = this.ctx.viewSession;
|
|
172
|
+
let aborted = false;
|
|
173
|
+
if (viewSession.isCompacting) {
|
|
174
|
+
try {
|
|
175
|
+
viewSession.abortCompaction();
|
|
176
|
+
} catch {}
|
|
177
|
+
aborted = true;
|
|
178
|
+
}
|
|
179
|
+
if (viewSession.isGeneratingHandoff) {
|
|
180
|
+
try {
|
|
181
|
+
viewSession.abortHandoff();
|
|
182
|
+
} catch {}
|
|
183
|
+
aborted = true;
|
|
184
|
+
}
|
|
185
|
+
if (viewSession.isRetrying) {
|
|
186
|
+
try {
|
|
187
|
+
viewSession.abortRetry();
|
|
188
|
+
} catch {}
|
|
189
|
+
aborted = true;
|
|
190
|
+
}
|
|
191
|
+
if (aborted) return;
|
|
192
|
+
|
|
91
193
|
if (this.ctx.loopModeEnabled) {
|
|
92
194
|
this.ctx.pauseLoop();
|
|
93
195
|
if (this.ctx.session.isStreaming) {
|
|
94
|
-
void this.ctx.session.abort();
|
|
196
|
+
void this.ctx.session.abort({ reason: USER_INTERRUPT_LABEL });
|
|
95
197
|
} else {
|
|
96
198
|
this.ctx.cancelPendingSubmission();
|
|
97
199
|
}
|
|
@@ -103,6 +205,27 @@ export class InputController {
|
|
|
103
205
|
if (this.ctx.hasActiveOmfg() && this.ctx.handleOmfgEscape()) {
|
|
104
206
|
return;
|
|
105
207
|
}
|
|
208
|
+
if (this.ctx.focusedAgentId) {
|
|
209
|
+
// Esc never interrupts the focused agent's turn: clear typed text,
|
|
210
|
+
// else return the view to the main session. Interrupt via empty
|
|
211
|
+
// steer-flush submit if needed.
|
|
212
|
+
if (this.ctx.editor.getText().trim()) {
|
|
213
|
+
this.ctx.editor.setText("");
|
|
214
|
+
this.ctx.ui.requestRender();
|
|
215
|
+
} else {
|
|
216
|
+
void this.ctx.unfocusSession();
|
|
217
|
+
}
|
|
218
|
+
return; // double-escape backtrack (/tree, /branch) stays main-only
|
|
219
|
+
}
|
|
220
|
+
if (this.ctx.collabGuest) {
|
|
221
|
+
// Guest Esc: ask the host to interrupt its agent; the local replica
|
|
222
|
+
// session is never streaming, so the native abort path below would
|
|
223
|
+
// no-op.
|
|
224
|
+
if (this.ctx.collabGuest.state?.isStreaming || this.ctx.loadingAnimation) {
|
|
225
|
+
this.ctx.collabGuest.sendAbort();
|
|
226
|
+
}
|
|
227
|
+
return;
|
|
228
|
+
}
|
|
106
229
|
if (this.ctx.loadingAnimation) {
|
|
107
230
|
if (this.ctx.cancelPendingSubmission()) {
|
|
108
231
|
return;
|
|
@@ -121,8 +244,13 @@ export class InputController {
|
|
|
121
244
|
this.ctx.isPythonMode = false;
|
|
122
245
|
this.ctx.updateEditorBorderColor();
|
|
123
246
|
} else if (this.ctx.session.isStreaming) {
|
|
124
|
-
void this.ctx.session.abort();
|
|
125
|
-
} else if (
|
|
247
|
+
void this.ctx.session.abort({ reason: USER_INTERRUPT_LABEL });
|
|
248
|
+
} else if (this.ctx.editor.getText().trim()) {
|
|
249
|
+
// Esc with typed text clears the draft instead of (or before) any double-Esc action
|
|
250
|
+
this.ctx.editor.setText("");
|
|
251
|
+
this.ctx.ui.requestRender();
|
|
252
|
+
this.ctx.lastEscapeTime = 0;
|
|
253
|
+
} else {
|
|
126
254
|
// Double-interrupt with empty editor triggers /tree, /branch, or nothing based on setting
|
|
127
255
|
const action = settings.get("doubleEscapeAction");
|
|
128
256
|
if (action !== "none") {
|
|
@@ -133,6 +261,7 @@ export class InputController {
|
|
|
133
261
|
} else {
|
|
134
262
|
this.ctx.showUserMessageSelector();
|
|
135
263
|
}
|
|
264
|
+
this.ctx.ui.resetDisplay();
|
|
136
265
|
this.ctx.lastEscapeTime = 0;
|
|
137
266
|
} else {
|
|
138
267
|
this.ctx.lastEscapeTime = now;
|
|
@@ -176,11 +305,13 @@ export class InputController {
|
|
|
176
305
|
this.ctx.keybindings.getKeys("app.clipboard.pasteImage"),
|
|
177
306
|
);
|
|
178
307
|
this.ctx.editor.onPasteImage = () => this.handleImagePaste();
|
|
308
|
+
this.ctx.editor.onPasteImagePath = path => this.handleImagePathPaste(path);
|
|
179
309
|
this.ctx.editor.setActionKeys(
|
|
180
310
|
"app.clipboard.pasteTextRaw",
|
|
181
311
|
this.ctx.keybindings.getKeys("app.clipboard.pasteTextRaw"),
|
|
182
312
|
);
|
|
183
313
|
this.ctx.editor.onPasteTextRaw = () => void this.handleClipboardTextRawPaste();
|
|
314
|
+
this.ctx.editor.onLargePaste = (text, lineCount) => this.handleLargePaste(text, lineCount);
|
|
184
315
|
this.ctx.editor.setActionKeys(
|
|
185
316
|
"app.clipboard.copyPrompt",
|
|
186
317
|
this.ctx.keybindings.getKeys("app.clipboard.copyPrompt"),
|
|
@@ -216,13 +347,40 @@ export class InputController {
|
|
|
216
347
|
for (const key of this.ctx.keybindings.getKeys("app.stt.toggle")) {
|
|
217
348
|
this.ctx.editor.setCustomKeyHandler(key, () => void this.ctx.handleSTTToggle());
|
|
218
349
|
}
|
|
350
|
+
// Hold the space bar to push-to-talk: the editor recognizes the auto-repeat burst, tracks
|
|
351
|
+
// the spam back out, and toggles STT on hold start / release. Gated on `stt.enabled` so a
|
|
352
|
+
// disabled STT leaves the space bar typing normally.
|
|
353
|
+
this.ctx.editor.sttHoldEnabled = () => settings.get("stt.enabled");
|
|
354
|
+
this.ctx.editor.onSpaceHoldStart = () => void this.ctx.handleSTTToggle();
|
|
355
|
+
this.ctx.editor.onSpaceHoldEnd = () => void this.ctx.handleSTTToggle();
|
|
219
356
|
for (const key of this.ctx.keybindings.getKeys("app.clipboard.copyLine")) {
|
|
220
357
|
this.ctx.editor.setCustomKeyHandler(key, () => this.handleCopyCurrentLine());
|
|
221
358
|
}
|
|
222
|
-
|
|
223
|
-
this.ctx.
|
|
359
|
+
const hubKeys = new Set([
|
|
360
|
+
...this.ctx.keybindings.getKeys("app.agents.hub"),
|
|
361
|
+
...this.ctx.keybindings.getKeys("app.session.observe"),
|
|
362
|
+
]);
|
|
363
|
+
for (const key of hubKeys) {
|
|
364
|
+
this.ctx.editor.setCustomKeyHandler(key, () => this.ctx.showAgentHub());
|
|
224
365
|
}
|
|
225
366
|
|
|
367
|
+
// Double-tap left arrow on an empty editor: opens the agent hub from the
|
|
368
|
+
// main session, or returns the focused subagent view to the main session.
|
|
369
|
+
// Focused ←← intentionally matches Esc. From the main session the gesture
|
|
370
|
+
// stays inert when there are no subagents (requireContent); the explicit
|
|
371
|
+
// hub key still opens the empty roster.
|
|
372
|
+
this.ctx.editor.onLeftAtStart = () => {
|
|
373
|
+
if (this.ctx.focusedAgentId) {
|
|
374
|
+
this.#handleFocusedLeftTap();
|
|
375
|
+
return;
|
|
376
|
+
}
|
|
377
|
+
if (this.#detectLeftDoubleTap()) {
|
|
378
|
+
this.ctx.showAgentHub({ requireContent: true });
|
|
379
|
+
}
|
|
380
|
+
};
|
|
381
|
+
|
|
382
|
+
this.#setupEnhancedPaste();
|
|
383
|
+
|
|
226
384
|
this.ctx.editor.onChange = (text: string) => {
|
|
227
385
|
const wasBashMode = this.ctx.isBashMode;
|
|
228
386
|
const wasPythonMode = this.ctx.isPythonMode;
|
|
@@ -235,28 +393,114 @@ export class InputController {
|
|
|
235
393
|
};
|
|
236
394
|
}
|
|
237
395
|
|
|
396
|
+
#handleFocusedLeftTap(): void {
|
|
397
|
+
if (this.#detectLeftDoubleTap()) {
|
|
398
|
+
void this.ctx.unfocusSession();
|
|
399
|
+
}
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
/**
|
|
403
|
+
* Detect a deliberate double-← gesture, rejecting terminal-synthesized arrow
|
|
404
|
+
* bursts. Returns true only on the *second* tap of a fresh sequence when it
|
|
405
|
+
* lands a human-plausible interval after the first
|
|
406
|
+
* (`[LEFT_DOUBLE_TAP_MIN_GAP_MS, LEFT_DOUBLE_TAP_MAX_GAP_MS)`). Taps closer
|
|
407
|
+
* than the lower bound, or any third-and-later tap before a quiet gap, are a
|
|
408
|
+
* burst and never fire — so a stray click that makes the terminal emit a run
|
|
409
|
+
* of ← keys can no longer pop the Agent Hub.
|
|
410
|
+
*/
|
|
411
|
+
#detectLeftDoubleTap(): boolean {
|
|
412
|
+
const now = Date.now();
|
|
413
|
+
const sinceLast = now - this.ctx.lastLeftTapTime;
|
|
414
|
+
this.ctx.lastLeftTapTime = now;
|
|
415
|
+
if (sinceLast >= LEFT_DOUBLE_TAP_MAX_GAP_MS) {
|
|
416
|
+
// Quiet gap: this tap starts a fresh sequence.
|
|
417
|
+
this.#leftTapCount = 1;
|
|
418
|
+
return false;
|
|
419
|
+
}
|
|
420
|
+
this.#leftTapCount += 1;
|
|
421
|
+
if (this.#leftTapCount === 2 && sinceLast >= LEFT_DOUBLE_TAP_MIN_GAP_MS) {
|
|
422
|
+
// Exactly two taps, the second a human-plausible interval after the first.
|
|
423
|
+
this.#leftTapCount = 0;
|
|
424
|
+
this.ctx.lastLeftTapTime = 0;
|
|
425
|
+
return true;
|
|
426
|
+
}
|
|
427
|
+
return false;
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
#setupEnhancedPaste(): void {
|
|
431
|
+
if (this.#enhancedPaste) return;
|
|
432
|
+
|
|
433
|
+
this.#enhancedPaste = new EnhancedPasteController({
|
|
434
|
+
write: data => this.ctx.ui.terminal.write(data),
|
|
435
|
+
pasteText: text => {
|
|
436
|
+
// Route enhanced-paste text to the currently focused component when it
|
|
437
|
+
// exposes a `pasteText` hook (modal Input prompts: OAuth API-key entry,
|
|
438
|
+
// Perplexity OTP, GitHub Enterprise URL, manual redirect URL). Falling
|
|
439
|
+
// back to the main editor would have buried the text in the detached
|
|
440
|
+
// editor while the modal Input had focus (#2127).
|
|
441
|
+
const focused = this.ctx.ui.getFocused();
|
|
442
|
+
const target = focused && focused !== this.ctx.editor && hasPasteText(focused) ? focused : this.ctx.editor;
|
|
443
|
+
target.pasteText(text);
|
|
444
|
+
this.ctx.ui.requestRender();
|
|
445
|
+
},
|
|
446
|
+
pasteImage: async image => {
|
|
447
|
+
// Images can only land in the main editor — when a modal Input is
|
|
448
|
+
// focused, refuse rather than dump the binary blob in a hidden buffer.
|
|
449
|
+
const focused = this.ctx.ui.getFocused();
|
|
450
|
+
if (focused && focused !== this.ctx.editor && hasPasteText(focused)) {
|
|
451
|
+
this.ctx.showStatus("Image paste is not supported in this prompt");
|
|
452
|
+
return;
|
|
453
|
+
}
|
|
454
|
+
await this.#normalizeAndInsertPastedImage(image, `Unsupported pasted image format: ${image.mimeType}`);
|
|
455
|
+
},
|
|
456
|
+
showStatus: message => this.ctx.showStatus(message),
|
|
457
|
+
});
|
|
458
|
+
this.ctx.ui.addInputListener(data => (this.#enhancedPaste?.handleInput(data) ? { consume: true } : undefined));
|
|
459
|
+
this.ctx.ui.addStartListener(() => this.#enhancedPaste?.enable());
|
|
460
|
+
}
|
|
461
|
+
|
|
238
462
|
setupEditorSubmitHandler(): void {
|
|
239
463
|
this.ctx.editor.onSubmit = async (text: string) => {
|
|
240
464
|
text = text.trim();
|
|
241
465
|
if ((!isSettingsInitialized() || settings.get("emojiAutocomplete")) && text) text = expandEmoticons(text);
|
|
242
466
|
|
|
243
|
-
//
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
467
|
+
// Focused subagent session: the editor is a plain chat box for it.
|
|
468
|
+
// Everything below (continue shortcuts, slash/bash/python, loop,
|
|
469
|
+
// compaction queueing) is main-session-only.
|
|
470
|
+
if (this.ctx.focusedAgentId) {
|
|
471
|
+
await this.#submitToFocusedSession(text, "steer");
|
|
472
|
+
return;
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
// Empty submit while streaming with queued messages: abort the active
|
|
476
|
+
// turn and let the post-unwind drain deliver the agent-core queue.
|
|
477
|
+
if (!text && this.ctx.session.isStreaming) {
|
|
478
|
+
if (this.ctx.session.queuedMessageCount > 0) {
|
|
479
|
+
const aborting = this.ctx.session.abort({ reason: USER_INTERRUPT_LABEL });
|
|
480
|
+
await aborting;
|
|
481
|
+
this.ctx.updatePendingMessagesDisplay();
|
|
482
|
+
this.ctx.ui.requestRender();
|
|
483
|
+
}
|
|
247
484
|
return;
|
|
248
485
|
}
|
|
249
486
|
|
|
250
487
|
if (!text) return;
|
|
251
488
|
|
|
252
|
-
// Continue shortcuts: "." or "c"
|
|
489
|
+
// Continue shortcuts: "." or "c" resume the agent with a hidden agent-authored
|
|
490
|
+
// developer directive (no visible user message) instead of an empty turn, so the
|
|
491
|
+
// model continues the prior intent rather than second-guessing the interrupt.
|
|
253
492
|
if (text === "." || text === "c") {
|
|
254
493
|
if (this.ctx.onInputCallback) {
|
|
255
494
|
this.ctx.editor.setText("");
|
|
256
495
|
this.ctx.pendingImages = [];
|
|
257
496
|
this.ctx.pendingImageLinks = [];
|
|
258
497
|
this.ctx.editor.imageLinks = undefined;
|
|
259
|
-
this.ctx.onInputCallback({
|
|
498
|
+
this.ctx.onInputCallback({
|
|
499
|
+
text: manualContinuePrompt,
|
|
500
|
+
cancelled: false,
|
|
501
|
+
started: true,
|
|
502
|
+
synthetic: true,
|
|
503
|
+
});
|
|
260
504
|
}
|
|
261
505
|
return;
|
|
262
506
|
}
|
|
@@ -291,7 +535,6 @@ export class InputController {
|
|
|
291
535
|
// Handle built-in slash commands
|
|
292
536
|
const slashResult = await executeBuiltinSlashCommand(text, {
|
|
293
537
|
ctx: this.ctx,
|
|
294
|
-
handleBackgroundCommand: () => this.handleBackgroundCommand(),
|
|
295
538
|
});
|
|
296
539
|
if (slashResult === true) {
|
|
297
540
|
return;
|
|
@@ -301,6 +544,37 @@ export class InputController {
|
|
|
301
544
|
text = slashResult;
|
|
302
545
|
}
|
|
303
546
|
|
|
547
|
+
// Collab guest: prompts execute on the host; local slash/skill/bash/
|
|
548
|
+
// python execution is host-only (builtins are gated inside
|
|
549
|
+
// executeBuiltinSlashCommand, which already consumed allowed ones).
|
|
550
|
+
if (this.ctx.collabGuest) {
|
|
551
|
+
if (text.startsWith("/")) {
|
|
552
|
+
this.ctx.showStatus(`${text.split(/\s+/, 1)[0]} is host-only during a collab session`);
|
|
553
|
+
this.ctx.editor.setText("");
|
|
554
|
+
return;
|
|
555
|
+
}
|
|
556
|
+
if (text.startsWith("!") || text.startsWith("$")) {
|
|
557
|
+
this.ctx.showStatus("Local execution is host-only during a collab session");
|
|
558
|
+
this.ctx.editor.setText("");
|
|
559
|
+
return;
|
|
560
|
+
}
|
|
561
|
+
if (this.ctx.collabGuest.readOnly) {
|
|
562
|
+
// Keep the typed text: the prompt was not consumed.
|
|
563
|
+
this.ctx.showStatus("This collab link is read-only — prompting is disabled");
|
|
564
|
+
return;
|
|
565
|
+
}
|
|
566
|
+
this.ctx.editor.addToHistory(text);
|
|
567
|
+
this.ctx.editor.setText("");
|
|
568
|
+
this.ctx.editor.imageLinks = undefined;
|
|
569
|
+
const images = inputImages && inputImages.length > 0 ? [...inputImages] : undefined;
|
|
570
|
+
this.ctx.pendingImages = [];
|
|
571
|
+
this.ctx.pendingImageLinks = [];
|
|
572
|
+
// No local render: the prompt comes back from the host as a
|
|
573
|
+
// collab-prompt event/entry and renders with the author badge.
|
|
574
|
+
this.ctx.collabGuest.sendPrompt(text, images);
|
|
575
|
+
return;
|
|
576
|
+
}
|
|
577
|
+
|
|
304
578
|
// Handle skill commands (/skill:name [args]). Enter ⇒ steer (matches the
|
|
305
579
|
// free-text Enter semantics applied a few lines below at the streaming
|
|
306
580
|
// branch). Ctrl+Enter routes through `handleFollowUp` and dispatches the
|
|
@@ -353,11 +627,8 @@ export class InputController {
|
|
|
353
627
|
|
|
354
628
|
// Queue input during compaction
|
|
355
629
|
if (this.ctx.session.isCompacting) {
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
return;
|
|
359
|
-
}
|
|
360
|
-
this.ctx.queueCompactionMessage(text, "steer");
|
|
630
|
+
const images = inputImages && inputImages.length > 0 ? [...inputImages] : undefined;
|
|
631
|
+
this.ctx.queueCompactionMessage(text, "steer", images);
|
|
361
632
|
return;
|
|
362
633
|
}
|
|
363
634
|
|
|
@@ -403,6 +674,7 @@ export class InputController {
|
|
|
403
674
|
this.ctx.session.sessionId,
|
|
404
675
|
this.ctx.session.model,
|
|
405
676
|
provider => this.ctx.session.agent.metadataForProvider(provider),
|
|
677
|
+
this.ctx.titleSystemPrompt,
|
|
406
678
|
)
|
|
407
679
|
.then(async title => {
|
|
408
680
|
// Re-check: a concurrent attempt for an earlier message may have
|
|
@@ -442,11 +714,76 @@ export class InputController {
|
|
|
442
714
|
});
|
|
443
715
|
|
|
444
716
|
this.ctx.onInputCallback(submission);
|
|
717
|
+
} else {
|
|
718
|
+
// No input waiter: the main loop is between turns (post-turn
|
|
719
|
+
// epilogue, retry backoff, or a scheduled continue) with the agent
|
|
720
|
+
// momentarily idle. The editor already cleared itself on Enter, so
|
|
721
|
+
// falling through here would silently swallow the message. Queue it
|
|
722
|
+
// as a steer instead: the idle drain in #queueSteer delivers it
|
|
723
|
+
// immediately when the session is resumable, and a retry/continue
|
|
724
|
+
// run picks it up at loop start otherwise.
|
|
725
|
+
this.ctx.editor.imageLinks = undefined;
|
|
726
|
+
const images = inputImages && inputImages.length > 0 ? [...inputImages] : undefined;
|
|
727
|
+
this.ctx.pendingImages = [];
|
|
728
|
+
this.ctx.pendingImageLinks = [];
|
|
729
|
+
try {
|
|
730
|
+
await this.ctx.withLocalSubmission(text, () => this.ctx.session.steer(text, images), {
|
|
731
|
+
imageCount: images?.length ?? 0,
|
|
732
|
+
});
|
|
733
|
+
} catch (error) {
|
|
734
|
+
// Don't lose the message: hand the text and images back to the
|
|
735
|
+
// editor so the user can retry (e.g. steer() rejecting an
|
|
736
|
+
// extension command).
|
|
737
|
+
this.ctx.editor.setText(text);
|
|
738
|
+
if (images && images.length > 0) {
|
|
739
|
+
this.ctx.pendingImages = [...images];
|
|
740
|
+
this.ctx.pendingImageLinks = inputImageLinks ? [...inputImageLinks] : images.map(() => undefined);
|
|
741
|
+
this.ctx.editor.imageLinks = this.ctx.pendingImageLinks;
|
|
742
|
+
}
|
|
743
|
+
this.ctx.showError(error instanceof Error ? error.message : String(error));
|
|
744
|
+
}
|
|
745
|
+
this.ctx.updatePendingMessagesDisplay();
|
|
746
|
+
this.ctx.ui.requestRender();
|
|
445
747
|
}
|
|
446
748
|
this.ctx.editor.addToHistory(text);
|
|
447
749
|
};
|
|
448
750
|
}
|
|
449
751
|
|
|
752
|
+
/** Submit editor text to the focused subagent session (chat-only focus policy). */
|
|
753
|
+
async #submitToFocusedSession(text: string, streamingBehavior: "steer" | "followUp"): Promise<void> {
|
|
754
|
+
const target = this.ctx.viewSession;
|
|
755
|
+
if (!text) {
|
|
756
|
+
if (target.isStreaming && target.queuedMessageCount > 0) {
|
|
757
|
+
const aborting = target.abort({ reason: USER_INTERRUPT_LABEL });
|
|
758
|
+
await aborting;
|
|
759
|
+
this.ctx.updatePendingMessagesDisplay();
|
|
760
|
+
this.ctx.ui.requestRender();
|
|
761
|
+
}
|
|
762
|
+
return;
|
|
763
|
+
}
|
|
764
|
+
if (text.startsWith("/") || text.startsWith("!") || text.startsWith("$")) {
|
|
765
|
+
this.ctx.showStatus("Commands run in the main session — press ←← to return first");
|
|
766
|
+
return; // editor text not cleared: Editor does not auto-clear on submit
|
|
767
|
+
}
|
|
768
|
+
const images = this.ctx.pendingImages.length > 0 ? [...this.ctx.pendingImages] : undefined;
|
|
769
|
+
this.ctx.editor.addToHistory(text);
|
|
770
|
+
this.ctx.editor.setText("");
|
|
771
|
+
this.ctx.editor.imageLinks = undefined;
|
|
772
|
+
this.ctx.pendingImages = [];
|
|
773
|
+
this.ctx.pendingImageLinks = [];
|
|
774
|
+
try {
|
|
775
|
+
// prompt() handles idle (new turn) and streaming (queues per streamingBehavior).
|
|
776
|
+
await this.ctx.withLocalSubmission(text, () => target.prompt(text, { streamingBehavior, images }), {
|
|
777
|
+
imageCount: images?.length ?? 0,
|
|
778
|
+
});
|
|
779
|
+
} catch (error) {
|
|
780
|
+
this.ctx.editor.setText(text); // hand the message back, mirroring the main submit error path
|
|
781
|
+
this.ctx.showError(error instanceof Error ? error.message : String(error));
|
|
782
|
+
}
|
|
783
|
+
this.ctx.updatePendingMessagesDisplay();
|
|
784
|
+
this.ctx.ui.requestRender();
|
|
785
|
+
}
|
|
786
|
+
|
|
450
787
|
handleCtrlC(): void {
|
|
451
788
|
const now = Date.now();
|
|
452
789
|
if (now - this.ctx.lastSigintTime < 500) {
|
|
@@ -455,6 +792,18 @@ export class InputController {
|
|
|
455
792
|
this.ctx.clearEditor();
|
|
456
793
|
this.ctx.lastSigintTime = now;
|
|
457
794
|
}
|
|
795
|
+
// Sync-flush the session JSONL so in-flight writes survive a hard exit.
|
|
796
|
+
// The TUI consumes Ctrl+C as a key event in raw mode, so postmortem's
|
|
797
|
+
// process-level SIGINT handler never fires. The second press still
|
|
798
|
+
// funnels through shutdown() which awaits its own async flush — the
|
|
799
|
+
// sync flush here is a superset that also covers the first-press case.
|
|
800
|
+
try {
|
|
801
|
+
this.ctx.sessionManager.flushSync();
|
|
802
|
+
} catch (err) {
|
|
803
|
+
logger.warn("session-manager sync flush on Ctrl+C failed", {
|
|
804
|
+
error: err instanceof Error ? err.message : String(err),
|
|
805
|
+
});
|
|
806
|
+
}
|
|
458
807
|
}
|
|
459
808
|
|
|
460
809
|
handleCtrlD(): void {
|
|
@@ -465,17 +814,44 @@ export class InputController {
|
|
|
465
814
|
}
|
|
466
815
|
|
|
467
816
|
handleCtrlZ(): void {
|
|
468
|
-
//
|
|
469
|
-
process.
|
|
817
|
+
// SIGTSTP is POSIX job-control: Windows has no equivalent and
|
|
818
|
+
// `process.kill(_, "SIGTSTP")` throws `TypeError: Unknown signal:
|
|
819
|
+
// SIGTSTP` there, taking the whole agent down via an uncaught
|
|
820
|
+
// exception (issue #2036). No-op on platforms that cannot suspend.
|
|
821
|
+
if (process.platform === "win32") {
|
|
822
|
+
this.ctx.showStatus("Suspend (Ctrl+Z) is not supported on this platform");
|
|
823
|
+
return;
|
|
824
|
+
}
|
|
825
|
+
|
|
826
|
+
// Capture the listener so we can detach it if the signal never
|
|
827
|
+
// fires; otherwise a failed suspend would leave a stale SIGCONT
|
|
828
|
+
// handler that fires on the next unrelated continue and tries to
|
|
829
|
+
// re-`start()` an already-running TUI.
|
|
830
|
+
const onResume = (): void => {
|
|
470
831
|
this.ctx.ui.start();
|
|
471
832
|
this.ctx.ui.requestRender(true);
|
|
472
|
-
}
|
|
833
|
+
};
|
|
834
|
+
process.once("SIGCONT", onResume);
|
|
473
835
|
|
|
474
|
-
// Stop the TUI (restore terminal to normal mode)
|
|
836
|
+
// Stop the TUI (restore terminal to normal mode) before sending the
|
|
837
|
+
// signal so the parent shell sees a sane terminal state.
|
|
475
838
|
this.ctx.ui.stop();
|
|
476
839
|
|
|
477
|
-
|
|
478
|
-
|
|
840
|
+
try {
|
|
841
|
+
// pid=0 → entire foreground process group; the shell receives
|
|
842
|
+
// SIGTSTP and parks the job.
|
|
843
|
+
process.kill(0, "SIGTSTP");
|
|
844
|
+
} catch (err) {
|
|
845
|
+
// Either the runtime refused the signal or the kernel rejected
|
|
846
|
+
// it (some sandboxes block sending to pid=0). Tear the resume
|
|
847
|
+
// hook down and bring the TUI back so the user is not stranded
|
|
848
|
+
// on a frozen prompt.
|
|
849
|
+
process.removeListener("SIGCONT", onResume);
|
|
850
|
+
this.ctx.ui.start();
|
|
851
|
+
this.ctx.ui.requestRender(true);
|
|
852
|
+
const reason = err instanceof Error ? err.message : String(err);
|
|
853
|
+
this.ctx.showError(`Failed to suspend: ${reason}`);
|
|
854
|
+
}
|
|
479
855
|
}
|
|
480
856
|
|
|
481
857
|
handleDequeue(): void {
|
|
@@ -524,15 +900,6 @@ export class InputController {
|
|
|
524
900
|
args: args || undefined,
|
|
525
901
|
lineCount: body ? body.split("\n").length : 0,
|
|
526
902
|
};
|
|
527
|
-
// When the agent is streaming, register the compact slash-form text as
|
|
528
|
-
// the pending-display twin BEFORE dispatching the CustomMessage. The
|
|
529
|
-
// returned tag is embedded in details so AgentSession.#handleAgentEvent
|
|
530
|
-
// can remove the matching display entry when the agent consumes this
|
|
531
|
-
// message (mirrors the user-message dequeue path).
|
|
532
|
-
if (this.ctx.session.isStreaming) {
|
|
533
|
-
const tag = this.ctx.session.enqueueCustomMessageDisplay(text, streamingBehavior);
|
|
534
|
-
details.__pendingDisplayTag = tag;
|
|
535
|
-
}
|
|
536
903
|
await this.ctx.session.promptCustomMessage(
|
|
537
904
|
{
|
|
538
905
|
customType: SKILL_PROMPT_MESSAGE_TYPE,
|
|
@@ -541,7 +908,7 @@ export class InputController {
|
|
|
541
908
|
details,
|
|
542
909
|
attribution: "user",
|
|
543
910
|
},
|
|
544
|
-
{ streamingBehavior },
|
|
911
|
+
{ streamingBehavior, queueChipText: text },
|
|
545
912
|
);
|
|
546
913
|
if (this.ctx.session.isStreaming) {
|
|
547
914
|
this.ctx.updatePendingMessagesDisplay();
|
|
@@ -555,9 +922,15 @@ export class InputController {
|
|
|
555
922
|
|
|
556
923
|
/** Send editor text as a follow-up message (queued behind current stream). */
|
|
557
924
|
async handleFollowUp(): Promise<void> {
|
|
558
|
-
|
|
925
|
+
let text = this.ctx.editor.getText().trim();
|
|
559
926
|
if (!text) return;
|
|
560
927
|
|
|
928
|
+
// Focused subagent session: follow-ups go to it; non-chat input is gated.
|
|
929
|
+
if (this.ctx.focusedAgentId) {
|
|
930
|
+
await this.#submitToFocusedSession(text, "followUp");
|
|
931
|
+
return;
|
|
932
|
+
}
|
|
933
|
+
|
|
561
934
|
// Compaction first: while compacting, free text gets queued via
|
|
562
935
|
// `queueCompactionMessage`, and `/skill:*` rides the same queue so a
|
|
563
936
|
// skill typed during compaction is not lost or short-circuited through
|
|
@@ -565,10 +938,21 @@ export class InputController {
|
|
|
565
938
|
// the queued entry is later re-parsed into a skill invocation is a
|
|
566
939
|
// separate concern owned by the compaction-resume path.
|
|
567
940
|
if (this.ctx.session.isCompacting) {
|
|
568
|
-
this.ctx.
|
|
941
|
+
const images = this.ctx.pendingImages.length > 0 ? [...this.ctx.pendingImages] : undefined;
|
|
942
|
+
this.ctx.queueCompactionMessage(text, "followUp", images);
|
|
569
943
|
return;
|
|
570
944
|
}
|
|
571
945
|
|
|
946
|
+
const slashResult = await executeBuiltinSlashCommand(text, {
|
|
947
|
+
ctx: this.ctx,
|
|
948
|
+
});
|
|
949
|
+
if (slashResult === true) {
|
|
950
|
+
return;
|
|
951
|
+
}
|
|
952
|
+
if (typeof slashResult === "string") {
|
|
953
|
+
text = slashResult;
|
|
954
|
+
}
|
|
955
|
+
|
|
572
956
|
// Skill commands invoke through the custom-message path regardless of
|
|
573
957
|
// which keybinding submitted them. Enter routes them as `steer`;
|
|
574
958
|
// Ctrl+Enter (this handler) routes them as `followUp`.
|
|
@@ -576,11 +960,20 @@ export class InputController {
|
|
|
576
960
|
return;
|
|
577
961
|
}
|
|
578
962
|
|
|
963
|
+
// Forward any pending clipboard-pasted images alongside the queued text;
|
|
964
|
+
// otherwise the follow-up would drop the image (mirrors the Enter/steer path).
|
|
965
|
+
const images = this.ctx.pendingImages.length > 0 ? [...this.ctx.pendingImages] : undefined;
|
|
966
|
+
|
|
579
967
|
if (this.ctx.session.isStreaming) {
|
|
580
968
|
this.ctx.editor.addToHistory(text);
|
|
581
969
|
this.ctx.editor.setText("");
|
|
582
|
-
|
|
583
|
-
|
|
970
|
+
this.ctx.editor.imageLinks = undefined;
|
|
971
|
+
this.ctx.pendingImages = [];
|
|
972
|
+
this.ctx.pendingImageLinks = [];
|
|
973
|
+
await this.ctx.withLocalSubmission(
|
|
974
|
+
text,
|
|
975
|
+
() => this.ctx.session.prompt(text, { streamingBehavior: "followUp", images }),
|
|
976
|
+
{ imageCount: images?.length ?? 0 },
|
|
584
977
|
);
|
|
585
978
|
this.ctx.updatePendingMessagesDisplay();
|
|
586
979
|
this.ctx.ui.requestRender();
|
|
@@ -590,148 +983,260 @@ export class InputController {
|
|
|
590
983
|
// Not streaming — just submit normally
|
|
591
984
|
this.ctx.editor.addToHistory(text);
|
|
592
985
|
this.ctx.editor.setText("");
|
|
593
|
-
|
|
986
|
+
this.ctx.editor.imageLinks = undefined;
|
|
987
|
+
this.ctx.pendingImages = [];
|
|
988
|
+
this.ctx.pendingImageLinks = [];
|
|
989
|
+
await this.ctx.withLocalSubmission(text, () => this.ctx.session.prompt(text, { images }), {
|
|
990
|
+
imageCount: images?.length ?? 0,
|
|
991
|
+
});
|
|
594
992
|
}
|
|
595
993
|
|
|
596
994
|
restoreQueuedMessagesToEditor(options?: { abort?: boolean; currentText?: string }): number {
|
|
597
995
|
this.ctx.locallySubmittedUserSignatures.clear();
|
|
598
996
|
const { steering, followUp } = this.ctx.session.clearQueue();
|
|
599
|
-
|
|
997
|
+
// Messages typed while compacting live in `compactionQueuedMessages`, not the
|
|
998
|
+
// agent queue `clearQueue()` drains — but the pending bar shows the same
|
|
999
|
+
// "Alt+Up to edit" hint for them (ui-helpers `updatePendingMessagesDisplay`).
|
|
1000
|
+
// Drain them here too so the dequeue restores every message the hint
|
|
1001
|
+
// advertises; otherwise a skill/text queued during compaction is stranded and
|
|
1002
|
+
// Alt+Up reports "No queued messages to restore".
|
|
1003
|
+
const compactionQueued = this.ctx.compactionQueuedMessages;
|
|
1004
|
+
this.ctx.compactionQueuedMessages = [];
|
|
1005
|
+
const allQueued = [
|
|
1006
|
+
...steering,
|
|
1007
|
+
...compactionQueued.filter(e => e.mode === "steer").map(e => ({ text: e.text, images: e.images })),
|
|
1008
|
+
...followUp,
|
|
1009
|
+
...compactionQueued.filter(e => e.mode === "followUp").map(e => ({ text: e.text, images: e.images })),
|
|
1010
|
+
];
|
|
600
1011
|
if (allQueued.length === 0) {
|
|
601
1012
|
this.ctx.updatePendingMessagesDisplay();
|
|
602
1013
|
if (options?.abort) {
|
|
603
|
-
this.ctx.session.abort();
|
|
1014
|
+
void this.ctx.session.abort({ reason: USER_INTERRUPT_LABEL });
|
|
604
1015
|
}
|
|
605
1016
|
return 0;
|
|
606
1017
|
}
|
|
607
|
-
|
|
1018
|
+
// Image markers are positional: `[Image #N]` ↔ `pendingImages[N-1]`. Each
|
|
1019
|
+
// queued message numbered its markers against its own local image list
|
|
1020
|
+
// (1..K). Because we prepend the queued text but append the queued images
|
|
1021
|
+
// to `pendingImages`, any existing draft images (M of them) — plus images
|
|
1022
|
+
// already pulled in by earlier queued messages — shift the slot index that
|
|
1023
|
+
// every marker must point to. Bumping each message's markers by the
|
|
1024
|
+
// running offset keeps the merged text aligned with the merged
|
|
1025
|
+
// `pendingImages` order; draft markers stay valid because draft images
|
|
1026
|
+
// keep their original positions.
|
|
1027
|
+
const queuedImages = allQueued.flatMap(e => e.images ?? []);
|
|
1028
|
+
let queuedText: string;
|
|
1029
|
+
if (queuedImages.length > 0) {
|
|
1030
|
+
const parts: string[] = [];
|
|
1031
|
+
let imageOffset = this.ctx.pendingImages.length;
|
|
1032
|
+
for (const entry of allQueued) {
|
|
1033
|
+
parts.push(shiftImageMarkers(entry.text, imageOffset));
|
|
1034
|
+
if (entry.images && entry.images.length > 0) imageOffset += entry.images.length;
|
|
1035
|
+
}
|
|
1036
|
+
queuedText = parts.join("\n\n");
|
|
1037
|
+
} else {
|
|
1038
|
+
queuedText = allQueued.map(e => e.text).join("\n\n");
|
|
1039
|
+
}
|
|
608
1040
|
const currentText = options?.currentText ?? this.ctx.editor.getText();
|
|
609
1041
|
const combinedText = [queuedText, currentText].filter(t => t.trim()).join("\n\n");
|
|
610
1042
|
this.ctx.editor.setText(combinedText);
|
|
1043
|
+
// Hand queued images back to the pending-image buffer (links are
|
|
1044
|
+
// re-materialized lazily; the restored text already carries the
|
|
1045
|
+
// renumbered `[Image #N, WxH]` markers).
|
|
1046
|
+
if (queuedImages.length > 0) {
|
|
1047
|
+
this.ctx.pendingImages.push(...queuedImages);
|
|
1048
|
+
this.ctx.pendingImageLinks.push(...queuedImages.map(() => undefined));
|
|
1049
|
+
this.ctx.editor.imageLinks = this.ctx.pendingImageLinks;
|
|
1050
|
+
}
|
|
611
1051
|
this.ctx.updatePendingMessagesDisplay();
|
|
612
1052
|
if (options?.abort) {
|
|
613
|
-
this.ctx.session.abort();
|
|
1053
|
+
void this.ctx.session.abort({ reason: USER_INTERRUPT_LABEL });
|
|
614
1054
|
}
|
|
615
1055
|
return allQueued.length;
|
|
616
1056
|
}
|
|
617
1057
|
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
this.ctx.
|
|
639
|
-
this
|
|
1058
|
+
async #insertPendingImage(imageData: ImageContent): Promise<void> {
|
|
1059
|
+
const imageLink = (
|
|
1060
|
+
await materializeImageReferenceLinks(
|
|
1061
|
+
[
|
|
1062
|
+
{
|
|
1063
|
+
type: "image",
|
|
1064
|
+
data: imageData.data,
|
|
1065
|
+
mimeType: imageData.mimeType,
|
|
1066
|
+
},
|
|
1067
|
+
],
|
|
1068
|
+
this.ctx.sessionManager.putBlob.bind(this.ctx.sessionManager),
|
|
1069
|
+
)
|
|
1070
|
+
)?.[0];
|
|
1071
|
+
this.ctx.pendingImages.push({
|
|
1072
|
+
type: "image",
|
|
1073
|
+
data: imageData.data,
|
|
1074
|
+
mimeType: imageData.mimeType,
|
|
1075
|
+
});
|
|
1076
|
+
this.ctx.pendingImageLinks.push(imageLink);
|
|
1077
|
+
this.ctx.editor.imageLinks = this.ctx.pendingImageLinks;
|
|
1078
|
+
const imageNum = this.ctx.pendingImages.length;
|
|
1079
|
+
const dims = await this.#imageDimensions(imageData);
|
|
1080
|
+
const label = dims ? `[Image #${imageNum}, ${dims.width}x${dims.height}]` : `[Image #${imageNum}]`;
|
|
1081
|
+
this.ctx.editor.insertText(`${label} `);
|
|
1082
|
+
this.ctx.ui.requestRender();
|
|
1083
|
+
}
|
|
640
1084
|
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
if (this.ctx.retryLoader) {
|
|
650
|
-
this.ctx.retryLoader.stop();
|
|
651
|
-
this.ctx.retryLoader = undefined;
|
|
1085
|
+
/** Probe pixel dimensions for the marker label (`[Image #N, WxH]`). Returns undefined when the
|
|
1086
|
+
* header can't be decoded, so the caller falls back to a bare `[Image #N]`. */
|
|
1087
|
+
async #imageDimensions(image: ImageContent): Promise<{ width: number; height: number } | undefined> {
|
|
1088
|
+
try {
|
|
1089
|
+
const { width, height } = await new Bun.Image(Buffer.from(image.data, "base64")).metadata();
|
|
1090
|
+
if (width && height) return { width, height };
|
|
1091
|
+
} catch {
|
|
1092
|
+
// Unknown/corrupt header — fall back to a bare label.
|
|
652
1093
|
}
|
|
653
|
-
|
|
654
|
-
|
|
1094
|
+
return undefined;
|
|
1095
|
+
}
|
|
655
1096
|
|
|
656
|
-
|
|
657
|
-
|
|
1097
|
+
async #normalizeAndInsertPastedImage(image: ImageContent, unsupportedMessage: string): Promise<boolean> {
|
|
1098
|
+
let imageData = await ensureSupportedImageInput(image);
|
|
1099
|
+
if (!imageData) {
|
|
1100
|
+
this.ctx.showStatus(unsupportedMessage);
|
|
1101
|
+
return false;
|
|
658
1102
|
}
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
1103
|
+
if (settings.get("images.autoResize")) {
|
|
1104
|
+
try {
|
|
1105
|
+
const resized = await resizeImage({
|
|
1106
|
+
type: "image",
|
|
1107
|
+
data: imageData.data,
|
|
1108
|
+
mimeType: imageData.mimeType,
|
|
1109
|
+
});
|
|
1110
|
+
imageData = { type: "image", data: resized.data, mimeType: resized.mimeType };
|
|
1111
|
+
} catch {
|
|
1112
|
+
// Keep the normalized image when resize fails.
|
|
1113
|
+
}
|
|
667
1114
|
}
|
|
1115
|
+
await this.#insertPendingImage(imageData);
|
|
1116
|
+
return true;
|
|
1117
|
+
}
|
|
668
1118
|
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
1119
|
+
/**
|
|
1120
|
+
* Win+Shift+S on Windows 11 leaves the screenshot bitmap on the clipboard
|
|
1121
|
+
* while the terminal pastes a transient packaged-app TempState path
|
|
1122
|
+
* (…\MicrosoftWindows.Client.Core_*\TempState\…) that is already gone — or
|
|
1123
|
+
* never materialized — by the time we read it. Whenever a pasted image path
|
|
1124
|
+
* can't be turned into an image locally, those clipboard bytes are the real
|
|
1125
|
+
* payload, so prefer them before degrading to a text paste.
|
|
1126
|
+
*
|
|
1127
|
+
* Skipped over SSH: the clipboard read would hit the remote host, not the
|
|
1128
|
+
* terminal that holds the screenshot. Returns true when the clipboard owned
|
|
1129
|
+
* the outcome (image attached, or an unsupported-format status surfaced), so
|
|
1130
|
+
* the caller stops without emitting its own degraded diagnostic.
|
|
1131
|
+
*/
|
|
1132
|
+
async #tryPasteClipboardImage(): Promise<boolean> {
|
|
1133
|
+
const env = process.env;
|
|
1134
|
+
if (env.SSH_CONNECTION || env.SSH_TTY || env.SSH_CLIENT) return false;
|
|
1135
|
+
try {
|
|
1136
|
+
const image = await this.clipboard.readImage();
|
|
1137
|
+
if (!image) return false;
|
|
1138
|
+
await this.#normalizeAndInsertPastedImage(
|
|
1139
|
+
{ type: "image", data: image.data.toBase64(), mimeType: image.mimeType },
|
|
1140
|
+
`Unsupported clipboard image format: ${image.mimeType}`,
|
|
1141
|
+
);
|
|
1142
|
+
return true;
|
|
1143
|
+
} catch {
|
|
1144
|
+
return false;
|
|
674
1145
|
}
|
|
1146
|
+
}
|
|
675
1147
|
|
|
676
|
-
|
|
1148
|
+
async handleImagePathPaste(path: string): Promise<void> {
|
|
1149
|
+
try {
|
|
1150
|
+
const image = await loadImageInput({
|
|
1151
|
+
path,
|
|
1152
|
+
cwd: this.ctx.sessionManager.getCwd(),
|
|
1153
|
+
autoResize: false,
|
|
1154
|
+
});
|
|
1155
|
+
if (!image) {
|
|
1156
|
+
// Path resolved but is not a readable image (e.g. a zero-byte or
|
|
1157
|
+
// locked transient screenshot file). Prefer the clipboard bytes.
|
|
1158
|
+
if (await this.#tryPasteClipboardImage()) return;
|
|
1159
|
+
this.ctx.editor.pasteText(path);
|
|
1160
|
+
this.ctx.ui.requestRender();
|
|
1161
|
+
this.ctx.showStatus("Pasted path is not a supported image");
|
|
1162
|
+
return;
|
|
1163
|
+
}
|
|
1164
|
+
await this.#normalizeAndInsertPastedImage(
|
|
1165
|
+
{ type: "image", data: image.data, mimeType: image.mimeType },
|
|
1166
|
+
`Unsupported pasted image format: ${image.mimeType}`,
|
|
1167
|
+
);
|
|
1168
|
+
} catch (error) {
|
|
1169
|
+
if (error instanceof ImageInputTooLargeError) {
|
|
1170
|
+
this.ctx.editor.pasteText(path);
|
|
1171
|
+
this.ctx.ui.requestRender();
|
|
1172
|
+
this.ctx.showStatus(error.message);
|
|
1173
|
+
return;
|
|
1174
|
+
}
|
|
1175
|
+
if (isEnoent(error)) {
|
|
1176
|
+
// #2375: the bracketed paste forwarded by a local terminal carries a
|
|
1177
|
+
// path on the *local* filesystem. The bytes may still be on the
|
|
1178
|
+
// clipboard (Win+Shift+S), so try those before giving up.
|
|
1179
|
+
if (await this.#tryPasteClipboardImage()) return;
|
|
1180
|
+
// Over SSH the clipboard lives on the remote host, so the path is
|
|
1181
|
+
// genuinely unreachable; pasting it as text would look like the
|
|
1182
|
+
// image was attached when nothing was sent. Surface an SSH-aware
|
|
1183
|
+
// diagnostic instead. The pasted path is untrusted terminal input —
|
|
1184
|
+
// strip control/ANSI/newlines, collapse home to `~`, and bound the
|
|
1185
|
+
// displayed length before splicing it into the status string.
|
|
1186
|
+
const env = process.env;
|
|
1187
|
+
const overSsh = Boolean(env.SSH_CONNECTION || env.SSH_TTY || env.SSH_CLIENT);
|
|
1188
|
+
const displayPath = truncateToWidth(
|
|
1189
|
+
shortenPath(
|
|
1190
|
+
sanitizeText(path)
|
|
1191
|
+
.replace(/[\r\n\t]+/g, " ")
|
|
1192
|
+
.trim(),
|
|
1193
|
+
),
|
|
1194
|
+
TRUNCATE_LENGTHS.CONTENT,
|
|
1195
|
+
);
|
|
1196
|
+
this.ctx.showStatus(
|
|
1197
|
+
overSsh
|
|
1198
|
+
? `Image not found at ${displayPath}. Over SSH this path is local to your terminal — paste the image directly (clipboard image-paste shortcut) to send its bytes.`
|
|
1199
|
+
: `Image not found at ${displayPath}`,
|
|
1200
|
+
);
|
|
1201
|
+
return;
|
|
1202
|
+
}
|
|
1203
|
+
if (await this.#tryPasteClipboardImage()) return;
|
|
1204
|
+
this.ctx.editor.pasteText(path);
|
|
1205
|
+
this.ctx.ui.requestRender();
|
|
1206
|
+
this.ctx.showStatus("Failed to read pasted image path");
|
|
1207
|
+
}
|
|
677
1208
|
}
|
|
678
1209
|
|
|
679
1210
|
async handleImagePaste(): Promise<boolean> {
|
|
680
1211
|
try {
|
|
681
|
-
const image = await
|
|
682
|
-
if (image) {
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
if (!
|
|
690
|
-
this.ctx.showStatus(
|
|
1212
|
+
const image = await this.clipboard.readImage();
|
|
1213
|
+
if (!image) {
|
|
1214
|
+
// Smart paste (#1628): no image on the clipboard — fall back to
|
|
1215
|
+
// pasting its text so the same chord covers both payload kinds.
|
|
1216
|
+
// Hosts that pre-empt the terminal's own paste (VS Code's
|
|
1217
|
+
// integrated terminal, Win+V clipboard history) deliver only
|
|
1218
|
+
// this keypress, so a miss here must not dead-end.
|
|
1219
|
+
const text = await this.clipboard.readText();
|
|
1220
|
+
if (!text) {
|
|
1221
|
+
this.ctx.showStatus("Clipboard is empty");
|
|
691
1222
|
return false;
|
|
692
1223
|
}
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
mimeType: imageData.mimeType,
|
|
699
|
-
});
|
|
700
|
-
imageData = { type: "image", data: resized.data, mimeType: resized.mimeType };
|
|
701
|
-
} catch {
|
|
702
|
-
// Keep the normalized image when resize fails.
|
|
703
|
-
}
|
|
704
|
-
}
|
|
705
|
-
|
|
706
|
-
const imageLink = (
|
|
707
|
-
await materializeImageReferenceLinks(
|
|
708
|
-
[
|
|
709
|
-
{
|
|
710
|
-
type: "image",
|
|
711
|
-
data: imageData.data,
|
|
712
|
-
mimeType: imageData.mimeType,
|
|
713
|
-
},
|
|
714
|
-
],
|
|
715
|
-
this.ctx.sessionManager.putBlob.bind(this.ctx.sessionManager),
|
|
716
|
-
)
|
|
717
|
-
)?.[0];
|
|
718
|
-
this.ctx.pendingImages.push({
|
|
719
|
-
type: "image",
|
|
720
|
-
data: imageData.data,
|
|
721
|
-
mimeType: imageData.mimeType,
|
|
722
|
-
});
|
|
723
|
-
this.ctx.pendingImageLinks.push(imageLink);
|
|
724
|
-
this.ctx.editor.imageLinks = this.ctx.pendingImageLinks;
|
|
725
|
-
// Insert placeholder at cursor like Claude does
|
|
726
|
-
const imageNum = this.ctx.pendingImages.length;
|
|
727
|
-
const placeholder = `[Image #${imageNum}]`;
|
|
728
|
-
this.ctx.editor.insertText(`${placeholder} `);
|
|
1224
|
+
// Route to the focused component when it accepts pastes (modal
|
|
1225
|
+
// Input prompts), matching the enhanced-paste text path (#2127).
|
|
1226
|
+
const focused = this.ctx.ui.getFocused();
|
|
1227
|
+
const target = focused && focused !== this.ctx.editor && hasPasteText(focused) ? focused : this.ctx.editor;
|
|
1228
|
+
target.pasteText(text);
|
|
729
1229
|
this.ctx.ui.requestRender();
|
|
730
1230
|
return true;
|
|
731
1231
|
}
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
1232
|
+
return await this.#normalizeAndInsertPastedImage(
|
|
1233
|
+
{
|
|
1234
|
+
type: "image",
|
|
1235
|
+
data: image.data.toBase64(),
|
|
1236
|
+
mimeType: image.mimeType,
|
|
1237
|
+
},
|
|
1238
|
+
`Unsupported clipboard image format: ${image.mimeType}`,
|
|
1239
|
+
);
|
|
735
1240
|
} catch {
|
|
736
1241
|
this.ctx.showStatus("Failed to read clipboard");
|
|
737
1242
|
return false;
|
|
@@ -740,10 +1245,11 @@ export class InputController {
|
|
|
740
1245
|
|
|
741
1246
|
async handleClipboardTextRawPaste(): Promise<void> {
|
|
742
1247
|
try {
|
|
743
|
-
const text = await
|
|
1248
|
+
const text = await this.clipboard.readText();
|
|
744
1249
|
if (text) {
|
|
745
1250
|
this.ctx.editor.insertText(text);
|
|
746
1251
|
this.ctx.ui.requestRender();
|
|
1252
|
+
} else {
|
|
747
1253
|
this.ctx.showStatus("No text in clipboard to paste raw");
|
|
748
1254
|
}
|
|
749
1255
|
} catch {
|
|
@@ -751,6 +1257,97 @@ export class InputController {
|
|
|
751
1257
|
}
|
|
752
1258
|
}
|
|
753
1259
|
|
|
1260
|
+
/**
|
|
1261
|
+
* Editor `onLargePaste` hook: gate a marker-sized paste behind the large-paste menu. Returns
|
|
1262
|
+
* `true` to intercept (the editor skips its default `[Paste]` marker) once the paste reaches the
|
|
1263
|
+
* configured `paste.largeMenuThreshold` line count; otherwise `false` for default collapse-to-marker
|
|
1264
|
+
* behavior. The async menu is fired and forgotten — the editor only needs the synchronous verdict.
|
|
1265
|
+
*/
|
|
1266
|
+
handleLargePaste(text: string, lineCount: number): boolean {
|
|
1267
|
+
const threshold = this.ctx.settings.get("paste.largeMenuThreshold");
|
|
1268
|
+
if (!(threshold > 0) || lineCount < threshold) return false;
|
|
1269
|
+
void this.presentLargePasteMenu(text, lineCount);
|
|
1270
|
+
return true;
|
|
1271
|
+
}
|
|
1272
|
+
|
|
1273
|
+
/**
|
|
1274
|
+
* Present the large-paste menu and apply the chosen action: wrap in a code block or in XML tags
|
|
1275
|
+
* (both collapse to a `[Paste]` marker that expands on submit), or save the text to a file and
|
|
1276
|
+
* reference its path so the agent can `read` it on demand. Cancelling (Esc) falls back to the
|
|
1277
|
+
* default inline paste marker, so the pasted content is never lost.
|
|
1278
|
+
*/
|
|
1279
|
+
async presentLargePasteMenu(text: string, lineCount: number): Promise<void> {
|
|
1280
|
+
const CODE_BLOCK = "Wrap in a code block";
|
|
1281
|
+
const XML = "Wrap in XML tags";
|
|
1282
|
+
const FILE = "Attach as a file";
|
|
1283
|
+
|
|
1284
|
+
let choice: string | undefined;
|
|
1285
|
+
try {
|
|
1286
|
+
choice = await this.ctx.showHookSelector(
|
|
1287
|
+
`Pasted ${lineCount} lines`,
|
|
1288
|
+
[
|
|
1289
|
+
{ label: CODE_BLOCK, description: "Fence the text in a ``` block, collapsed to a marker" },
|
|
1290
|
+
{ label: XML, description: "Wrap the text in <pasted_text> tags, collapsed to a marker" },
|
|
1291
|
+
{ label: FILE, description: "Save the text to a file and reference its path" },
|
|
1292
|
+
],
|
|
1293
|
+
{ helpText: "Esc to paste inline" },
|
|
1294
|
+
);
|
|
1295
|
+
} catch (error) {
|
|
1296
|
+
logger.warn("large-paste menu failed", { error: error instanceof Error ? error.message : String(error) });
|
|
1297
|
+
choice = undefined;
|
|
1298
|
+
}
|
|
1299
|
+
|
|
1300
|
+
switch (choice) {
|
|
1301
|
+
case CODE_BLOCK:
|
|
1302
|
+
this.ctx.editor.insertPaste(wrapPasteInCodeBlock(text));
|
|
1303
|
+
break;
|
|
1304
|
+
case XML:
|
|
1305
|
+
this.ctx.editor.insertPaste(wrapPasteInXml(text));
|
|
1306
|
+
break;
|
|
1307
|
+
case FILE:
|
|
1308
|
+
await this.#attachPasteAsFile(text, lineCount);
|
|
1309
|
+
break;
|
|
1310
|
+
default:
|
|
1311
|
+
// Esc / cancel: keep the original behavior — collapse to an inline paste marker.
|
|
1312
|
+
this.ctx.editor.insertPaste(text);
|
|
1313
|
+
break;
|
|
1314
|
+
}
|
|
1315
|
+
this.ctx.ui.requestRender();
|
|
1316
|
+
}
|
|
1317
|
+
|
|
1318
|
+
/**
|
|
1319
|
+
* Save a large paste to the session's `local://` store and insert a clean `local://attachment-N`
|
|
1320
|
+
* reference into the editor so the agent can `read` it on demand — instead of inlining the text or
|
|
1321
|
+
* leaking a raw temp path. Falls back to an inline paste marker when the write fails, so the
|
|
1322
|
+
* content is never lost.
|
|
1323
|
+
*/
|
|
1324
|
+
async #attachPasteAsFile(text: string, lineCount: number): Promise<void> {
|
|
1325
|
+
try {
|
|
1326
|
+
// Mirror the exact mapping the read tool's local:// resolver uses so a later
|
|
1327
|
+
// `read local://attachment-N` lands on the file written here.
|
|
1328
|
+
const localRoot = resolveLocalRoot({
|
|
1329
|
+
getArtifactsDir: () => this.ctx.sessionManager.getArtifactsDir(),
|
|
1330
|
+
getSessionId: () => this.ctx.sessionManager.getSessionId(),
|
|
1331
|
+
});
|
|
1332
|
+
let name: string;
|
|
1333
|
+
let filePath: string;
|
|
1334
|
+
do {
|
|
1335
|
+
this.#attachmentCounter++;
|
|
1336
|
+
name = `attachment-${this.#attachmentCounter}`;
|
|
1337
|
+
filePath = path.join(localRoot, name);
|
|
1338
|
+
} while (await Bun.file(filePath).exists());
|
|
1339
|
+
await Bun.write(filePath, text);
|
|
1340
|
+
this.ctx.editor.insertText(`local://${name} `);
|
|
1341
|
+
this.ctx.showStatus(`Saved ${lineCount} pasted lines to local://${name}`);
|
|
1342
|
+
} catch (error) {
|
|
1343
|
+
logger.warn("failed to save large paste to file", {
|
|
1344
|
+
error: error instanceof Error ? error.message : String(error),
|
|
1345
|
+
});
|
|
1346
|
+
this.ctx.editor.insertPaste(text);
|
|
1347
|
+
this.ctx.showError("Failed to save paste to a file — pasted inline instead");
|
|
1348
|
+
}
|
|
1349
|
+
}
|
|
1350
|
+
|
|
754
1351
|
createAutocompleteProvider(commands: SlashCommand[], basePath: string): AutocompleteProvider {
|
|
755
1352
|
return createPromptActionAutocompleteProvider({
|
|
756
1353
|
commands,
|
|
@@ -802,6 +1399,10 @@ export class InputController {
|
|
|
802
1399
|
}
|
|
803
1400
|
|
|
804
1401
|
cycleThinkingLevel(): void {
|
|
1402
|
+
if (this.ctx.focusedAgentId) {
|
|
1403
|
+
this.ctx.showStatus("Model/thinking apply to the main session — press ←← to return first");
|
|
1404
|
+
return;
|
|
1405
|
+
}
|
|
805
1406
|
const newLevel = this.ctx.session.cycleThinkingLevel();
|
|
806
1407
|
if (newLevel === undefined) {
|
|
807
1408
|
this.ctx.showStatus("Current model does not support thinking");
|
|
@@ -812,6 +1413,10 @@ export class InputController {
|
|
|
812
1413
|
}
|
|
813
1414
|
|
|
814
1415
|
async cycleRoleModel(direction: "forward" | "backward" = "forward"): Promise<void> {
|
|
1416
|
+
if (this.ctx.focusedAgentId) {
|
|
1417
|
+
this.ctx.showStatus("Model/thinking apply to the main session — press ←← to return first");
|
|
1418
|
+
return;
|
|
1419
|
+
}
|
|
815
1420
|
try {
|
|
816
1421
|
const cycleOrder = settings.get("cycleOrder");
|
|
817
1422
|
const result = await this.ctx.session.cycleRoleModels(cycleOrder, direction);
|
|
@@ -824,12 +1429,14 @@ export class InputController {
|
|
|
824
1429
|
this.ctx.updateEditorBorderColor();
|
|
825
1430
|
// The status line already reports the resolved model + thinking level, so
|
|
826
1431
|
// the cycle status is just a status-line-style chip track (active role
|
|
827
|
-
// filled), matching the plan-approval model slider.
|
|
1432
|
+
// filled), matching the plan-approval model slider. It renders into its
|
|
1433
|
+
// own anchored container above the editor (cleared+rebuilt each cycle),
|
|
1434
|
+
// so it updates in place instead of stacking duplicates in the scrollback.
|
|
828
1435
|
const track = renderSegmentTrack(
|
|
829
|
-
cycleOrder.map(role => ({ label: role
|
|
1436
|
+
cycleOrder.map(role => ({ label: role })),
|
|
830
1437
|
cycleOrder.indexOf(result.role),
|
|
831
1438
|
);
|
|
832
|
-
this.ctx.
|
|
1439
|
+
this.ctx.showModelCycleTrack(track);
|
|
833
1440
|
} catch (error) {
|
|
834
1441
|
this.ctx.showError(error instanceof Error ? error.message : String(error));
|
|
835
1442
|
}
|
|
@@ -846,23 +1453,32 @@ export class InputController {
|
|
|
846
1453
|
child.setExpanded(expanded);
|
|
847
1454
|
}
|
|
848
1455
|
}
|
|
849
|
-
|
|
1456
|
+
// Toggling expansion mutates every block, but on ED3-risk terminals the
|
|
1457
|
+
// transcript freezes a snapshot of each block once it scrolls past the live
|
|
1458
|
+
// region (committed native scrollback is immutable there). A plain repaint
|
|
1459
|
+
// replays those stale snapshots, so the toggle appears to do nothing above
|
|
1460
|
+
// the live block. resetDisplay() invalidates the snapshots and forces a
|
|
1461
|
+
// full clear + replay — the keyboard-accessible resize-reset equivalent —
|
|
1462
|
+
// which is the only path that re-emits the whole transcript at its new
|
|
1463
|
+
// heights.
|
|
1464
|
+
this.ctx.ui.resetDisplay();
|
|
850
1465
|
}
|
|
851
1466
|
|
|
852
1467
|
toggleThinkingBlockVisibility(): void {
|
|
853
1468
|
this.ctx.hideThinkingBlock = !this.ctx.hideThinkingBlock;
|
|
854
|
-
settings.set("hideThinkingBlock", this.ctx.hideThinkingBlock);
|
|
1469
|
+
this.ctx.settings.set("hideThinkingBlock", this.ctx.hideThinkingBlock);
|
|
855
1470
|
this.ctx.session.agent.hideThinkingSummary = this.ctx.hideThinkingBlock;
|
|
856
1471
|
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
1472
|
+
for (const child of this.ctx.chatContainer.children) {
|
|
1473
|
+
if (child instanceof AssistantMessageComponent) {
|
|
1474
|
+
child.setHideThinkingBlock(this.ctx.hideThinkingBlock);
|
|
1475
|
+
child.invalidate();
|
|
1476
|
+
}
|
|
1477
|
+
}
|
|
860
1478
|
|
|
861
|
-
// If streaming, re-add the streaming component with updated visibility and re-render
|
|
862
1479
|
if (this.ctx.streamingComponent && this.ctx.streamingMessage) {
|
|
863
1480
|
this.ctx.streamingComponent.setHideThinkingBlock(this.ctx.hideThinkingBlock);
|
|
864
1481
|
this.ctx.streamingComponent.updateContent(this.ctx.streamingMessage);
|
|
865
|
-
this.ctx.chatContainer.addChild(this.ctx.streamingComponent);
|
|
866
1482
|
}
|
|
867
1483
|
|
|
868
1484
|
this.ctx.showStatus(`Thinking blocks: ${this.ctx.hideThinkingBlock ? "hidden" : "visible"}`);
|