@oh-my-pi/pi-coding-agent 15.10.10 → 15.10.12
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 +142 -7
- package/dist/cli.js +23108 -0
- package/dist/tokenizers.linux-x64-gnu-xcjh3jwk.node +0 -0
- package/dist/types/async/job-manager.d.ts +18 -0
- package/dist/types/cli/args.d.ts +2 -1
- package/dist/types/cli/dry-balance-cli.d.ts +1 -1
- package/dist/types/cli/gallery-cli.d.ts +1 -1
- package/dist/types/cli/gallery-fixtures/types.d.ts +1 -1
- package/dist/types/cli/usage-cli.d.ts +72 -0
- package/dist/types/cli-commands.d.ts +12 -0
- package/dist/types/commands/launch.d.ts +5 -1
- package/dist/types/commands/read.d.ts +1 -1
- package/dist/types/commands/usage.d.ts +25 -0
- package/dist/types/config/api-key-resolver.d.ts +3 -0
- package/dist/types/config/append-only-context-mode.d.ts +2 -1
- package/dist/types/config/model-discovery.d.ts +55 -0
- package/dist/types/config/model-registry.d.ts +8 -219
- package/dist/types/config/model-resolver.d.ts +34 -10
- package/dist/types/config/model-roles.d.ts +28 -0
- package/dist/types/config/models-config-schema.d.ts +523 -42
- package/dist/types/config/models-config.d.ts +385 -0
- package/dist/types/config/settings-schema.d.ts +41 -8
- package/dist/types/config/settings.d.ts +8 -1
- package/dist/types/debug/log-viewer.d.ts +1 -1
- package/dist/types/debug/raw-sse.d.ts +1 -1
- package/dist/types/edit/hashline/noop-loop-guard.d.ts +72 -0
- package/dist/types/eval/backend.d.ts +0 -2
- package/dist/types/eval/idle-timeout.d.ts +0 -4
- package/dist/types/eval/js/shared/rewrite-imports.d.ts +6 -6
- package/dist/types/eval/py/executor.d.ts +5 -0
- package/dist/types/eval/py/kernel.d.ts +6 -1
- package/dist/types/eval/py/runtime.d.ts +9 -0
- package/dist/types/exec/bash-executor.d.ts +2 -0
- package/dist/types/export/html/template.generated.d.ts +1 -1
- package/dist/types/extensibility/extensions/runner.d.ts +3 -2
- package/dist/types/extensibility/extensions/types.d.ts +6 -3
- package/dist/types/hindsight/mental-models.d.ts +17 -8
- package/dist/types/internal-urls/artifact-protocol.d.ts +2 -2
- package/dist/types/internal-urls/types.d.ts +1 -1
- package/dist/types/lsp/edits.d.ts +9 -0
- package/dist/types/lsp/index.d.ts +2 -2
- package/dist/types/lsp/types.d.ts +2 -0
- package/dist/types/lsp/utils.d.ts +3 -0
- package/dist/types/mcp/json-rpc.d.ts +5 -0
- package/dist/types/memory-backend/index.d.ts +1 -0
- package/dist/types/memory-backend/runtime.d.ts +4 -0
- package/dist/types/memory-backend/types.d.ts +66 -1
- package/dist/types/mnemopi/state.d.ts +11 -1
- package/dist/types/modes/components/agent-dashboard.d.ts +1 -1
- package/dist/types/modes/components/assistant-message.d.ts +3 -1
- package/dist/types/modes/components/bash-execution.d.ts +1 -1
- package/dist/types/modes/components/copy-selector.d.ts +1 -1
- 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 +1 -1
- package/dist/types/modes/components/model-selector.d.ts +1 -1
- package/dist/types/modes/components/plan-review-overlay.d.ts +1 -1
- package/dist/types/modes/components/session-observer-overlay.d.ts +1 -1
- package/dist/types/modes/components/session-selector.d.ts +1 -1
- package/dist/types/modes/components/status-line/component.d.ts +1 -1
- package/dist/types/modes/components/tiny-title-download-progress.d.ts +1 -1
- package/dist/types/modes/components/transcript-container.d.ts +25 -6
- package/dist/types/modes/components/tree-selector.d.ts +1 -1
- 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 +19 -3
- package/dist/types/modes/controllers/mcp-command-controller.d.ts +1 -1
- package/dist/types/modes/controllers/streaming-reveal.d.ts +1 -1
- package/dist/types/modes/index.d.ts +3 -3
- package/dist/types/modes/interactive-mode.d.ts +8 -3
- package/dist/types/modes/oauth-manual-input.d.ts +7 -0
- package/dist/types/modes/rpc/rpc-client.d.ts +39 -2
- package/dist/types/modes/rpc/rpc-mode.d.ts +31 -2
- package/dist/types/modes/rpc/rpc-subagents.d.ts +24 -0
- package/dist/types/modes/rpc/rpc-types.d.ts +75 -1
- package/dist/types/modes/setup-wizard/index.d.ts +5 -1
- package/dist/types/modes/setup-wizard/lazy.d.ts +2 -0
- package/dist/types/modes/setup-wizard/scenes/sign-in.d.ts +1 -1
- package/dist/types/modes/setup-wizard/scenes/types.d.ts +1 -1
- package/dist/types/modes/setup-wizard/scenes/web-search.d.ts +1 -1
- package/dist/types/modes/setup-wizard/wizard-overlay.d.ts +1 -1
- package/dist/types/modes/types.d.ts +4 -1
- package/dist/types/secrets/index.d.ts +1 -1
- package/dist/types/secrets/obfuscator.d.ts +8 -2
- package/dist/types/session/agent-session.d.ts +15 -3
- package/dist/types/session/auth-broker-config.d.ts +4 -0
- package/dist/types/session/session-manager.d.ts +1 -1
- package/dist/types/session/streaming-output.d.ts +23 -0
- package/dist/types/slash-commands/acp-builtins.d.ts +16 -0
- package/dist/types/slash-commands/builtin-registry.d.ts +1 -0
- package/dist/types/slash-commands/helpers/stats-dashboard.d.ts +13 -0
- package/dist/types/slash-commands/types.d.ts +1 -1
- package/dist/types/ssh/connection-manager.d.ts +8 -0
- package/dist/types/system-prompt.d.ts +2 -0
- package/dist/types/task/executor.d.ts +1 -0
- package/dist/types/task/index.d.ts +2 -2
- package/dist/types/task/parallel.d.ts +2 -2
- package/dist/types/task/types.d.ts +8 -0
- package/dist/types/task/worktree.d.ts +2 -0
- package/dist/types/thinking.d.ts +4 -0
- package/dist/types/tiny/title-client.d.ts +11 -0
- package/dist/types/tiny/title-protocol.d.ts +1 -0
- package/dist/types/tools/ask.d.ts +4 -0
- package/dist/types/tools/conflict-detect.d.ts +16 -0
- package/dist/types/tools/github-cache.d.ts +7 -0
- package/dist/types/tools/index.d.ts +6 -0
- package/dist/types/tools/sqlite-reader.d.ts +3 -0
- package/dist/types/tui/output-block.d.ts +3 -3
- package/dist/types/utils/changelog.d.ts +8 -0
- package/dist/types/utils/git.d.ts +15 -2
- package/dist/types/utils/title-generator.d.ts +3 -2
- 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/providers/codex.d.ts +1 -1
- package/dist/types/web/search/providers/gemini.d.ts +1 -1
- package/examples/extensions/tools.ts +5 -4
- package/package.json +14 -11
- package/scripts/build-binary.ts +18 -23
- package/scripts/bundle-dist.ts +81 -0
- package/scripts/{dev-launch → omp} +1 -1
- package/scripts/{dev-launch-preload.ts → omp.ts} +1 -1
- package/src/async/job-manager.ts +57 -3
- package/src/auto-thinking/classifier.ts +1 -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/capability/fs.ts +10 -0
- package/src/cli/args.ts +4 -1
- package/src/cli/auth-gateway-cli.ts +1 -3
- package/src/cli/dry-balance-cli.ts +1 -1
- package/src/cli/gallery-cli.ts +1 -1
- package/src/cli/gallery-fixtures/fs.ts +1 -1
- package/src/cli/gallery-fixtures/types.ts +5 -1
- package/src/cli/list-models.ts +2 -1
- package/src/cli/usage-cli.ts +603 -0
- package/src/cli-commands.ts +30 -0
- package/src/cli.ts +76 -13
- package/src/commands/complete.ts +1 -1
- package/src/commands/launch.ts +5 -1
- package/src/commands/read.ts +6 -3
- package/src/commands/usage.ts +35 -0
- package/src/commit/agentic/agent.ts +1 -1
- package/src/commit/model-selection.ts +4 -3
- package/src/config/api-key-resolver.ts +8 -6
- package/src/config/append-only-context-mode.ts +6 -12
- package/src/config/model-discovery.ts +554 -0
- package/src/config/model-registry.ts +320 -1041
- package/src/config/model-resolver.ts +173 -156
- package/src/config/model-roles.ts +74 -0
- package/src/config/models-config-schema.ts +57 -8
- package/src/config/models-config.ts +129 -0
- package/src/config/settings-schema.ts +61 -19
- package/src/config/settings.ts +98 -4
- package/src/dap/client.ts +124 -37
- package/src/dap/session.ts +259 -158
- package/src/debug/log-viewer.ts +1 -1
- package/src/debug/raw-sse.ts +1 -1
- package/src/edit/diff.ts +47 -3
- package/src/edit/hashline/block-resolver.ts +20 -1
- package/src/edit/hashline/diff.ts +36 -1
- package/src/edit/hashline/execute.ts +47 -4
- package/src/edit/hashline/noop-loop-guard.ts +99 -0
- package/src/edit/index.ts +16 -1
- package/src/edit/modes/patch.ts +52 -0
- package/src/edit/modes/replace.ts +56 -22
- package/src/edit/notebook.ts +22 -2
- package/src/edit/renderer.ts +36 -10
- package/src/eval/__tests__/completion-bridge.test.ts +1 -1
- package/src/eval/backend.ts +0 -2
- package/src/eval/completion-bridge.ts +3 -1
- package/src/eval/idle-timeout.ts +2 -9
- package/src/eval/js/context-manager.ts +6 -8
- package/src/eval/js/executor.ts +6 -2
- package/src/eval/js/index.ts +0 -2
- package/src/eval/js/shared/helpers.ts +5 -6
- package/src/eval/js/shared/local-module-loader.ts +1 -1
- package/src/eval/js/shared/prelude.txt +62 -1
- package/src/eval/js/shared/rewrite-imports.ts +40 -22
- package/src/eval/js/shared/runtime.ts +1 -1
- package/src/eval/py/executor.ts +29 -7
- package/src/eval/py/index.ts +6 -3
- package/src/eval/py/kernel.ts +43 -4
- package/src/eval/py/runner.py +107 -3
- package/src/eval/py/runtime.ts +37 -0
- package/src/exec/bash-executor.ts +85 -4
- package/src/export/html/template.generated.ts +1 -1
- package/src/export/html/template.js +3 -1
- package/src/extensibility/extensions/get-commands-handler.ts +2 -1
- package/src/extensibility/extensions/runner.ts +6 -1
- package/src/extensibility/extensions/types.ts +6 -2
- package/src/extensibility/plugins/legacy-pi-compat.ts +20 -3
- package/src/hindsight/bank.ts +17 -2
- package/src/hindsight/mental-models.ts +59 -12
- package/src/hindsight/state.ts +6 -1
- package/src/internal-urls/artifact-protocol.ts +11 -2
- package/src/internal-urls/docs-index.generated.ts +11 -11
- package/src/internal-urls/issue-pr-protocol.ts +12 -5
- package/src/internal-urls/router.ts +1 -1
- package/src/internal-urls/types.ts +1 -1
- package/src/lib/xai-http.ts +1 -1
- package/src/lsp/client.ts +118 -38
- package/src/lsp/clients/biome-client.ts +101 -39
- package/src/lsp/edits.ts +143 -95
- package/src/lsp/index.ts +31 -22
- package/src/lsp/render.ts +1 -1
- package/src/lsp/types.ts +2 -0
- package/src/lsp/utils.ts +28 -10
- package/src/main.ts +183 -23
- package/src/mcp/json-rpc.ts +35 -5
- package/src/mcp/transports/stdio.ts +7 -1
- package/src/memories/index.ts +4 -1
- package/src/memory-backend/index.ts +1 -0
- package/src/memory-backend/local-backend.ts +9 -0
- package/src/memory-backend/off-backend.ts +9 -0
- package/src/memory-backend/runtime.ts +66 -0
- package/src/memory-backend/types.ts +81 -1
- package/src/mnemopi/backend.ts +176 -7
- package/src/mnemopi/state.ts +38 -2
- package/src/modes/acp/acp-agent.ts +119 -11
- package/src/modes/components/agent-dashboard.ts +10 -7
- package/src/modes/components/assistant-message.ts +32 -28
- package/src/modes/components/bash-execution.ts +1 -1
- package/src/modes/components/copy-selector.ts +1 -1
- package/src/modes/components/diff.ts +13 -2
- package/src/modes/components/dynamic-border.ts +12 -3
- 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 +1 -1
- 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-selector.ts +2 -2
- package/src/modes/components/model-selector.ts +4 -2
- package/src/modes/components/plan-review-overlay.ts +1 -1
- package/src/modes/components/session-observer-overlay.ts +2 -2
- package/src/modes/components/session-selector.ts +1 -1
- package/src/modes/components/settings-selector.ts +5 -1
- package/src/modes/components/status-line/component.ts +119 -35
- package/src/modes/components/tiny-title-download-progress.ts +1 -1
- package/src/modes/components/transcript-container.ts +258 -53
- package/src/modes/components/tree-selector.ts +3 -3
- package/src/modes/components/user-message-selector.ts +1 -1
- package/src/modes/components/user-message.ts +17 -5
- package/src/modes/components/visual-truncate.ts +1 -1
- package/src/modes/components/welcome.ts +108 -26
- package/src/modes/controllers/command-controller.ts +11 -4
- package/src/modes/controllers/event-controller.ts +73 -4
- package/src/modes/controllers/input-controller.ts +2 -1
- package/src/modes/controllers/mcp-command-controller.ts +39 -4
- package/src/modes/controllers/selector-controller.ts +1 -1
- package/src/modes/controllers/streaming-reveal.ts +85 -18
- package/src/modes/index.ts +3 -21
- package/src/modes/interactive-mode.ts +42 -18
- package/src/modes/oauth-manual-input.ts +30 -3
- package/src/modes/rpc/rpc-client.ts +154 -3
- package/src/modes/rpc/rpc-mode.ts +97 -12
- package/src/modes/rpc/rpc-subagents.ts +265 -0
- package/src/modes/rpc/rpc-types.ts +81 -1
- package/src/modes/setup-wizard/index.ts +12 -2
- package/src/modes/setup-wizard/lazy.ts +16 -0
- package/src/modes/setup-wizard/scenes/glyph.ts +1 -1
- package/src/modes/setup-wizard/scenes/providers.ts +1 -1
- package/src/modes/setup-wizard/scenes/sign-in.ts +1 -1
- package/src/modes/setup-wizard/scenes/theme.ts +1 -1
- package/src/modes/setup-wizard/scenes/types.ts +1 -1
- package/src/modes/setup-wizard/scenes/web-search.ts +1 -1
- package/src/modes/setup-wizard/wizard-overlay.ts +1 -1
- package/src/modes/types.ts +4 -1
- package/src/prompts/agents/explore.md +2 -2
- package/src/prompts/agents/librarian.md +1 -2
- package/src/prompts/agents/oracle.md +1 -1
- package/src/prompts/agents/plan.md +5 -5
- package/src/prompts/agents/task.md +5 -5
- 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/memories/read-path.md +1 -1
- 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/background-tan-dispatch.md +1 -1
- 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-todo.md +2 -2
- package/src/prompts/system/irc-incoming.md +1 -1
- package/src/prompts/system/manual-continue.md +1 -1
- package/src/prompts/system/omfg-user.md +3 -4
- package/src/prompts/system/orchestrate-notice.md +9 -9
- package/src/prompts/system/plan-mode-active.md +4 -4
- 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/subagent-system-prompt.md +4 -4
- package/src/prompts/system/system-prompt.md +13 -24
- package/src/prompts/system/title-system.md +2 -2
- package/src/prompts/system/ttsr-tool-reminder.md +1 -1
- package/src/prompts/system/workflow-notice.md +1 -1
- package/src/prompts/tools/ast-edit.md +1 -1
- package/src/prompts/tools/ast-grep.md +2 -2
- package/src/prompts/tools/bash.md +5 -7
- package/src/prompts/tools/browser.md +7 -7
- package/src/prompts/tools/debug.md +1 -1
- package/src/prompts/tools/eval.md +3 -3
- 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 +15 -15
- package/src/prompts/tools/lsp.md +2 -2
- package/src/prompts/tools/patch.md +2 -2
- package/src/prompts/tools/read.md +3 -4
- 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.md +2 -3
- package/src/prompts/tools/todo.md +1 -1
- package/src/sdk.ts +31 -11
- package/src/secrets/index.ts +8 -1
- package/src/secrets/obfuscator.ts +39 -18
- package/src/session/agent-session.ts +223 -64
- package/src/session/auth-broker-config.ts +30 -1
- package/src/session/session-manager.ts +2 -2
- package/src/session/streaming-output.ts +188 -11
- package/src/slash-commands/acp-builtins.ts +24 -0
- package/src/slash-commands/builtin-registry.ts +40 -0
- package/src/slash-commands/helpers/stats-dashboard.ts +85 -0
- package/src/slash-commands/types.ts +1 -1
- package/src/ssh/connection-manager.ts +27 -0
- package/src/system-prompt.ts +14 -0
- package/src/task/commands.ts +2 -1
- package/src/task/executor.ts +74 -65
- package/src/task/index.ts +146 -68
- package/src/task/parallel.ts +3 -3
- package/src/task/render.ts +20 -5
- package/src/task/types.ts +9 -0
- package/src/task/worktree.ts +64 -56
- package/src/thinking.ts +9 -1
- package/src/tiny/title-client.ts +60 -16
- package/src/tiny/title-protocol.ts +1 -1
- package/src/tiny/worker.ts +6 -4
- package/src/tools/archive-reader.ts +30 -2
- package/src/tools/ask.ts +104 -21
- package/src/tools/ast-edit.ts +25 -5
- package/src/tools/auto-generated-guard.ts +20 -3
- package/src/tools/bash-interactive.ts +27 -7
- package/src/tools/bash.ts +100 -18
- package/src/tools/browser/launch.ts +11 -2
- package/src/tools/browser/readable.ts +19 -2
- package/src/tools/browser/registry.ts +4 -1
- package/src/tools/browser/render.ts +2 -2
- package/src/tools/browser/tab-supervisor.ts +55 -16
- package/src/tools/conflict-detect.ts +50 -4
- package/src/tools/debug.ts +1 -1
- package/src/tools/eval-render.ts +5 -5
- package/src/tools/eval.ts +0 -2
- package/src/tools/fetch.ts +33 -10
- package/src/tools/gh-cache-invalidation.ts +63 -8
- package/src/tools/gh-renderer.ts +1 -1
- package/src/tools/gh.ts +172 -29
- package/src/tools/github-cache.ts +70 -6
- package/src/tools/image-gen.ts +14 -13
- package/src/tools/index.ts +13 -1
- package/src/tools/inspect-image.ts +1 -0
- package/src/tools/irc.ts +5 -1
- package/src/tools/job.ts +1 -1
- package/src/tools/read.ts +202 -61
- package/src/tools/render-utils.ts +3 -3
- package/src/tools/resolve.ts +1 -1
- package/src/tools/search.ts +92 -29
- package/src/tools/sqlite-reader.ts +17 -5
- package/src/tools/ssh.ts +8 -8
- package/src/tools/todo.ts +38 -8
- package/src/tools/write.ts +118 -18
- package/src/tui/output-block.ts +4 -4
- package/src/utils/changelog.ts +27 -1
- package/src/utils/commit-message-generator.ts +1 -0
- package/src/utils/file-mentions.ts +2 -1
- package/src/utils/git.ts +267 -13
- package/src/utils/title-generator.ts +24 -5
- package/src/web/scrapers/arxiv.ts +1 -1
- 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 +6 -1
- package/src/web/search/index.ts +1 -1
- package/src/web/search/providers/codex.ts +2 -1
- package/src/web/search/providers/gemini.ts +2 -3
- package/src/web/search/render.ts +8 -6
- package/dist/types/config/model-equivalence.d.ts +0 -24
- package/dist/types/config/model-id-affixes.d.ts +0 -12
- package/dist/types/config/model-provider-priority.d.ts +0 -1
- package/dist/types/exec/idle-timeout-watchdog.d.ts +0 -18
- package/src/config/model-equivalence.ts +0 -875
- package/src/config/model-id-affixes.ts +0 -81
- package/src/config/model-provider-priority.ts +0 -56
- package/src/exec/idle-timeout-watchdog.ts +0 -126
|
@@ -17,6 +17,24 @@ const TIPS: readonly string[] = tipsText
|
|
|
17
17
|
.map(line => line.trim())
|
|
18
18
|
.filter(line => line.length > 0);
|
|
19
19
|
|
|
20
|
+
/**
|
|
21
|
+
* Tip chosen once per process so the pre-TUI startup splash and the in-TUI
|
|
22
|
+
* welcome screen show the same tip instead of shuffling on the swap.
|
|
23
|
+
*/
|
|
24
|
+
const PROCESS_TIP: string | undefined = TIPS.length > 0 ? TIPS[Math.floor(Math.random() * TIPS.length)] : undefined;
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Fixed number of session rows in the welcome box so its height doesn't shift
|
|
28
|
+
* between the pre-TUI splash (loading placeholder) and the loaded state.
|
|
29
|
+
*/
|
|
30
|
+
export const WELCOME_SESSION_SLOTS = 4;
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Fixed number of LSP-server rows, for the same reason. Overflow is sliced so
|
|
34
|
+
* the box height is constant regardless of how many servers a project has.
|
|
35
|
+
*/
|
|
36
|
+
export const WELCOME_LSP_SLOTS = 4;
|
|
37
|
+
|
|
20
38
|
export function renderWelcomeTip(tip: string, boxWidth: number): string[] {
|
|
21
39
|
const label = "Tip: ";
|
|
22
40
|
const labelWidth = visibleWidth(label);
|
|
@@ -48,7 +66,7 @@ export interface RecentSession {
|
|
|
48
66
|
|
|
49
67
|
export interface LspServerInfo {
|
|
50
68
|
name: string;
|
|
51
|
-
status: "ready" | "error" | "connecting";
|
|
69
|
+
status: "ready" | "error" | "connecting" | "available";
|
|
52
70
|
fileTypes: string[];
|
|
53
71
|
}
|
|
54
72
|
|
|
@@ -58,18 +76,38 @@ export interface LspServerInfo {
|
|
|
58
76
|
export class WelcomeComponent implements Component {
|
|
59
77
|
#animStart: number | null = null;
|
|
60
78
|
#animTimer: ReturnType<typeof setInterval> | null = null;
|
|
61
|
-
/**
|
|
62
|
-
|
|
79
|
+
/** When set, a non-animating render shows the intro's first frame instead of the resting frame. */
|
|
80
|
+
#holdIntroFirstFrame = false;
|
|
81
|
+
/** Per-process tip so re-renders (intro, LSP updates, splash swap) don't shuffle it. */
|
|
82
|
+
readonly #tip: string | undefined = PROCESS_TIP;
|
|
83
|
+
// Render cache: the welcome box is the first transcript-area component, so
|
|
84
|
+
// returning a stable array reference keeps the whole frame prefix stable.
|
|
85
|
+
// Bypassed while the intro animation runs (every frame differs).
|
|
86
|
+
#cachedWidth = -1;
|
|
87
|
+
#cachedLines: string[] | undefined;
|
|
63
88
|
|
|
64
89
|
constructor(
|
|
65
90
|
private readonly version: string,
|
|
66
91
|
private modelName: string,
|
|
67
92
|
private providerName: string,
|
|
68
|
-
private recentSessions: RecentSession[] = [],
|
|
93
|
+
private recentSessions: RecentSession[] | null = [],
|
|
69
94
|
private lspServers: LspServerInfo[] = [],
|
|
70
95
|
) {}
|
|
71
96
|
|
|
72
|
-
invalidate(): void {
|
|
97
|
+
invalidate(): void {
|
|
98
|
+
this.#cachedWidth = -1;
|
|
99
|
+
this.#cachedLines = undefined;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* Freeze the logo on the intro animation's first frame. The pre-TUI startup
|
|
104
|
+
* splash uses this so the in-TUI intro — which starts at that exact frame —
|
|
105
|
+
* picks up seamlessly from the splash's static box.
|
|
106
|
+
*/
|
|
107
|
+
holdIntroFirstFrame(): void {
|
|
108
|
+
this.#holdIntroFirstFrame = true;
|
|
109
|
+
this.invalidate();
|
|
110
|
+
}
|
|
73
111
|
|
|
74
112
|
/**
|
|
75
113
|
* Play a one-shot intro that sweeps the gradient through every phase
|
|
@@ -78,6 +116,7 @@ export class WelcomeComponent implements Component {
|
|
|
78
116
|
*/
|
|
79
117
|
playIntro(requestRender: () => void): void {
|
|
80
118
|
this.#stopAnimation();
|
|
119
|
+
this.#holdIntroFirstFrame = false;
|
|
81
120
|
this.#animStart = performance.now();
|
|
82
121
|
requestRender();
|
|
83
122
|
this.#animTimer = setInterval(() => {
|
|
@@ -95,22 +134,43 @@ export class WelcomeComponent implements Component {
|
|
|
95
134
|
this.#animTimer = null;
|
|
96
135
|
}
|
|
97
136
|
this.#animStart = null;
|
|
137
|
+
// The settled (resting) frame differs from the last intro frame.
|
|
138
|
+
this.invalidate();
|
|
98
139
|
}
|
|
99
140
|
|
|
100
141
|
setModel(modelName: string, providerName: string): void {
|
|
101
142
|
this.modelName = modelName;
|
|
102
143
|
this.providerName = providerName;
|
|
144
|
+
this.invalidate();
|
|
103
145
|
}
|
|
104
146
|
|
|
105
147
|
setRecentSessions(sessions: RecentSession[]): void {
|
|
106
148
|
this.recentSessions = sessions;
|
|
149
|
+
this.invalidate();
|
|
107
150
|
}
|
|
108
151
|
|
|
109
152
|
setLspServers(servers: LspServerInfo[]): void {
|
|
110
153
|
this.lspServers = servers;
|
|
154
|
+
this.invalidate();
|
|
111
155
|
}
|
|
112
156
|
|
|
113
|
-
render(termWidth: number): string[] {
|
|
157
|
+
render(termWidth: number): readonly string[] {
|
|
158
|
+
const animating = this.#animStart != null;
|
|
159
|
+
if (!animating && this.#cachedLines && this.#cachedWidth === termWidth) {
|
|
160
|
+
return this.#cachedLines;
|
|
161
|
+
}
|
|
162
|
+
const lines = this.#renderLines(termWidth);
|
|
163
|
+
if (animating) {
|
|
164
|
+
this.#cachedLines = undefined;
|
|
165
|
+
this.#cachedWidth = -1;
|
|
166
|
+
} else {
|
|
167
|
+
this.#cachedLines = lines;
|
|
168
|
+
this.#cachedWidth = termWidth;
|
|
169
|
+
}
|
|
170
|
+
return lines;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
#renderLines(termWidth: number): string[] {
|
|
114
174
|
// Box dimensions - responsive with max width and small-terminal support
|
|
115
175
|
const maxWidth = 100;
|
|
116
176
|
const boxWidth = Math.min(maxWidth, Math.max(0, termWidth - 2));
|
|
@@ -157,7 +217,9 @@ export class WelcomeComponent implements Component {
|
|
|
157
217
|
|
|
158
218
|
// Recent sessions content
|
|
159
219
|
const sessionLines: string[] = [];
|
|
160
|
-
if (this.recentSessions
|
|
220
|
+
if (this.recentSessions === null) {
|
|
221
|
+
sessionLines.push(` ${theme.fg("dim", "Loading…")}`);
|
|
222
|
+
} else if (this.recentSessions.length === 0) {
|
|
161
223
|
sessionLines.push(` ${theme.fg("dim", "No recent sessions")}`);
|
|
162
224
|
} else {
|
|
163
225
|
// Reserve width for the bullet prefix (" • ") and the trailing " (timeAgo)"
|
|
@@ -165,7 +227,7 @@ export class WelcomeComponent implements Component {
|
|
|
165
227
|
// absorbs whatever space is left.
|
|
166
228
|
const bulletPrefix = ` ${theme.md.bullet} `;
|
|
167
229
|
const prefixWidth = visibleWidth(bulletPrefix);
|
|
168
|
-
for (const session of this.recentSessions.slice(0,
|
|
230
|
+
for (const session of this.recentSessions.slice(0, WELCOME_SESSION_SLOTS)) {
|
|
169
231
|
const timeSuffixRaw = ` (${session.timeAgo})`;
|
|
170
232
|
const timeWidth = visibleWidth(timeSuffixRaw);
|
|
171
233
|
const nameBudget = Math.max(1, rightCol - prefixWidth - timeWidth);
|
|
@@ -176,23 +238,33 @@ export class WelcomeComponent implements Component {
|
|
|
176
238
|
);
|
|
177
239
|
}
|
|
178
240
|
}
|
|
241
|
+
// Pad to the fixed slot count so the box doesn't grow when sessions load in.
|
|
242
|
+
while (sessionLines.length < WELCOME_SESSION_SLOTS) {
|
|
243
|
+
sessionLines.push("");
|
|
244
|
+
}
|
|
179
245
|
|
|
180
246
|
// LSP servers content
|
|
181
247
|
const lspLines: string[] = [];
|
|
182
248
|
if (this.lspServers.length === 0) {
|
|
183
249
|
lspLines.push(` ${theme.fg("dim", "No LSP servers")}`);
|
|
184
250
|
} else {
|
|
185
|
-
for (const server of this.lspServers) {
|
|
251
|
+
for (const server of this.lspServers.slice(0, WELCOME_LSP_SLOTS)) {
|
|
186
252
|
const icon =
|
|
187
253
|
server.status === "ready"
|
|
188
254
|
? theme.styledSymbol("status.enabled", "success")
|
|
189
|
-
: server.status === "
|
|
190
|
-
? theme.styledSymbol("status.
|
|
191
|
-
:
|
|
255
|
+
: server.status === "available"
|
|
256
|
+
? theme.styledSymbol("status.enabled", "dim")
|
|
257
|
+
: server.status === "connecting"
|
|
258
|
+
? theme.styledSymbol("status.pending", "muted")
|
|
259
|
+
: theme.styledSymbol("status.error", "error");
|
|
192
260
|
const exts = server.fileTypes.slice(0, 3).join(" ");
|
|
193
261
|
lspLines.push(` ${icon} ${theme.fg("muted", server.name)} ${theme.fg("dim", exts)}`);
|
|
194
262
|
}
|
|
195
263
|
}
|
|
264
|
+
// Pad to the fixed slot count so the box height doesn't depend on server count.
|
|
265
|
+
while (lspLines.length < WELCOME_LSP_SLOTS) {
|
|
266
|
+
lspLines.push("");
|
|
267
|
+
}
|
|
196
268
|
|
|
197
269
|
// Right column
|
|
198
270
|
const rightLines = [
|
|
@@ -305,23 +377,12 @@ export class WelcomeComponent implements Component {
|
|
|
305
377
|
return str + padding(width - visLen);
|
|
306
378
|
}
|
|
307
379
|
|
|
308
|
-
/** Pick the logo frame for the current intro phase, or the resting frame. */
|
|
380
|
+
/** Pick the logo frame for the current intro phase, or the resting/held frame. */
|
|
309
381
|
#currentLogoFrame(): readonly string[] {
|
|
310
|
-
if (this.#animStart == null) return REST_FRAME;
|
|
382
|
+
if (this.#animStart == null) return this.#holdIntroFirstFrame ? INTRO_FIRST_FRAME : REST_FRAME;
|
|
311
383
|
const elapsed = performance.now() - this.#animStart;
|
|
312
384
|
if (elapsed >= INTRO_MS) return REST_FRAME;
|
|
313
|
-
|
|
314
|
-
const progress = elapsed / INTRO_MS;
|
|
315
|
-
const eased = 1 - (1 - progress) ** 3;
|
|
316
|
-
// Sweep backward through INTRO_SWEEPS full rotations so the gradient
|
|
317
|
-
// visibly spins multiple times. `eased == 1` → phase = 0 = resting frame.
|
|
318
|
-
const phase = ((((1 - eased) * INTRO_SWEEPS) % 1) + 1) % 1;
|
|
319
|
-
// Shine traverses the diagonal at a steady pace, decoupled from the
|
|
320
|
-
// gradient phase so the two layers parallax. Strength fades out with
|
|
321
|
-
// the same ease-out curve so the highlight is gone by the resting frame.
|
|
322
|
-
const shinePos = (((progress * INTRO_SHINE_TRAVERSALS) % 1) + 1) % 1;
|
|
323
|
-
const shineStrength = (1 - eased) ** 1.5;
|
|
324
|
-
return gradientLogo(PI_LOGO, phase, { strength: shineStrength, pos: shinePos });
|
|
385
|
+
return introLogoFrame(elapsed / INTRO_MS);
|
|
325
386
|
}
|
|
326
387
|
}
|
|
327
388
|
|
|
@@ -431,5 +492,26 @@ const INTRO_SWEEPS = 2.5;
|
|
|
431
492
|
/** Number of times the shine highlight crosses the diagonal across the intro. */
|
|
432
493
|
const INTRO_SHINE_TRAVERSALS = 3;
|
|
433
494
|
|
|
495
|
+
/**
|
|
496
|
+
* Logo frame for a normalized intro progress in [0, 1).
|
|
497
|
+
*
|
|
498
|
+
* Ease-out cubic so the spin decelerates into the resting state. The gradient
|
|
499
|
+
* sweeps backward through INTRO_SWEEPS full rotations (`eased == 1` → phase =
|
|
500
|
+
* 0 = resting frame) while the shine traverses the diagonal at a steady pace,
|
|
501
|
+
* decoupled from the gradient phase so the two layers parallax; its strength
|
|
502
|
+
* fades with the same ease-out curve so the highlight is gone by the resting
|
|
503
|
+
* frame.
|
|
504
|
+
*/
|
|
505
|
+
function introLogoFrame(progress: number): string[] {
|
|
506
|
+
const eased = 1 - (1 - progress) ** 3;
|
|
507
|
+
const phase = ((((1 - eased) * INTRO_SWEEPS) % 1) + 1) % 1;
|
|
508
|
+
const shinePos = (((progress * INTRO_SHINE_TRAVERSALS) % 1) + 1) % 1;
|
|
509
|
+
const shineStrength = (1 - eased) ** 1.5;
|
|
510
|
+
return gradientLogo(PI_LOGO, phase, { strength: shineStrength, pos: shinePos });
|
|
511
|
+
}
|
|
512
|
+
|
|
513
|
+
/** First intro frame, cached for splash-held renders (resize re-renders reuse it). */
|
|
514
|
+
const INTRO_FIRST_FRAME = introLogoFrame(0);
|
|
515
|
+
|
|
434
516
|
/** Resting gradient frame, cached for re-renders outside of the intro. */
|
|
435
517
|
const REST_FRAME = gradientLogo(PI_LOGO, 0);
|
|
@@ -21,6 +21,7 @@ import {
|
|
|
21
21
|
loadHindsightConfig,
|
|
22
22
|
reloadMentalModelsForSession,
|
|
23
23
|
resolveSeedsForScope,
|
|
24
|
+
seedAlreadyExists,
|
|
24
25
|
summarizeMentalModel,
|
|
25
26
|
} from "../../hindsight";
|
|
26
27
|
import { resolveMemoryBackend } from "../../memory-backend";
|
|
@@ -314,7 +315,13 @@ export class CommandController {
|
|
|
314
315
|
info += `\n${theme.bold("LSP Servers")}\n`;
|
|
315
316
|
for (const server of this.ctx.lspServers) {
|
|
316
317
|
const statusColor =
|
|
317
|
-
server.status === "ready"
|
|
318
|
+
server.status === "ready"
|
|
319
|
+
? "success"
|
|
320
|
+
: server.status === "available"
|
|
321
|
+
? "dim"
|
|
322
|
+
: server.status === "connecting"
|
|
323
|
+
? "warning"
|
|
324
|
+
: "error";
|
|
318
325
|
const statusText =
|
|
319
326
|
server.status === "error" && server.error ? `${server.status}: ${server.error}` : server.status;
|
|
320
327
|
info += `${theme.fg("dim", `${server.name}:`)} ${theme.fg(statusColor, statusText)} ${theme.fg("dim", `(${server.fileTypes.join(", ")})`)}\n`;
|
|
@@ -712,11 +719,11 @@ export class CommandController {
|
|
|
712
719
|
return;
|
|
713
720
|
}
|
|
714
721
|
const list = await state.client.listMentalModels(state.bankId, { detail: "metadata" });
|
|
715
|
-
const existing =
|
|
722
|
+
const existing = list.items ?? [];
|
|
716
723
|
let created = 0;
|
|
717
724
|
let skipped = 0;
|
|
718
725
|
for (const seed of seeds) {
|
|
719
|
-
if (
|
|
726
|
+
if (seedAlreadyExists(seed, existing)) {
|
|
720
727
|
skipped++;
|
|
721
728
|
continue;
|
|
722
729
|
}
|
|
@@ -927,7 +934,7 @@ export class CommandController {
|
|
|
927
934
|
this.ctx.bashComponent.appendOutput(chunk);
|
|
928
935
|
}
|
|
929
936
|
},
|
|
930
|
-
{ excludeFromContext },
|
|
937
|
+
{ excludeFromContext, useUserShell: true },
|
|
931
938
|
);
|
|
932
939
|
|
|
933
940
|
if (this.ctx.bashComponent) {
|
|
@@ -25,6 +25,16 @@ import { StreamingRevealController } from "./streaming-reveal";
|
|
|
25
25
|
type AgentSessionEventKind = AgentSessionEvent["type"];
|
|
26
26
|
|
|
27
27
|
const IRC_MESSAGE_VISIBLE_TTL_MS = 10_000;
|
|
28
|
+
/**
|
|
29
|
+
* Concurrent IRC cards allowed in the transcript's live region. Cards land
|
|
30
|
+
* below a still-live block (a running task), where they cannot commit to
|
|
31
|
+
* native scrollback (commits are prefix-only) — every visible card inflates
|
|
32
|
+
* the live region and pushes the live block's uncommitted rows above the
|
|
33
|
+
* window top, where they are neither on screen nor in history. A swarm burst
|
|
34
|
+
* (several agents coordinating at once) must therefore stay bounded: the
|
|
35
|
+
* oldest live-region card retires as soon as a new one would exceed the cap.
|
|
36
|
+
*/
|
|
37
|
+
const MAX_LIVE_IRC_CARDS = 4;
|
|
28
38
|
|
|
29
39
|
/**
|
|
30
40
|
* Loader label shown the instant a user interrupt (Esc) is requested, kept until
|
|
@@ -64,6 +74,9 @@ export class EventController {
|
|
|
64
74
|
#pinnedErrorComponent: AssistantMessageComponent | undefined = undefined;
|
|
65
75
|
#idleCompactionTimer?: NodeJS.Timeout;
|
|
66
76
|
#ircExpiryTimers = new Map<string, NodeJS.Timeout>();
|
|
77
|
+
// Insertion-ordered IRC cards not yet retired; values are the transcript
|
|
78
|
+
// components each card contributed (see #retireIrcCard for the guard).
|
|
79
|
+
#liveIrcCards = new Map<string, Component[]>();
|
|
67
80
|
#streamingReveal: StreamingRevealController;
|
|
68
81
|
#handlers: AgentSessionEventHandlers;
|
|
69
82
|
|
|
@@ -111,6 +124,7 @@ export class EventController {
|
|
|
111
124
|
clearTimeout(timer);
|
|
112
125
|
}
|
|
113
126
|
this.#ircExpiryTimers.clear();
|
|
127
|
+
this.#liveIrcCards.clear();
|
|
114
128
|
}
|
|
115
129
|
|
|
116
130
|
#resetReadGroup(): void {
|
|
@@ -324,6 +338,7 @@ export class EventController {
|
|
|
324
338
|
this.#resetReadGroup();
|
|
325
339
|
const components = this.ctx.addMessageToChat(event.message);
|
|
326
340
|
this.#scheduleIrcExpiry(signature, components);
|
|
341
|
+
this.#enforceIrcCardCap(signature);
|
|
327
342
|
this.ctx.ui.requestRender();
|
|
328
343
|
}
|
|
329
344
|
|
|
@@ -331,13 +346,47 @@ export class EventController {
|
|
|
331
346
|
if (components.length === 0 || this.#ircExpiryTimers.has(signature)) return;
|
|
332
347
|
const timer = setTimeout(() => {
|
|
333
348
|
this.#ircExpiryTimers.delete(signature);
|
|
334
|
-
|
|
335
|
-
this.ctx.chatContainer.removeChild(component);
|
|
336
|
-
}
|
|
337
|
-
this.ctx.ui.requestRender();
|
|
349
|
+
this.#retireIrcCard(signature);
|
|
338
350
|
}, IRC_MESSAGE_VISIBLE_TTL_MS);
|
|
339
351
|
timer.unref?.();
|
|
340
352
|
this.#ircExpiryTimers.set(signature, timer);
|
|
353
|
+
this.#liveIrcCards.set(signature, components);
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
/**
|
|
357
|
+
* Remove an expired/evicted IRC card — but only while it still sits below a
|
|
358
|
+
* live block, where its rows cannot have entered native scrollback. Once
|
|
359
|
+
* everything above it has finalized, its rows may already be committed;
|
|
360
|
+
* removing them then is an interior deletion of the committed prefix, which
|
|
361
|
+
* the engine can only repair by recommitting every row below the gap —
|
|
362
|
+
* exactly the duplicated-block artifact this guard exists to prevent. Such
|
|
363
|
+
* a card simply stays: it is final history, and the window scrolls past it.
|
|
364
|
+
*/
|
|
365
|
+
#retireIrcCard(signature: string): void {
|
|
366
|
+
const components = this.#liveIrcCards.get(signature);
|
|
367
|
+
this.#liveIrcCards.delete(signature);
|
|
368
|
+
if (!components) return;
|
|
369
|
+
let removed = false;
|
|
370
|
+
for (const component of components) {
|
|
371
|
+
if (!this.ctx.chatContainer.isWithinLiveRegion(component)) continue;
|
|
372
|
+
this.ctx.chatContainer.removeChild(component);
|
|
373
|
+
removed = true;
|
|
374
|
+
}
|
|
375
|
+
if (removed) this.ctx.ui.requestRender();
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
/** Evict oldest live-region cards beyond {@link MAX_LIVE_IRC_CARDS}. */
|
|
379
|
+
#enforceIrcCardCap(latestSignature: string): void {
|
|
380
|
+
while (this.#liveIrcCards.size > MAX_LIVE_IRC_CARDS) {
|
|
381
|
+
const oldest = this.#liveIrcCards.keys().next().value;
|
|
382
|
+
if (oldest === undefined || oldest === latestSignature) return;
|
|
383
|
+
const timer = this.#ircExpiryTimers.get(oldest);
|
|
384
|
+
if (timer) {
|
|
385
|
+
clearTimeout(timer);
|
|
386
|
+
this.#ircExpiryTimers.delete(oldest);
|
|
387
|
+
}
|
|
388
|
+
this.#retireIrcCard(oldest);
|
|
389
|
+
}
|
|
341
390
|
}
|
|
342
391
|
|
|
343
392
|
async #handleNotice(event: Extract<AgentSessionEvent, { type: "notice" }>): Promise<void> {
|
|
@@ -365,6 +414,26 @@ export class EventController {
|
|
|
365
414
|
this.#resetReadGroup();
|
|
366
415
|
this.#lastVisibleBlockCount = visibleBlockCount;
|
|
367
416
|
}
|
|
417
|
+
|
|
418
|
+
// Content blocks stream sequentially: a toolCall block can only begin
|
|
419
|
+
// after every preceding thinking/text block has closed, and the
|
|
420
|
+
// reveal's setTarget above force-completes the visible text for
|
|
421
|
+
// toolCall messages. Finalize the assistant block now instead of at
|
|
422
|
+
// message_end so the transcript's commit-safe run can extend through
|
|
423
|
+
// it into the streaming tool preview below — otherwise a long args
|
|
424
|
+
// stream (a big write/edit/eval) sits below a still-live block and
|
|
425
|
+
// can never reach native scrollback: the head of the preview is
|
|
426
|
+
// neither committed nor on screen and the transcript reads as cut.
|
|
427
|
+
// Skipped when the per-turn usage row is enabled: that row is only
|
|
428
|
+
// known at message_end and appends to this block, which would shift
|
|
429
|
+
// committed tool rows below it every turn (audit recommit →
|
|
430
|
+
// duplicated preview copies in scrollback).
|
|
431
|
+
if (
|
|
432
|
+
this.ctx.streamingMessage.content.some(content => content.type === "toolCall") &&
|
|
433
|
+
!settings.get("display.showTokenUsage")
|
|
434
|
+
) {
|
|
435
|
+
this.ctx.streamingComponent.markTranscriptBlockFinalized();
|
|
436
|
+
}
|
|
368
437
|
for (const content of this.ctx.streamingMessage.content) {
|
|
369
438
|
if (content.type !== "toolCall") continue;
|
|
370
439
|
if (content.name === "read") {
|
|
@@ -2,7 +2,7 @@ import * as fs from "node:fs/promises";
|
|
|
2
2
|
import type { ImageContent } from "@oh-my-pi/pi-ai";
|
|
3
3
|
import type { AutocompleteProvider, SlashCommand } from "@oh-my-pi/pi-tui";
|
|
4
4
|
import { $env, logger, sanitizeText } from "@oh-my-pi/pi-utils";
|
|
5
|
-
import { getRoleInfo } from "../../config/model-
|
|
5
|
+
import { getRoleInfo } from "../../config/model-roles";
|
|
6
6
|
import { isSettingsInitialized, settings } from "../../config/settings";
|
|
7
7
|
import { renderSegmentTrack } from "../../modes/components/segment-track";
|
|
8
8
|
import { TinyTitleDownloadProgressComponent } from "../../modes/components/tiny-title-download-progress";
|
|
@@ -467,6 +467,7 @@ export class InputController {
|
|
|
467
467
|
this.ctx.session.sessionId,
|
|
468
468
|
this.ctx.session.model,
|
|
469
469
|
provider => this.ctx.session.agent.metadataForProvider(provider),
|
|
470
|
+
this.ctx.titleSystemPrompt,
|
|
470
471
|
)
|
|
471
472
|
.then(async title => {
|
|
472
473
|
// Re-check: a concurrent attempt for an earlier message may have
|
|
@@ -46,9 +46,14 @@ import { theme } from "../theme/theme";
|
|
|
46
46
|
import type { InteractiveModeContext } from "../types";
|
|
47
47
|
import { groupBySource, parseRemoveArgs, readScopeFlag, showCommandMessage } from "./command-controller-shared";
|
|
48
48
|
|
|
49
|
-
|
|
49
|
+
const MCP_MANUAL_INPUT_PROVIDER_ID = "mcp";
|
|
50
|
+
const MCP_MANUAL_LOGIN_TIP = "Headless? Paste the redirect URL or code with /login <value>.";
|
|
51
|
+
function withTimeout<T>(promise: Promise<T>, timeoutMs: number, message: string, onTimeout?: () => void): Promise<T> {
|
|
50
52
|
const { promise: timeoutPromise, reject } = Promise.withResolvers<T>();
|
|
51
|
-
const timer = setTimeout(() =>
|
|
53
|
+
const timer = setTimeout(() => {
|
|
54
|
+
onTimeout?.();
|
|
55
|
+
reject(new Error(message));
|
|
56
|
+
}, timeoutMs);
|
|
52
57
|
return Promise.race([promise, timeoutPromise]).finally(() => clearTimeout(timer));
|
|
53
58
|
}
|
|
54
59
|
|
|
@@ -62,7 +67,7 @@ export class MCPAuthorizationLinkPrompt implements Component {
|
|
|
62
67
|
|
|
63
68
|
invalidate(): void {}
|
|
64
69
|
|
|
65
|
-
render(_width: number): string[] {
|
|
70
|
+
render(_width: number): readonly string[] {
|
|
66
71
|
const link = urlHyperlinkAlways(this.#url, "Click here to authorize");
|
|
67
72
|
return [
|
|
68
73
|
` ${theme.fg("success", "Open authorization URL:")}`,
|
|
@@ -591,6 +596,15 @@ export class MCPCommandController {
|
|
|
591
596
|
const resolvedClientId = clientId.trim() || parsedAuthUrl.searchParams.get("client_id") || undefined;
|
|
592
597
|
const resolvedClientSecret = clientSecret.trim() || undefined;
|
|
593
598
|
|
|
599
|
+
const manualInput = this.ctx.oauthManualInput;
|
|
600
|
+
if (manualInput.hasPending()) {
|
|
601
|
+
const pendingProvider = manualInput.pendingProviderId ?? "another provider";
|
|
602
|
+
throw new Error(
|
|
603
|
+
`OAuth login already in progress for ${pendingProvider}. Complete or cancel it before starting MCP OAuth.`,
|
|
604
|
+
);
|
|
605
|
+
}
|
|
606
|
+
let manualInputClaim: { promise: Promise<string>; clear: (reason?: string) => void } | undefined;
|
|
607
|
+
const oauthTimeout = new AbortController();
|
|
594
608
|
try {
|
|
595
609
|
// Create OAuth flow
|
|
596
610
|
const flow = new MCPOAuthFlow(
|
|
@@ -620,6 +634,7 @@ export class MCPCommandController {
|
|
|
620
634
|
0,
|
|
621
635
|
),
|
|
622
636
|
);
|
|
637
|
+
block.addChild(new Text(theme.fg("muted", MCP_MANUAL_LOGIN_TIP), 1, 0));
|
|
623
638
|
block.addChild(new Spacer(1));
|
|
624
639
|
block.addChild(new Text(theme.fg("accent", "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"), 1, 0));
|
|
625
640
|
// Try to open browser automatically
|
|
@@ -644,11 +659,29 @@ export class MCPCommandController {
|
|
|
644
659
|
onProgress: (message: string) => {
|
|
645
660
|
this.ctx.present([new Spacer(1), new Text(theme.fg("muted", message), 1, 0)]);
|
|
646
661
|
},
|
|
662
|
+
onManualCodeInput: () => {
|
|
663
|
+
if (manualInputClaim) return manualInputClaim.promise;
|
|
664
|
+
const pendingInput = manualInput.tryClaimInput(MCP_MANUAL_INPUT_PROVIDER_ID);
|
|
665
|
+
if (!pendingInput) {
|
|
666
|
+
const pendingProvider = manualInput.pendingProviderId ?? "another provider";
|
|
667
|
+
throw new Error(
|
|
668
|
+
`OAuth login already in progress for ${pendingProvider}. Complete or cancel it before starting MCP OAuth.`,
|
|
669
|
+
);
|
|
670
|
+
}
|
|
671
|
+
manualInputClaim = pendingInput;
|
|
672
|
+
return pendingInput.promise;
|
|
673
|
+
},
|
|
674
|
+
signal: oauthTimeout.signal,
|
|
647
675
|
},
|
|
648
676
|
);
|
|
649
677
|
|
|
650
678
|
// Execute OAuth flow with 5 minute timeout
|
|
651
|
-
const credentials = await withTimeout(
|
|
679
|
+
const credentials = await withTimeout(
|
|
680
|
+
flow.login(),
|
|
681
|
+
5 * 60 * 1000,
|
|
682
|
+
"OAuth flow timed out after 5 minutes",
|
|
683
|
+
() => oauthTimeout.abort("MCP OAuth flow timed out"),
|
|
684
|
+
);
|
|
652
685
|
|
|
653
686
|
this.ctx.present([
|
|
654
687
|
new Spacer(1),
|
|
@@ -687,6 +720,8 @@ export class MCPCommandController {
|
|
|
687
720
|
} else {
|
|
688
721
|
throw new Error(`OAuth authentication failed: ${errorMsg}`);
|
|
689
722
|
}
|
|
723
|
+
} finally {
|
|
724
|
+
manualInputClaim?.clear("Manual MCP OAuth input cleared");
|
|
690
725
|
}
|
|
691
726
|
}
|
|
692
727
|
|
|
@@ -5,8 +5,8 @@ import type { OAuthProvider } from "@oh-my-pi/pi-ai/oauth/types";
|
|
|
5
5
|
import type { Component, OverlayHandle } from "@oh-my-pi/pi-tui";
|
|
6
6
|
import { Input, Loader, Spacer, Text } from "@oh-my-pi/pi-tui";
|
|
7
7
|
import { getAgentDbPath, getProjectDir, normalizePathForComparison } from "@oh-my-pi/pi-utils";
|
|
8
|
-
import { getRoleInfo } from "../../config/model-registry";
|
|
9
8
|
import { formatModelSelectorValue } from "../../config/model-resolver";
|
|
9
|
+
import { getRoleInfo } from "../../config/model-roles";
|
|
10
10
|
import { settings } from "../../config/settings";
|
|
11
11
|
import { disableProvider, enableProvider } from "../../discovery";
|
|
12
12
|
import { clearPluginRootsAndCaches, resolveActiveProjectRegistryPath } from "../../discovery/helpers";
|