@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
package/src/main.ts
CHANGED
|
@@ -11,6 +11,7 @@ import { EventLoopKeepalive } from "@oh-my-pi/pi-agent-core";
|
|
|
11
11
|
import type { ImageContent } from "@oh-my-pi/pi-ai";
|
|
12
12
|
import {
|
|
13
13
|
$env,
|
|
14
|
+
getLogPath,
|
|
14
15
|
getProjectDir,
|
|
15
16
|
logger,
|
|
16
17
|
normalizePathForComparison,
|
|
@@ -28,7 +29,7 @@ import { runListModelsCommand } from "./cli/list-models";
|
|
|
28
29
|
import { selectSession } from "./cli/session-picker";
|
|
29
30
|
import { applyStartupCwd } from "./cli/startup-cwd";
|
|
30
31
|
import { findConfigFile } from "./config";
|
|
31
|
-
import { ModelRegistry
|
|
32
|
+
import { ModelRegistry } from "./config/model-registry";
|
|
32
33
|
import {
|
|
33
34
|
getModelMatchPreferences,
|
|
34
35
|
resolveCliModel,
|
|
@@ -36,6 +37,7 @@ import {
|
|
|
36
37
|
resolveModelScope,
|
|
37
38
|
type ScopedModel,
|
|
38
39
|
} from "./config/model-resolver";
|
|
40
|
+
import { ModelsConfigFile } from "./config/models-config";
|
|
39
41
|
import { getDefault, type SettingPath, Settings, settings } from "./config/settings";
|
|
40
42
|
import { initializeWithSettings } from "./discovery";
|
|
41
43
|
import {
|
|
@@ -49,6 +51,7 @@ import { ExtensionRunner } from "./extensibility/extensions/runner";
|
|
|
49
51
|
import type { ExtensionUIContext } from "./extensibility/extensions/types";
|
|
50
52
|
import { scheduleMarketplaceAutoUpdate } from "./extensibility/plugins/marketplace-auto-update";
|
|
51
53
|
import type { MCPManager } from "./mcp";
|
|
54
|
+
import { WelcomeComponent } from "./modes/components/welcome";
|
|
52
55
|
import { InteractiveMode } from "./modes/interactive-mode";
|
|
53
56
|
import type { PrintModeOptions } from "./modes/print-mode";
|
|
54
57
|
import { CURRENT_SETUP_VERSION } from "./modes/setup-version";
|
|
@@ -64,11 +67,17 @@ import {
|
|
|
64
67
|
import type { AgentSession } from "./session/agent-session";
|
|
65
68
|
import type { AuthStorage } from "./session/auth-storage";
|
|
66
69
|
import { resolveResumableSession, type SessionInfo, SessionManager } from "./session/session-manager";
|
|
67
|
-
import { resolvePromptInput } from "./system-prompt";
|
|
70
|
+
import { discoverTitleSystemPromptFile, resolvePromptInput } from "./system-prompt";
|
|
68
71
|
import { initTelemetryExport, isTelemetryExportEnabled } from "./telemetry-export";
|
|
69
72
|
import { AUTO_THINKING } from "./thinking";
|
|
70
|
-
import type
|
|
71
|
-
import {
|
|
73
|
+
import { discoverStartupLspServers, type LspStartupServerInfo } from "./tools";
|
|
74
|
+
import {
|
|
75
|
+
getChangelogPath,
|
|
76
|
+
getNewEntries,
|
|
77
|
+
parseChangelog,
|
|
78
|
+
readLastChangelogVersion,
|
|
79
|
+
writeLastChangelogVersion,
|
|
80
|
+
} from "./utils/changelog";
|
|
72
81
|
import { EventBus } from "./utils/event-bus";
|
|
73
82
|
|
|
74
83
|
type RunAcpMode = (createSession: AcpSessionFactory) => Promise<never>;
|
|
@@ -76,8 +85,47 @@ type RunPrintMode = (session: AgentSession, options: PrintModeOptions) => Promis
|
|
|
76
85
|
type RunRpcMode = (
|
|
77
86
|
session: AgentSession,
|
|
78
87
|
setToolUIContext?: (uiContext: ExtensionUIContext, hasUI: boolean) => void,
|
|
88
|
+
eventBus?: EventBus,
|
|
79
89
|
) => Promise<never>;
|
|
80
90
|
|
|
91
|
+
function maybeShowStartupSplash(options: {
|
|
92
|
+
isInteractive: boolean;
|
|
93
|
+
resuming: boolean;
|
|
94
|
+
quiet: boolean;
|
|
95
|
+
version: string;
|
|
96
|
+
setupPending: boolean;
|
|
97
|
+
modelName?: string;
|
|
98
|
+
providerName?: string;
|
|
99
|
+
lspServers?: LspStartupServerInfo[];
|
|
100
|
+
}): void {
|
|
101
|
+
if (!options.isInteractive) return;
|
|
102
|
+
if (options.resuming || options.quiet) return;
|
|
103
|
+
if ($env.PI_TIMING) return;
|
|
104
|
+
if (!process.stdin.isTTY || !process.stdout.isTTY) return;
|
|
105
|
+
// First-run launches go straight into the setup wizard, which paints its own
|
|
106
|
+
// splash — keep the minimal two-line notice there.
|
|
107
|
+
if (options.setupPending) {
|
|
108
|
+
process.stdout.write(`${chalk.dim(`omp ${options.version}`)}\n${chalk.dim("Initializing session…")}\n`);
|
|
109
|
+
return;
|
|
110
|
+
}
|
|
111
|
+
// Render the same welcome box the TUI paints first: recent sessions as a
|
|
112
|
+
// loading placeholder (the fixed slot count keeps the box height stable) and
|
|
113
|
+
// the logo held on the intro animation's first frame so the in-TUI intro
|
|
114
|
+
// continues from the frame shown here. Clearing the screen first puts the
|
|
115
|
+
// box at the same origin the TUI's first full paint (clearScrollback) uses,
|
|
116
|
+
// so the live welcome replaces this frame in place without shifting.
|
|
117
|
+
const welcome = new WelcomeComponent(
|
|
118
|
+
options.version,
|
|
119
|
+
options.modelName ?? "",
|
|
120
|
+
options.providerName ?? "",
|
|
121
|
+
null,
|
|
122
|
+
options.lspServers ?? [],
|
|
123
|
+
);
|
|
124
|
+
welcome.holdIntroFirstFrame();
|
|
125
|
+
const lines = welcome.render(process.stdout.columns || 80);
|
|
126
|
+
process.stdout.write(`\x1b[2J\x1b[H\x1b[3J\n${lines.join("\n")}\n`);
|
|
127
|
+
}
|
|
128
|
+
|
|
81
129
|
async function checkForNewVersion(currentVersion: string): Promise<string | undefined> {
|
|
82
130
|
if (!settings.get("startup.checkUpdate")) {
|
|
83
131
|
return;
|
|
@@ -143,15 +191,79 @@ function applyAcpDefaultSettingOverrides(targetSettings: Settings = settings): v
|
|
|
143
191
|
|
|
144
192
|
async function readPipedInput(): Promise<string | undefined> {
|
|
145
193
|
if (process.stdin.isTTY !== false) return undefined;
|
|
194
|
+
// stdin is a pipe: a producer that never writes nor closes would block
|
|
195
|
+
// startup forever with zero output. Say what we're blocked on after 1s.
|
|
196
|
+
const notice = setTimeout(() => {
|
|
197
|
+
process.stderr.write(`${chalk.dim("Reading prompt from piped stdin (waiting for EOF; ctrl+c to abort)…")}\n`);
|
|
198
|
+
}, 1000);
|
|
199
|
+
notice.unref?.();
|
|
146
200
|
try {
|
|
147
201
|
const text = await Bun.stdin.text();
|
|
148
202
|
if (text.trim().length === 0) return undefined;
|
|
149
203
|
return text;
|
|
150
204
|
} catch {
|
|
151
205
|
return undefined;
|
|
206
|
+
} finally {
|
|
207
|
+
clearTimeout(notice);
|
|
152
208
|
}
|
|
153
209
|
}
|
|
154
210
|
|
|
211
|
+
// ---------------------------------------------------------------------------
|
|
212
|
+
// Startup watchdog
|
|
213
|
+
// ---------------------------------------------------------------------------
|
|
214
|
+
// Speculative-hang reporter: until startup hands off to a mode runner, print a
|
|
215
|
+
// stderr line every 10s naming the deepest in-flight startup phase. Turns
|
|
216
|
+
// zero-output indefinite hangs (stuck discovery read, network wait, stdin
|
|
217
|
+
// pipe) into self-diagnosing reports instead of "it just hangs" (see the
|
|
218
|
+
// PI_DEBUG_STARTUP markers for the synchronous-hang counterpart).
|
|
219
|
+
|
|
220
|
+
const STARTUP_WATCHDOG_INTERVAL_MS = 10_000;
|
|
221
|
+
let startupWatchdogTimer: NodeJS.Timeout | undefined;
|
|
222
|
+
let startupWatchdogActive = false;
|
|
223
|
+
let startupWatchdogStartedAt = 0;
|
|
224
|
+
|
|
225
|
+
function armStartupWatchdog(): void {
|
|
226
|
+
if (startupWatchdogTimer) return;
|
|
227
|
+
startupWatchdogTimer = setInterval(() => {
|
|
228
|
+
const elapsed = Math.round((Date.now() - startupWatchdogStartedAt) / 1000);
|
|
229
|
+
const phase = logger.openSpanPath().join(" > ") || "module load / pre-phase work";
|
|
230
|
+
process.stderr.write(
|
|
231
|
+
`${chalk.yellow(`Still starting after ${elapsed}s`)}${chalk.dim(` — phase: ${phase}`)}\n` +
|
|
232
|
+
`${chalk.dim(` logs: ${getLogPath()} · re-run with PI_DEBUG_STARTUP=1 for streaming phase markers`)}\n`,
|
|
233
|
+
);
|
|
234
|
+
}, STARTUP_WATCHDOG_INTERVAL_MS);
|
|
235
|
+
startupWatchdogTimer.unref?.();
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
function disarmStartupWatchdog(): void {
|
|
239
|
+
if (!startupWatchdogTimer) return;
|
|
240
|
+
clearInterval(startupWatchdogTimer);
|
|
241
|
+
startupWatchdogTimer = undefined;
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
/** Begin watching startup (idempotent). */
|
|
245
|
+
function startStartupWatchdog(): void {
|
|
246
|
+
startupWatchdogActive = true;
|
|
247
|
+
startupWatchdogStartedAt = Date.now();
|
|
248
|
+
armStartupWatchdog();
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
/** Permanently stop watching: a mode runner now owns the terminal. */
|
|
252
|
+
function stopStartupWatchdog(): void {
|
|
253
|
+
startupWatchdogActive = false;
|
|
254
|
+
disarmStartupWatchdog();
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
/** Pause while an interactive prompt legitimately waits on the user. */
|
|
258
|
+
function pauseStartupWatchdog(): void {
|
|
259
|
+
disarmStartupWatchdog();
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
/** Resume after an interactive prompt, if startup is still being watched. */
|
|
263
|
+
function resumeStartupWatchdog(): void {
|
|
264
|
+
if (startupWatchdogActive) armStartupWatchdog();
|
|
265
|
+
}
|
|
266
|
+
|
|
155
267
|
export interface InteractiveModeNotify {
|
|
156
268
|
kind: "warn" | "error" | "info";
|
|
157
269
|
message: string;
|
|
@@ -259,6 +371,7 @@ async function runInteractiveMode(
|
|
|
259
371
|
eventBus?: EventBus,
|
|
260
372
|
initialMessage?: string,
|
|
261
373
|
initialImages?: ImageContent[],
|
|
374
|
+
titleSystemPrompt?: string,
|
|
262
375
|
): Promise<void> {
|
|
263
376
|
const mode = new InteractiveMode(
|
|
264
377
|
session,
|
|
@@ -268,6 +381,7 @@ async function runInteractiveMode(
|
|
|
268
381
|
lspServers,
|
|
269
382
|
mcpManager,
|
|
270
383
|
eventBus,
|
|
384
|
+
titleSystemPrompt,
|
|
271
385
|
);
|
|
272
386
|
|
|
273
387
|
// Cold-launch gate: the full setup wizard (every scene + the overlay and
|
|
@@ -361,12 +475,14 @@ async function promptForkSession(session: SessionInfo): Promise<SessionPromptRes
|
|
|
361
475
|
return "unavailable";
|
|
362
476
|
}
|
|
363
477
|
const message = `Session found in different project: ${session.cwd}. Fork into current directory? [y/N] `;
|
|
478
|
+
pauseStartupWatchdog();
|
|
364
479
|
const rl = createInterface({ input: process.stdin, output: process.stdout });
|
|
365
480
|
try {
|
|
366
481
|
const answer = (await rl.question(message)).trim().toLowerCase();
|
|
367
482
|
return answer === "y" || answer === "yes" ? "accepted" : "declined";
|
|
368
483
|
} finally {
|
|
369
484
|
rl.close();
|
|
485
|
+
resumeStartupWatchdog();
|
|
370
486
|
}
|
|
371
487
|
}
|
|
372
488
|
|
|
@@ -375,12 +491,14 @@ async function promptMoveSession(session: SessionInfo): Promise<SessionPromptRes
|
|
|
375
491
|
return "unavailable";
|
|
376
492
|
}
|
|
377
493
|
const message = `Session's directory no longer exists (${session.cwd}). Move (re-root) it into the current directory? [Y/n] `;
|
|
494
|
+
pauseStartupWatchdog();
|
|
378
495
|
const rl = createInterface({ input: process.stdin, output: process.stdout });
|
|
379
496
|
try {
|
|
380
497
|
const answer = (await rl.question(message)).trim().toLowerCase();
|
|
381
498
|
return answer === "" || answer === "y" || answer === "yes" ? "accepted" : "declined";
|
|
382
499
|
} finally {
|
|
383
500
|
rl.close();
|
|
501
|
+
resumeStartupWatchdog();
|
|
384
502
|
}
|
|
385
503
|
}
|
|
386
504
|
|
|
@@ -437,7 +555,7 @@ async function getChangelogForDisplay(parsed: Args): Promise<string | undefined>
|
|
|
437
555
|
return undefined;
|
|
438
556
|
}
|
|
439
557
|
|
|
440
|
-
const lastVersion =
|
|
558
|
+
const lastVersion = await readLastChangelogVersion();
|
|
441
559
|
if (lastVersion === VERSION) {
|
|
442
560
|
// Steady state: user already saw the current version's changelog. Skip the file read + parse.
|
|
443
561
|
return undefined;
|
|
@@ -448,15 +566,13 @@ async function getChangelogForDisplay(parsed: Args): Promise<string | undefined>
|
|
|
448
566
|
|
|
449
567
|
if (!lastVersion) {
|
|
450
568
|
if (entries.length > 0) {
|
|
451
|
-
|
|
452
|
-
await flushChangelogVersion();
|
|
569
|
+
await writeLastChangelogVersion(VERSION);
|
|
453
570
|
return entries.map(e => e.content).join("\n\n");
|
|
454
571
|
}
|
|
455
572
|
} else {
|
|
456
573
|
const newEntries = getNewEntries(entries, lastVersion);
|
|
457
574
|
if (newEntries.length > 0) {
|
|
458
|
-
|
|
459
|
-
await flushChangelogVersion();
|
|
575
|
+
await writeLastChangelogVersion(VERSION);
|
|
460
576
|
return newEntries.map(e => e.content).join("\n\n");
|
|
461
577
|
}
|
|
462
578
|
}
|
|
@@ -464,14 +580,6 @@ async function getChangelogForDisplay(parsed: Args): Promise<string | undefined>
|
|
|
464
580
|
return undefined;
|
|
465
581
|
}
|
|
466
582
|
|
|
467
|
-
async function flushChangelogVersion(): Promise<void> {
|
|
468
|
-
try {
|
|
469
|
-
await settings.flush();
|
|
470
|
-
} catch (error: unknown) {
|
|
471
|
-
logger.warn("Failed to persist lastChangelogVersion", { error });
|
|
472
|
-
}
|
|
473
|
-
}
|
|
474
|
-
|
|
475
583
|
/** Resolves CLI session flags into an existing, forked, in-memory, or cancelled session manager. */
|
|
476
584
|
export async function createSessionManager(
|
|
477
585
|
parsed: Args,
|
|
@@ -619,7 +727,7 @@ async function buildSessionOptions(
|
|
|
619
727
|
sessionManager: SessionManager | undefined,
|
|
620
728
|
modelRegistry: ModelRegistry,
|
|
621
729
|
activeSettings: Settings,
|
|
622
|
-
): Promise<{ options: CreateAgentSessionOptions }> {
|
|
730
|
+
): Promise<{ options: CreateAgentSessionOptions; titleSystemPrompt?: string }> {
|
|
623
731
|
const options: CreateAgentSessionOptions = {
|
|
624
732
|
cwd: parsed.cwd ?? getProjectDir(),
|
|
625
733
|
autoApprove: parsed.autoApprove ?? false,
|
|
@@ -630,6 +738,8 @@ async function buildSessionOptions(
|
|
|
630
738
|
const resolvedSystemPrompt = await resolvePromptInput(systemPromptSource, "system prompt");
|
|
631
739
|
const appendPromptSource = parsed.appendSystemPrompt ?? discoverAppendSystemPromptFile();
|
|
632
740
|
const resolvedAppendPrompt = await resolvePromptInput(appendPromptSource, "append system prompt");
|
|
741
|
+
const titleSystemPromptSource = discoverTitleSystemPromptFile();
|
|
742
|
+
const titleSystemPrompt = await resolvePromptInput(titleSystemPromptSource, "title system prompt");
|
|
633
743
|
|
|
634
744
|
if (sessionManager) {
|
|
635
745
|
options.sessionManager = sessionManager;
|
|
@@ -775,7 +885,7 @@ async function buildSessionOptions(
|
|
|
775
885
|
options.additionalExtensionPaths = [];
|
|
776
886
|
}
|
|
777
887
|
|
|
778
|
-
return { options };
|
|
888
|
+
return { options, titleSystemPrompt };
|
|
779
889
|
}
|
|
780
890
|
|
|
781
891
|
interface RunRootCommandDependencies {
|
|
@@ -792,6 +902,7 @@ export async function runRootCommand(
|
|
|
792
902
|
deps: RunRootCommandDependencies = {},
|
|
793
903
|
): Promise<void> {
|
|
794
904
|
logger.startTiming();
|
|
905
|
+
startStartupWatchdog();
|
|
795
906
|
|
|
796
907
|
// Initialize theme early with defaults (CLI commands need symbols)
|
|
797
908
|
// Will be re-initialized with user preferences later
|
|
@@ -803,7 +914,7 @@ export async function runRootCommand(
|
|
|
803
914
|
const notifs: (InteractiveModeNotify | null)[] = [];
|
|
804
915
|
|
|
805
916
|
// Create AuthStorage and ModelRegistry upfront
|
|
806
|
-
const authStorage = await logger.time("
|
|
917
|
+
const authStorage = await logger.time("discoverAuthStorage", deps.discoverAuthStorage ?? discoverAuthStorage);
|
|
807
918
|
const modelRegistry = new ModelRegistry(authStorage);
|
|
808
919
|
|
|
809
920
|
if (parsedArgs.version) {
|
|
@@ -814,6 +925,7 @@ export async function runRootCommand(
|
|
|
814
925
|
if (parsedArgs.listModels !== undefined) {
|
|
815
926
|
const settingsInstance = await logger.time("settings:init:list-models", Settings.init, {
|
|
816
927
|
cwd: getProjectDir(),
|
|
928
|
+
configFiles: parsedArgs.config,
|
|
817
929
|
});
|
|
818
930
|
await modelRegistry.refresh("online");
|
|
819
931
|
const cliExtensionPaths = parsedArgs.noExtensions
|
|
@@ -877,11 +989,16 @@ export async function runRootCommand(
|
|
|
877
989
|
}
|
|
878
990
|
|
|
879
991
|
let cwd = getProjectDir();
|
|
880
|
-
const settingsInstance =
|
|
992
|
+
const settingsInstance =
|
|
993
|
+
deps.settings ?? (await logger.time("settings:init", Settings.init, { cwd, configFiles: parsedArgs.config }));
|
|
881
994
|
if (parsedArgs.approvalMode) {
|
|
882
995
|
// Runtime override (not persisted): every settings.get("tools.approvalMode") downstream
|
|
883
996
|
// sees this value. The wrapper still honours --auto-approve / --yolo on top of it.
|
|
884
997
|
settingsInstance.override("tools.approvalMode", parsedArgs.approvalMode);
|
|
998
|
+
} else if (parsedArgs.autoApprove) {
|
|
999
|
+
// --auto-approve / --yolo without an explicit --approval-mode: reflect in settings so
|
|
1000
|
+
// setup-time checks (e.g. #wrapToolForAcpPermission) also see the yolo intent.
|
|
1001
|
+
settingsInstance.override("tools.approvalMode", "yolo");
|
|
885
1002
|
}
|
|
886
1003
|
if (parsedArgs.mode === "rpc" || parsedArgs.mode === "rpc-ui") {
|
|
887
1004
|
applyRpcDefaultSettingOverrides(settingsInstance);
|
|
@@ -991,10 +1108,12 @@ export async function runRootCommand(
|
|
|
991
1108
|
}
|
|
992
1109
|
startInAllScope = true;
|
|
993
1110
|
}
|
|
1111
|
+
pauseStartupWatchdog();
|
|
994
1112
|
const selected = await logger.time("selectSession", selectSession, folderSessions, {
|
|
995
1113
|
allSessions: preloadedAllSessions,
|
|
996
1114
|
startInAllScope,
|
|
997
1115
|
});
|
|
1116
|
+
resumeStartupWatchdog();
|
|
998
1117
|
if (!selected) {
|
|
999
1118
|
process.stdout.write(`${chalk.dim("No session selected")}\n`);
|
|
1000
1119
|
return;
|
|
@@ -1025,7 +1144,7 @@ export async function runRootCommand(
|
|
|
1025
1144
|
clearPluginRootsCache: clearPluginRootsAndCaches,
|
|
1026
1145
|
});
|
|
1027
1146
|
|
|
1028
|
-
const { options: sessionOptions } = await logger.time(
|
|
1147
|
+
const { options: sessionOptions, titleSystemPrompt } = await logger.time(
|
|
1029
1148
|
"buildSessionOptions",
|
|
1030
1149
|
buildSessionOptions,
|
|
1031
1150
|
parsedArgs,
|
|
@@ -1086,6 +1205,7 @@ export async function runRootCommand(
|
|
|
1086
1205
|
});
|
|
1087
1206
|
// Branch-only protocol runner: keep ACP server code out of normal interactive startup.
|
|
1088
1207
|
const runAcpMode = deps.runAcpMode ?? (await import("./modes/acp/acp-mode")).runAcpMode;
|
|
1208
|
+
stopStartupWatchdog();
|
|
1089
1209
|
await runAcpMode(createAcpSession);
|
|
1090
1210
|
} else {
|
|
1091
1211
|
// Resolve extension-registered CLI flags before creating the session so a
|
|
@@ -1119,6 +1239,42 @@ export async function runRootCommand(
|
|
|
1119
1239
|
stdinContent: pipedInput,
|
|
1120
1240
|
});
|
|
1121
1241
|
|
|
1242
|
+
// Resolve the model the session will most likely start with so the splash
|
|
1243
|
+
// box matches the final welcome screen (the raw role selector, e.g.
|
|
1244
|
+
// "anthropic/claude-fable-5:high", is wider than the left column and would
|
|
1245
|
+
// collapse the box into the single-column layout).
|
|
1246
|
+
let splashModel = sessionOptions.model;
|
|
1247
|
+
if (!splashModel) {
|
|
1248
|
+
const remembered = settingsInstance.getModelRole("default");
|
|
1249
|
+
if (remembered) {
|
|
1250
|
+
splashModel = resolveModelRoleValue(remembered, modelRegistry.getAll(), {
|
|
1251
|
+
settings: settingsInstance,
|
|
1252
|
+
matchPreferences: modelMatchPreferences,
|
|
1253
|
+
modelRegistry,
|
|
1254
|
+
}).model;
|
|
1255
|
+
}
|
|
1256
|
+
}
|
|
1257
|
+
// Mirror createAgentSession's startup LSP discovery (sync and cheap: root
|
|
1258
|
+
// markers + binary lookup) so the splash lists the same servers the live
|
|
1259
|
+
// welcome screen will show.
|
|
1260
|
+
const splashLspServers =
|
|
1261
|
+
(sessionOptions.enableLsp ?? true)
|
|
1262
|
+
? discoverStartupLspServers(
|
|
1263
|
+
sessionOptions.cwd ?? cwd,
|
|
1264
|
+
settingsInstance.get("lsp.lazy") ? "available" : "connecting",
|
|
1265
|
+
)
|
|
1266
|
+
: [];
|
|
1267
|
+
maybeShowStartupSplash({
|
|
1268
|
+
isInteractive,
|
|
1269
|
+
resuming: Boolean(parsedArgs.continue || parsedArgs.resume || parsedArgs.fork),
|
|
1270
|
+
quiet: settingsInstance.get("startup.quiet"),
|
|
1271
|
+
version: VERSION,
|
|
1272
|
+
setupPending: deps.forceSetupWizard === true || settingsInstance.get("setupVersion") < CURRENT_SETUP_VERSION,
|
|
1273
|
+
modelName: splashModel?.name,
|
|
1274
|
+
providerName: splashModel?.provider,
|
|
1275
|
+
lspServers: splashLspServers,
|
|
1276
|
+
});
|
|
1277
|
+
|
|
1122
1278
|
const { session, setToolUIContext, modelFallbackMessage, lspServers, mcpManager } = await createSession({
|
|
1123
1279
|
...sessionOptions,
|
|
1124
1280
|
eventBus,
|
|
@@ -1152,7 +1308,8 @@ export async function runRootCommand(
|
|
|
1152
1308
|
if (mode === "rpc" || mode === "rpc-ui") {
|
|
1153
1309
|
// Branch-only protocol runner: keep RPC host code out of normal interactive startup.
|
|
1154
1310
|
const runRpcMode: RunRpcMode = (await import("./modes/rpc/rpc-mode")).runRpcMode;
|
|
1155
|
-
|
|
1311
|
+
stopStartupWatchdog();
|
|
1312
|
+
await runRpcMode(session, mode === "rpc-ui" ? setToolUIContext : undefined, eventBus);
|
|
1156
1313
|
} else if (isInteractive) {
|
|
1157
1314
|
const versionCheckPromise = checkForNewVersion(VERSION).catch(() => undefined);
|
|
1158
1315
|
const changelogMarkdown = await logger.time("main:getChangelogForDisplay", getChangelogForDisplay, parsedArgs);
|
|
@@ -1175,6 +1332,7 @@ export async function runRootCommand(
|
|
|
1175
1332
|
}
|
|
1176
1333
|
}
|
|
1177
1334
|
|
|
1335
|
+
stopStartupWatchdog();
|
|
1178
1336
|
logger.endTiming();
|
|
1179
1337
|
await runInteractiveMode(
|
|
1180
1338
|
session,
|
|
@@ -1191,9 +1349,11 @@ export async function runRootCommand(
|
|
|
1191
1349
|
eventBus,
|
|
1192
1350
|
initialMessage,
|
|
1193
1351
|
initialImages,
|
|
1352
|
+
titleSystemPrompt,
|
|
1194
1353
|
);
|
|
1195
1354
|
} else {
|
|
1196
1355
|
// Branch-only single-shot runner: keep print-mode code out of normal interactive startup.
|
|
1356
|
+
stopStartupWatchdog();
|
|
1197
1357
|
const runPrintMode: RunPrintMode = (await import("./modes/print-mode")).runPrintMode;
|
|
1198
1358
|
await runPrintMode(session, {
|
|
1199
1359
|
mode,
|
package/src/mcp/json-rpc.ts
CHANGED
|
@@ -6,6 +6,28 @@
|
|
|
6
6
|
*/
|
|
7
7
|
import { logger } from "@oh-my-pi/pi-utils";
|
|
8
8
|
|
|
9
|
+
/** Hard ceiling on a single MCP HTTP request when the caller provides no signal. */
|
|
10
|
+
const MCP_DEFAULT_TIMEOUT_MS = 60_000;
|
|
11
|
+
|
|
12
|
+
const SENSITIVE_QUERY_PARAM = /key|token|secret|auth/i;
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Redact credential-bearing query params (e.g. `exaApiKey`) so failed
|
|
16
|
+
* requests never write secrets to the persistent log file.
|
|
17
|
+
*/
|
|
18
|
+
export function redactUrlForLog(url: string): string {
|
|
19
|
+
try {
|
|
20
|
+
const parsed = new URL(url);
|
|
21
|
+
for (const name of parsed.searchParams.keys()) {
|
|
22
|
+
if (SENSITIVE_QUERY_PARAM.test(name)) parsed.searchParams.set(name, "[redacted]");
|
|
23
|
+
}
|
|
24
|
+
return parsed.toString();
|
|
25
|
+
} catch {
|
|
26
|
+
// Unparseable URL — drop the query string entirely rather than risk leaking it.
|
|
27
|
+
return url.split("?")[0];
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
9
31
|
/** Parse SSE response format (lines starting with "data: ") */
|
|
10
32
|
export function parseSSE(text: string): unknown {
|
|
11
33
|
const lines = text.split("\n");
|
|
@@ -13,8 +35,12 @@ export function parseSSE(text: string): unknown {
|
|
|
13
35
|
if (line.startsWith("data: ")) {
|
|
14
36
|
const data = line.slice(6).trim();
|
|
15
37
|
if (data === "[DONE]") continue;
|
|
16
|
-
|
|
17
|
-
|
|
38
|
+
try {
|
|
39
|
+
const result = JSON.parse(data) as unknown;
|
|
40
|
+
if (result) return result;
|
|
41
|
+
} catch {
|
|
42
|
+
// Non-JSON data line (keep-alive/comment) — skip and keep scanning.
|
|
43
|
+
}
|
|
18
44
|
}
|
|
19
45
|
}
|
|
20
46
|
// Fallback: try parsing entire response as JSON
|
|
@@ -71,12 +97,12 @@ export async function callMCP<T = unknown>(
|
|
|
71
97
|
Accept: "application/json, text/event-stream",
|
|
72
98
|
},
|
|
73
99
|
body: JSON.stringify(body),
|
|
74
|
-
signal: options?.signal,
|
|
100
|
+
signal: options?.signal ?? AbortSignal.timeout(MCP_DEFAULT_TIMEOUT_MS),
|
|
75
101
|
});
|
|
76
102
|
|
|
77
103
|
if (!response.ok) {
|
|
78
104
|
const errorMsg = `MCP request failed: ${response.status} ${response.statusText}`;
|
|
79
|
-
logger.error(errorMsg, { url, method, params });
|
|
105
|
+
logger.error(errorMsg, { url: redactUrlForLog(url), method, params });
|
|
80
106
|
throw new Error(errorMsg);
|
|
81
107
|
}
|
|
82
108
|
|
|
@@ -84,7 +110,11 @@ export async function callMCP<T = unknown>(
|
|
|
84
110
|
const result = parseSSE(text) as JsonRpcResponse<T> | null;
|
|
85
111
|
|
|
86
112
|
if (!result) {
|
|
87
|
-
logger.error("Failed to parse MCP response", {
|
|
113
|
+
logger.error("Failed to parse MCP response", {
|
|
114
|
+
url: redactUrlForLog(url),
|
|
115
|
+
method,
|
|
116
|
+
responseText: text.slice(0, 500),
|
|
117
|
+
});
|
|
88
118
|
throw new Error("Failed to parse MCP response");
|
|
89
119
|
}
|
|
90
120
|
|
|
@@ -133,6 +133,12 @@ function resolveComSpec(env: Record<string, string | undefined>): string {
|
|
|
133
133
|
return comspec && comspec.length > 0 ? comspec : "cmd.exe";
|
|
134
134
|
}
|
|
135
135
|
|
|
136
|
+
/** `cmd /s /c` strips one outer quote pair; keep inner argv quotes intact. */
|
|
137
|
+
function buildCmdExeCommand(command: string, args: readonly string[]): string {
|
|
138
|
+
const quotedCommand = [command, ...args].map(quoteCmdArg).join(" ");
|
|
139
|
+
return `"${quotedCommand}"`;
|
|
140
|
+
}
|
|
141
|
+
|
|
136
142
|
/** Resolve the subprocess argv used to launch an MCP stdio server. */
|
|
137
143
|
export async function resolveStdioSpawnCommand(
|
|
138
144
|
config: MCPStdioServerConfig,
|
|
@@ -146,7 +152,7 @@ export async function resolveStdioSpawnCommand(
|
|
|
146
152
|
if (!isWindowsBatchCommand(resolvedCommand)) return { cmd: [resolvedCommand, ...args] };
|
|
147
153
|
|
|
148
154
|
return {
|
|
149
|
-
cmd: [resolveComSpec(options.env), "/d", "/s", "/c",
|
|
155
|
+
cmd: [resolveComSpec(options.env), "/d", "/s", "/c", buildCmdExeCommand(resolvedCommand, args)],
|
|
150
156
|
};
|
|
151
157
|
}
|
|
152
158
|
|
package/src/memories/index.ts
CHANGED
|
@@ -3,7 +3,8 @@ import type * as fsNode from "node:fs";
|
|
|
3
3
|
import * as fs from "node:fs/promises";
|
|
4
4
|
import * as path from "node:path";
|
|
5
5
|
import type { AgentMessage } from "@oh-my-pi/pi-agent-core";
|
|
6
|
-
import { type ApiKey,
|
|
6
|
+
import { type ApiKey, completeSimple, Effort, type Model } from "@oh-my-pi/pi-ai";
|
|
7
|
+
import { clampThinkingLevelForModel } from "@oh-my-pi/pi-catalog/model-thinking";
|
|
7
8
|
import { getAgentDbPath, getMemoriesDir, logger, parseJsonlLenient, prompt } from "@oh-my-pi/pi-utils";
|
|
8
9
|
|
|
9
10
|
import type { ModelRegistry } from "../config/model-registry";
|
|
@@ -275,6 +276,7 @@ async function runPhase1(options: {
|
|
|
275
276
|
apiKey: modelRegistry.resolver(phase1Model.provider, {
|
|
276
277
|
sessionId: session.sessionId,
|
|
277
278
|
baseUrl: phase1Model.baseUrl,
|
|
279
|
+
modelId: phase1Model.id,
|
|
278
280
|
}),
|
|
279
281
|
modelMaxTokens: computeModelTokenBudget(phase1Model, config),
|
|
280
282
|
config,
|
|
@@ -435,6 +437,7 @@ async function runPhase2(options: {
|
|
|
435
437
|
apiKey: modelRegistry.resolver(phase2Model.provider, {
|
|
436
438
|
sessionId: session.sessionId,
|
|
437
439
|
baseUrl: phase2Model.baseUrl,
|
|
440
|
+
modelId: phase2Model.id,
|
|
438
441
|
}),
|
|
439
442
|
metadata: session.agent?.metadataForProvider(phase2Model.provider),
|
|
440
443
|
});
|
|
@@ -27,4 +27,13 @@ export const localBackend: MemoryBackend = {
|
|
|
27
27
|
async enqueue(agentDir, cwd) {
|
|
28
28
|
enqueueMemoryConsolidation(agentDir, cwd);
|
|
29
29
|
},
|
|
30
|
+
async status() {
|
|
31
|
+
return {
|
|
32
|
+
backend: "local" as const,
|
|
33
|
+
active: true,
|
|
34
|
+
writable: false,
|
|
35
|
+
searchable: false,
|
|
36
|
+
message: "Local rollout-summary memory is active; structured search/save is not available.",
|
|
37
|
+
};
|
|
38
|
+
},
|
|
30
39
|
};
|
|
@@ -13,4 +13,13 @@ export const offBackend: MemoryBackend = {
|
|
|
13
13
|
},
|
|
14
14
|
async clear() {},
|
|
15
15
|
async enqueue() {},
|
|
16
|
+
async status() {
|
|
17
|
+
return {
|
|
18
|
+
backend: "off" as const,
|
|
19
|
+
active: false,
|
|
20
|
+
writable: false,
|
|
21
|
+
searchable: false,
|
|
22
|
+
message: "Memory backend is off.",
|
|
23
|
+
};
|
|
24
|
+
},
|
|
16
25
|
};
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import type { AgentSession } from "../session/agent-session";
|
|
2
|
+
import { resolveMemoryBackend } from "./resolve";
|
|
3
|
+
import type {
|
|
4
|
+
MemoryBackendId,
|
|
5
|
+
MemoryBackendOperationContext,
|
|
6
|
+
MemoryBackendSaveInput,
|
|
7
|
+
MemoryBackendSearchOptions,
|
|
8
|
+
MemoryRuntimeContext,
|
|
9
|
+
} from "./types";
|
|
10
|
+
export function createMemoryRuntimeContext(context: MemoryBackendOperationContext): MemoryRuntimeContext {
|
|
11
|
+
const settings = context.session?.settings;
|
|
12
|
+
return {
|
|
13
|
+
async status() {
|
|
14
|
+
if (!settings) {
|
|
15
|
+
return {
|
|
16
|
+
backend: "off" as const,
|
|
17
|
+
active: false,
|
|
18
|
+
writable: false,
|
|
19
|
+
searchable: false,
|
|
20
|
+
message: "No active agent session.",
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
const backend = await resolveMemoryBackend(settings);
|
|
24
|
+
return backend.status
|
|
25
|
+
? await backend.status(context)
|
|
26
|
+
: {
|
|
27
|
+
backend: backend.id,
|
|
28
|
+
active: backend.id !== "off",
|
|
29
|
+
writable: false,
|
|
30
|
+
searchable: false,
|
|
31
|
+
message: "This memory backend does not expose structured status.",
|
|
32
|
+
};
|
|
33
|
+
},
|
|
34
|
+
async search(query: string, options?: MemoryBackendSearchOptions) {
|
|
35
|
+
if (!settings) return unavailableSearch("off", query, "No active agent session.");
|
|
36
|
+
const backend = await resolveMemoryBackend(settings);
|
|
37
|
+
return backend.search
|
|
38
|
+
? await backend.search(context, query, options)
|
|
39
|
+
: unavailableSearch(backend.id, query, `Memory search is not available for the ${backend.id} backend.`);
|
|
40
|
+
},
|
|
41
|
+
async save(input: string | MemoryBackendSaveInput) {
|
|
42
|
+
if (!settings) return unavailableSave("off", "No active agent session.");
|
|
43
|
+
const backend = await resolveMemoryBackend(settings);
|
|
44
|
+
const normalized = typeof input === "string" ? { content: input } : input;
|
|
45
|
+
return backend.save
|
|
46
|
+
? await backend.save(context, normalized)
|
|
47
|
+
: unavailableSave(backend.id, `Memory save is not available for the ${backend.id} backend.`);
|
|
48
|
+
},
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export function createSessionMemoryRuntimeContext(
|
|
53
|
+
session: AgentSession,
|
|
54
|
+
agentDir: string,
|
|
55
|
+
cwd: string,
|
|
56
|
+
): MemoryRuntimeContext {
|
|
57
|
+
return createMemoryRuntimeContext({ agentDir, cwd, session });
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
function unavailableSearch(backend: MemoryBackendId, query: string, message: string) {
|
|
61
|
+
return { backend, query, count: 0, items: [], message };
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
function unavailableSave(backend: MemoryBackendId, message: string) {
|
|
65
|
+
return { backend, stored: 0, message };
|
|
66
|
+
}
|