@oh-my-pi/pi-coding-agent 8.0.20 → 8.2.0
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 +125 -0
- package/docs/session.md +111 -46
- package/examples/custom-tools/hello/index.ts +1 -1
- package/examples/custom-tools/todo/index.ts +3 -4
- package/examples/extensions/api-demo.ts +0 -1
- package/examples/extensions/chalk-logger.ts +2 -3
- package/examples/extensions/hello.ts +0 -1
- package/examples/extensions/pirate.ts +0 -1
- package/examples/extensions/plan-mode.ts +15 -16
- package/examples/extensions/todo.ts +3 -4
- package/examples/extensions/tools.ts +1 -2
- package/examples/extensions/with-deps/index.ts +0 -1
- package/examples/hooks/auto-commit-on-exit.ts +1 -2
- package/examples/hooks/confirm-destructive.ts +0 -1
- package/examples/hooks/custom-compaction.ts +1 -2
- package/examples/hooks/dirty-repo-guard.ts +0 -1
- package/examples/hooks/file-trigger.ts +3 -4
- package/examples/hooks/git-checkpoint.ts +0 -1
- package/examples/hooks/handoff.ts +3 -4
- package/examples/hooks/permission-gate.ts +1 -2
- package/examples/hooks/protected-paths.ts +1 -2
- package/examples/hooks/qna.ts +2 -3
- package/examples/hooks/snake.ts +4 -5
- package/examples/hooks/status-line.ts +0 -1
- package/examples/sdk/01-minimal.ts +2 -3
- package/examples/sdk/02-custom-model.ts +2 -3
- package/examples/sdk/03-custom-prompt.ts +3 -4
- package/examples/sdk/04-skills.ts +2 -3
- package/examples/sdk/06-extensions.ts +1 -2
- package/examples/sdk/06-hooks.ts +6 -7
- package/examples/sdk/07-context-files.ts +0 -1
- package/examples/sdk/08-prompt-templates.ts +0 -1
- package/examples/sdk/08-slash-commands.ts +0 -1
- package/examples/sdk/09-api-keys-and-oauth.ts +0 -1
- package/examples/sdk/10-settings.ts +0 -1
- package/examples/sdk/11-sessions.ts +0 -1
- package/package.json +54 -23
- package/scripts/format-prompts.ts +0 -1
- package/src/capability/context-file.ts +3 -4
- package/src/capability/extension-module.ts +3 -4
- package/src/capability/extension.ts +3 -4
- package/src/capability/fs.ts +20 -21
- package/src/capability/hook.ts +3 -4
- package/src/capability/index.ts +15 -16
- package/src/capability/instruction.ts +3 -4
- package/src/capability/mcp.ts +3 -4
- package/src/capability/prompt.ts +3 -4
- package/src/capability/rule.ts +3 -4
- package/src/capability/settings.ts +2 -3
- package/src/capability/skill.ts +3 -4
- package/src/capability/slash-command.ts +3 -4
- package/src/capability/ssh.ts +3 -4
- package/src/capability/system-prompt.ts +3 -4
- package/src/capability/tool.ts +3 -4
- package/src/cli/args.ts +5 -6
- package/src/cli/config-cli.ts +6 -7
- package/src/cli/file-processor.ts +19 -17
- package/src/cli/jupyter-cli.ts +105 -0
- package/src/cli/list-models.ts +10 -11
- package/src/cli/plugin-cli.ts +20 -25
- package/src/cli/session-picker.ts +2 -3
- package/src/cli/setup-cli.ts +2 -3
- package/src/cli/stats-cli.ts +2 -3
- package/src/cli/update-cli.ts +25 -22
- package/src/commit/agentic/agent.ts +307 -0
- package/src/commit/agentic/fallback.ts +96 -0
- package/src/commit/agentic/index.ts +351 -0
- package/src/commit/agentic/prompts/analyze-file.md +22 -0
- package/src/commit/agentic/prompts/session-user.md +26 -0
- package/src/commit/agentic/prompts/split-confirm.md +1 -0
- package/src/commit/agentic/prompts/system.md +40 -0
- package/src/commit/agentic/state.ts +69 -0
- package/src/commit/agentic/tools/analyze-file.ts +131 -0
- package/src/commit/agentic/tools/git-file-diff.ts +194 -0
- package/src/commit/agentic/tools/git-hunk.ts +50 -0
- package/src/commit/agentic/tools/git-overview.ts +84 -0
- package/src/commit/agentic/tools/index.ts +56 -0
- package/src/commit/agentic/tools/propose-changelog.ts +128 -0
- package/src/commit/agentic/tools/propose-commit.ts +154 -0
- package/src/commit/agentic/tools/recent-commits.ts +81 -0
- package/src/commit/agentic/tools/split-commit.ts +280 -0
- package/src/commit/agentic/topo-sort.ts +44 -0
- package/src/commit/agentic/trivial.ts +51 -0
- package/src/commit/agentic/validation.ts +200 -0
- package/src/commit/analysis/conventional.ts +165 -0
- package/src/commit/analysis/index.ts +4 -0
- package/src/commit/analysis/scope.ts +242 -0
- package/src/commit/analysis/summary.ts +112 -0
- package/src/commit/analysis/validation.ts +66 -0
- package/src/commit/changelog/detect.ts +36 -0
- package/src/commit/changelog/generate.ts +110 -0
- package/src/commit/changelog/index.ts +233 -0
- package/src/commit/changelog/parse.ts +44 -0
- package/src/commit/cli.ts +93 -0
- package/src/commit/git/diff.ts +148 -0
- package/src/commit/git/errors.ts +11 -0
- package/src/commit/git/index.ts +212 -0
- package/src/commit/git/operations.ts +53 -0
- package/src/commit/index.ts +5 -0
- package/src/commit/map-reduce/index.ts +63 -0
- package/src/commit/map-reduce/map-phase.ts +178 -0
- package/src/commit/map-reduce/reduce-phase.ts +145 -0
- package/src/commit/map-reduce/utils.ts +9 -0
- package/src/commit/message.ts +11 -0
- package/src/commit/model-selection.ts +80 -0
- package/src/commit/pipeline.ts +240 -0
- package/src/commit/prompts/analysis-system.md +155 -0
- package/src/commit/prompts/analysis-user.md +41 -0
- package/src/commit/prompts/changelog-system.md +56 -0
- package/src/commit/prompts/changelog-user.md +19 -0
- package/src/commit/prompts/file-observer-system.md +26 -0
- package/src/commit/prompts/file-observer-user.md +9 -0
- package/src/commit/prompts/reduce-system.md +60 -0
- package/src/commit/prompts/reduce-user.md +17 -0
- package/src/commit/prompts/summary-retry.md +4 -0
- package/src/commit/prompts/summary-system.md +52 -0
- package/src/commit/prompts/summary-user.md +13 -0
- package/src/commit/prompts/types-description.md +2 -0
- package/src/commit/types.ts +109 -0
- package/src/commit/utils/exclusions.ts +42 -0
- package/src/config/file-lock.ts +121 -0
- package/src/config/keybindings.ts +6 -8
- package/src/config/model-registry.ts +65 -38
- package/src/config/model-resolver.ts +18 -19
- package/src/config/prompt-templates.ts +11 -11
- package/src/config/settings-manager.ts +141 -50
- package/src/config.ts +64 -66
- package/src/cursor.ts +11 -9
- package/src/discovery/agents-md.ts +11 -12
- package/src/discovery/builtin.ts +68 -73
- package/src/discovery/claude.ts +41 -42
- package/src/discovery/cline.ts +11 -12
- package/src/discovery/codex.ts +52 -53
- package/src/discovery/cursor.ts +9 -10
- package/src/discovery/gemini.ts +17 -22
- package/src/discovery/github.ts +13 -14
- package/src/discovery/helpers.ts +35 -34
- package/src/discovery/index.ts +22 -24
- package/src/discovery/mcp-json.ts +8 -9
- package/src/discovery/ssh.ts +8 -9
- package/src/discovery/vscode.ts +4 -5
- package/src/discovery/windsurf.ts +6 -7
- package/src/exa/company.ts +1 -2
- package/src/exa/index.ts +2 -3
- package/src/exa/linkedin.ts +1 -2
- package/src/exa/mcp-client.ts +14 -16
- package/src/exa/render.ts +10 -11
- package/src/exa/researcher.ts +1 -2
- package/src/exa/search.ts +1 -2
- package/src/exa/types.ts +0 -1
- package/src/exa/websets.ts +1 -2
- package/src/exec/bash-executor.ts +3 -4
- package/src/exec/exec.ts +0 -1
- package/src/export/custom-share.ts +5 -6
- package/src/export/html/index.ts +24 -21
- package/src/export/ttsr.ts +2 -3
- package/src/extensibility/custom-commands/bundled/review/index.ts +7 -8
- package/src/extensibility/custom-commands/loader.ts +18 -15
- package/src/extensibility/custom-commands/types.ts +2 -3
- package/src/extensibility/custom-tools/loader.ts +11 -12
- package/src/extensibility/custom-tools/types.ts +7 -8
- package/src/extensibility/custom-tools/wrapper.ts +2 -3
- package/src/extensibility/extensions/loader.ts +76 -54
- package/src/extensibility/extensions/runner.ts +11 -12
- package/src/extensibility/extensions/types.ts +20 -27
- package/src/extensibility/extensions/wrapper.ts +3 -4
- package/src/extensibility/hooks/index.ts +1 -1
- package/src/extensibility/hooks/loader.ts +9 -10
- package/src/extensibility/hooks/runner.ts +7 -8
- package/src/extensibility/hooks/tool-wrapper.ts +0 -1
- package/src/extensibility/hooks/types.ts +11 -18
- package/src/extensibility/plugins/doctor.ts +3 -3
- package/src/extensibility/plugins/installer.ts +27 -27
- package/src/extensibility/plugins/loader.ts +59 -56
- package/src/extensibility/plugins/manager.ts +211 -171
- package/src/extensibility/plugins/parser.ts +1 -1
- package/src/extensibility/plugins/paths.ts +8 -8
- package/src/extensibility/skills.ts +63 -60
- package/src/extensibility/slash-commands.ts +10 -10
- package/src/index.ts +54 -54
- package/src/internal-urls/agent-protocol.ts +21 -11
- package/src/internal-urls/artifact-protocol.ts +17 -13
- package/src/internal-urls/router.ts +1 -2
- package/src/internal-urls/rule-protocol.ts +3 -4
- package/src/internal-urls/skill-protocol.ts +3 -4
- package/src/ipy/executor.ts +109 -9
- package/src/ipy/gateway-coordinator.ts +79 -90
- package/src/ipy/kernel.ts +32 -30
- package/src/ipy/modules.ts +13 -13
- package/src/lsp/client.ts +21 -10
- package/src/lsp/clients/biome-client.ts +1 -2
- package/src/lsp/clients/index.ts +3 -3
- package/src/lsp/clients/lsp-linter-client.ts +4 -5
- package/src/lsp/config.ts +15 -15
- package/src/lsp/edits.ts +4 -5
- package/src/lsp/index.ts +43 -44
- package/src/lsp/lspmux.ts +8 -8
- package/src/lsp/render.ts +99 -61
- package/src/lsp/utils.ts +3 -3
- package/src/main.ts +71 -37
- package/src/mcp/client.ts +2 -3
- package/src/mcp/config.ts +5 -6
- package/src/mcp/json-rpc.ts +0 -1
- package/src/mcp/loader.ts +6 -7
- package/src/mcp/manager.ts +17 -18
- package/src/mcp/tool-bridge.ts +4 -9
- package/src/mcp/tool-cache.ts +2 -3
- package/src/mcp/transports/http.ts +2 -4
- package/src/mcp/transports/stdio.ts +1 -2
- package/src/migrations.ts +63 -52
- package/src/modes/components/armin.ts +4 -5
- package/src/modes/components/assistant-message.ts +33 -5
- package/src/modes/components/bash-execution.ts +7 -8
- package/src/modes/components/bordered-loader.ts +3 -3
- package/src/modes/components/branch-summary-message.ts +3 -3
- package/src/modes/components/compaction-summary-message.ts +3 -3
- package/src/modes/components/countdown-timer.ts +0 -1
- package/src/modes/components/custom-message.ts +5 -5
- package/src/modes/components/diff.ts +1 -1
- package/src/modes/components/dynamic-border.ts +2 -2
- package/src/modes/components/extensions/extension-dashboard.ts +6 -7
- package/src/modes/components/extensions/extension-list.ts +2 -3
- package/src/modes/components/extensions/inspector-panel.ts +3 -4
- package/src/modes/components/extensions/state-manager.ts +25 -26
- package/src/modes/components/extensions/types.ts +1 -2
- package/src/modes/components/footer.ts +47 -43
- package/src/modes/components/history-search.ts +2 -2
- package/src/modes/components/hook-editor.ts +3 -4
- package/src/modes/components/hook-input.ts +2 -3
- package/src/modes/components/hook-message.ts +5 -5
- package/src/modes/components/hook-selector.ts +2 -3
- package/src/modes/components/keybinding-hints.ts +2 -3
- package/src/modes/components/login-dialog.ts +2 -2
- package/src/modes/components/model-selector.ts +12 -12
- package/src/modes/components/oauth-selector.ts +2 -2
- package/src/modes/components/plugin-settings.ts +20 -20
- package/src/modes/components/python-execution.ts +7 -8
- package/src/modes/components/queue-mode-selector.ts +3 -3
- package/src/modes/components/read-tool-group.ts +2 -2
- package/src/modes/components/session-selector.ts +4 -4
- package/src/modes/components/settings-defs.ts +77 -69
- package/src/modes/components/settings-selector.ts +16 -16
- package/src/modes/components/show-images-selector.ts +2 -2
- package/src/modes/components/status-line/segments.ts +4 -4
- package/src/modes/components/status-line/separators.ts +1 -1
- package/src/modes/components/status-line/types.ts +2 -2
- package/src/modes/components/status-line-segment-editor.ts +7 -8
- package/src/modes/components/status-line.ts +12 -12
- package/src/modes/components/theme-selector.ts +8 -7
- package/src/modes/components/thinking-selector.ts +4 -4
- package/src/modes/components/todo-display.ts +2 -2
- package/src/modes/components/todo-reminder.ts +4 -4
- package/src/modes/components/tool-execution.ts +16 -19
- package/src/modes/components/tree-selector.ts +12 -12
- package/src/modes/components/ttsr-notification.ts +5 -5
- package/src/modes/components/user-message-selector.ts +1 -1
- package/src/modes/components/user-message.ts +1 -1
- package/src/modes/components/visual-truncate.ts +0 -1
- package/src/modes/components/welcome.ts +4 -4
- package/src/modes/controllers/command-controller.ts +46 -47
- package/src/modes/controllers/event-controller.ts +16 -20
- package/src/modes/controllers/extension-ui-controller.ts +40 -46
- package/src/modes/controllers/input-controller.ts +17 -18
- package/src/modes/controllers/selector-controller.ts +103 -91
- package/src/modes/index.ts +3 -3
- package/src/modes/interactive-mode.ts +31 -31
- package/src/modes/print-mode.ts +12 -13
- package/src/modes/rpc/rpc-client.ts +7 -8
- package/src/modes/rpc/rpc-mode.ts +24 -28
- package/src/modes/rpc/rpc-types.ts +3 -4
- package/src/modes/theme/mermaid-cache.ts +89 -0
- package/src/modes/theme/theme.ts +130 -53
- package/src/modes/types.ts +10 -10
- package/src/modes/utils/ui-helpers.ts +17 -17
- package/src/patch/applicator.ts +18 -19
- package/src/patch/diff.ts +1 -2
- package/src/patch/fuzzy.ts +1 -2
- package/src/patch/index.ts +11 -18
- package/src/patch/normalize.ts +4 -4
- package/src/patch/normative.ts +1 -2
- package/src/patch/parser.ts +8 -9
- package/src/patch/shared.ts +43 -16
- package/src/prompts/tools/task.md +2 -0
- package/src/sdk.ts +100 -65
- package/src/session/agent-session.ts +84 -85
- package/src/session/agent-storage.ts +43 -39
- package/src/session/artifacts.ts +32 -10
- package/src/session/auth-storage.ts +50 -39
- package/src/session/compaction/branch-summarization.ts +7 -10
- package/src/session/compaction/compaction.ts +8 -19
- package/src/session/compaction/utils.ts +6 -9
- package/src/session/history-storage.ts +10 -10
- package/src/session/messages.ts +4 -5
- package/src/session/session-manager.ts +76 -65
- package/src/session/session-storage.ts +57 -69
- package/src/session/storage-migration.ts +14 -56
- package/src/session/streaming-output.ts +2 -2
- package/src/ssh/connection-manager.ts +43 -50
- package/src/ssh/ssh-executor.ts +2 -2
- package/src/ssh/sshfs-mount.ts +11 -18
- package/src/system-prompt.ts +28 -35
- package/src/task/agents.ts +45 -30
- package/src/task/commands.ts +6 -7
- package/src/task/discovery.ts +39 -76
- package/src/task/executor.ts +14 -15
- package/src/task/index.ts +40 -34
- package/src/task/output-manager.ts +93 -0
- package/src/task/parallel.ts +0 -1
- package/src/task/render.ts +24 -30
- package/src/task/subprocess-tool-registry.ts +1 -2
- package/src/task/worker-protocol.ts +3 -3
- package/src/task/worker.ts +33 -39
- package/src/task/worktree.ts +19 -19
- package/src/tools/ask.ts +41 -20
- package/src/tools/bash-interceptor.ts +1 -5
- package/src/tools/bash.ts +91 -97
- package/src/tools/calculator.ts +49 -47
- package/src/tools/complete.ts +4 -5
- package/src/tools/context.ts +2 -2
- package/src/tools/fetch.ts +84 -124
- package/src/tools/find.ts +94 -98
- package/src/tools/gemini-image.ts +14 -14
- package/src/tools/grep.ts +100 -116
- package/src/tools/index.ts +80 -55
- package/src/tools/list-limit.ts +1 -1
- package/src/tools/ls.ts +44 -70
- package/src/tools/notebook.ts +51 -67
- package/src/tools/output-meta.ts +3 -4
- package/src/tools/output-utils.ts +2 -2
- package/src/tools/path-utils.ts +5 -5
- package/src/tools/python.ts +104 -217
- package/src/tools/read.ts +92 -33
- package/src/tools/render-utils.ts +8 -23
- package/src/tools/renderers.ts +6 -7
- package/src/tools/review.ts +8 -11
- package/src/tools/ssh.ts +69 -49
- package/src/tools/todo-write.ts +37 -25
- package/src/tools/tool-errors.ts +3 -3
- package/src/tools/tool-result.ts +3 -8
- package/src/tools/write.ts +99 -75
- package/src/tui/code-cell.ts +109 -0
- package/src/tui/file-list.ts +47 -0
- package/src/tui/index.ts +11 -0
- package/src/tui/output-block.ts +72 -0
- package/src/tui/status-line.ts +39 -0
- package/src/tui/tree-list.ts +55 -0
- package/src/tui/types.ts +16 -0
- package/src/tui/utils.ts +48 -0
- package/src/utils/changelog.ts +9 -10
- package/src/utils/clipboard.ts +11 -11
- package/src/utils/file-mentions.ts +4 -10
- package/src/utils/frontmatter.ts +6 -3
- package/src/utils/fuzzy.ts +2 -2
- package/src/utils/image-convert.ts +1 -1
- package/src/utils/image-resize.ts +1 -1
- package/src/utils/mime.ts +2 -2
- package/src/utils/shell-snapshot.ts +11 -13
- package/src/utils/shell.ts +4 -5
- package/src/utils/title-generator.ts +8 -9
- package/src/utils/tools-manager.ts +23 -23
- package/src/vendor/photon/index.js +1099 -1059
- package/src/vendor/photon/photon_rs_bg.wasm +0 -0
- package/src/web/scrapers/artifacthub.ts +1 -1
- package/src/web/scrapers/arxiv.ts +2 -2
- package/src/web/scrapers/bluesky.ts +2 -2
- package/src/web/scrapers/cheatsh.ts +1 -1
- package/src/web/scrapers/chocolatey.ts +2 -2
- package/src/web/scrapers/choosealicense.ts +5 -5
- package/src/web/scrapers/cisa-kev.ts +1 -1
- package/src/web/scrapers/crossref.ts +2 -2
- package/src/web/scrapers/devto.ts +3 -3
- package/src/web/scrapers/discogs.ts +3 -4
- package/src/web/scrapers/discourse.ts +1 -1
- package/src/web/scrapers/dockerhub.ts +1 -1
- package/src/web/scrapers/fdroid.ts +2 -2
- package/src/web/scrapers/firefox-addons.ts +3 -3
- package/src/web/scrapers/flathub.ts +1 -1
- package/src/web/scrapers/github.ts +3 -3
- package/src/web/scrapers/gitlab.ts +4 -4
- package/src/web/scrapers/hackernews.ts +2 -2
- package/src/web/scrapers/huggingface.ts +1 -1
- package/src/web/scrapers/iacr.ts +2 -2
- package/src/web/scrapers/index.ts +0 -1
- package/src/web/scrapers/jetbrains-marketplace.ts +1 -1
- package/src/web/scrapers/lemmy.ts +2 -2
- package/src/web/scrapers/maven.ts +2 -2
- package/src/web/scrapers/mdn.ts +2 -4
- package/src/web/scrapers/metacpan.ts +2 -2
- package/src/web/scrapers/musicbrainz.ts +1 -2
- package/src/web/scrapers/npm.ts +1 -1
- package/src/web/scrapers/nuget.ts +2 -2
- package/src/web/scrapers/nvd.ts +3 -3
- package/src/web/scrapers/ollama.ts +7 -9
- package/src/web/scrapers/opencorporates.ts +2 -2
- package/src/web/scrapers/openlibrary.ts +6 -6
- package/src/web/scrapers/orcid.ts +0 -1
- package/src/web/scrapers/osv.ts +2 -2
- package/src/web/scrapers/packagist.ts +1 -1
- package/src/web/scrapers/pubmed.ts +1 -2
- package/src/web/scrapers/rawg.ts +2 -2
- package/src/web/scrapers/readthedocs.ts +1 -2
- package/src/web/scrapers/repology.ts +2 -2
- package/src/web/scrapers/rfc.ts +1 -1
- package/src/web/scrapers/searchcode.ts +2 -2
- package/src/web/scrapers/semantic-scholar.ts +1 -1
- package/src/web/scrapers/snapcraft.ts +2 -2
- package/src/web/scrapers/sourcegraph.ts +1 -1
- package/src/web/scrapers/spdx.ts +3 -3
- package/src/web/scrapers/spotify.ts +0 -1
- package/src/web/scrapers/twitter.ts +1 -1
- package/src/web/scrapers/types.ts +1 -2
- package/src/web/scrapers/utils.ts +5 -5
- package/src/web/scrapers/wikidata.ts +3 -3
- package/src/web/scrapers/youtube.ts +9 -14
- package/src/web/search/auth.ts +5 -10
- package/src/web/search/index.ts +11 -21
- package/src/web/search/providers/anthropic.ts +3 -9
- package/src/web/search/providers/exa.ts +6 -10
- package/src/web/search/providers/perplexity.ts +5 -5
- package/src/web/search/render.ts +129 -175
- package/tsconfig.json +0 -42
package/src/lsp/utils.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import path from "node:path";
|
|
2
|
-
import { type Theme, theme } from "
|
|
2
|
+
import { type Theme, theme } from "../modes/theme/theme";
|
|
3
3
|
import type {
|
|
4
4
|
Diagnostic,
|
|
5
5
|
DiagnosticSeverity,
|
|
@@ -232,7 +232,7 @@ export function severityToIcon(severity?: DiagnosticSeverity): string {
|
|
|
232
232
|
function stripDiagnosticNoise(message: string): string {
|
|
233
233
|
return message
|
|
234
234
|
.split("\n")
|
|
235
|
-
.filter(
|
|
235
|
+
.filter(line => {
|
|
236
236
|
const trimmed = line.trim();
|
|
237
237
|
// Skip "for further information visit <url>" lines
|
|
238
238
|
if (trimmed.startsWith("for further information visit")) return false;
|
|
@@ -491,7 +491,7 @@ export function extractHoverText(
|
|
|
491
491
|
}
|
|
492
492
|
|
|
493
493
|
if (Array.isArray(contents)) {
|
|
494
|
-
return contents.map(
|
|
494
|
+
return contents.map(c => extractHoverText(c as string | { kind: string; value: string })).join("\n\n");
|
|
495
495
|
}
|
|
496
496
|
|
|
497
497
|
if (typeof contents === "object" && contents !== null) {
|
package/src/main.ts
CHANGED
|
@@ -4,32 +4,35 @@
|
|
|
4
4
|
* This file handles CLI argument parsing and translates them into
|
|
5
5
|
* createAgentSession() options. The SDK does the heavy lifting.
|
|
6
6
|
*/
|
|
7
|
-
|
|
8
|
-
import
|
|
9
|
-
import
|
|
7
|
+
import * as fs from "node:fs/promises";
|
|
8
|
+
import * as os from "node:os";
|
|
9
|
+
import * as path from "node:path";
|
|
10
10
|
import { createInterface } from "node:readline/promises";
|
|
11
11
|
import { type ImageContent, supportsXhigh } from "@oh-my-pi/pi-ai";
|
|
12
|
-
import { initTheme, stopThemeWatcher } from "@oh-my-pi/pi-coding-agent/modes/theme/theme";
|
|
13
12
|
import { postmortem } from "@oh-my-pi/pi-utils";
|
|
14
13
|
import chalk from "chalk";
|
|
15
14
|
import { type Args, parseArgs, printHelp } from "./cli/args";
|
|
16
15
|
import { parseConfigArgs, printConfigHelp, runConfigCommand } from "./cli/config-cli";
|
|
17
16
|
import { processFileArguments } from "./cli/file-processor";
|
|
17
|
+
import { parseJupyterArgs, printJupyterHelp, runJupyterCommand } from "./cli/jupyter-cli";
|
|
18
18
|
import { listModels } from "./cli/list-models";
|
|
19
19
|
import { parsePluginArgs, printPluginHelp, runPluginCommand } from "./cli/plugin-cli";
|
|
20
20
|
import { selectSession } from "./cli/session-picker";
|
|
21
21
|
import { parseSetupArgs, printSetupHelp, runSetupCommand } from "./cli/setup-cli";
|
|
22
22
|
import { parseStatsArgs, printStatsHelp, runStatsCommand } from "./cli/stats-cli";
|
|
23
23
|
import { parseUpdateArgs, printUpdateHelp, runUpdateCommand } from "./cli/update-cli";
|
|
24
|
+
import { runCommitCommand } from "./commit";
|
|
25
|
+
import { parseCommitArgs, printCommitHelp } from "./commit/cli";
|
|
24
26
|
import { findConfigFile, getModelsPath, VERSION } from "./config";
|
|
25
27
|
import type { ModelRegistry } from "./config/model-registry";
|
|
26
28
|
import { parseModelPattern, parseModelString, resolveModelScope, type ScopedModel } from "./config/model-resolver";
|
|
27
29
|
import { SettingsManager } from "./config/settings-manager";
|
|
28
30
|
import { initializeWithSettings } from "./discovery";
|
|
29
|
-
import { exportFromFile } from "./export/html
|
|
31
|
+
import { exportFromFile } from "./export/html";
|
|
30
32
|
import type { ExtensionUIContext } from "./extensibility/extensions/types";
|
|
31
33
|
import { runMigrations, showDeprecationWarnings } from "./migrations";
|
|
32
|
-
import { InteractiveMode, runPrintMode, runRpcMode } from "./modes
|
|
34
|
+
import { InteractiveMode, runPrintMode, runRpcMode } from "./modes";
|
|
35
|
+
import { initTheme, stopThemeWatcher } from "./modes/theme/theme";
|
|
33
36
|
import { type CreateAgentSessionOptions, createAgentSession, discoverAuthStorage, discoverModels } from "./sdk";
|
|
34
37
|
import type { AgentSession } from "./session/agent-session";
|
|
35
38
|
import { type SessionInfo, SessionManager } from "./session/session-manager";
|
|
@@ -85,7 +88,7 @@ async function runInteractiveMode(
|
|
|
85
88
|
initialMessages: string[],
|
|
86
89
|
setExtensionUIContext: (uiContext: ExtensionUIContext, hasUI: boolean) => void,
|
|
87
90
|
lspServers: Array<{ name: string; status: "ready" | "error"; fileTypes: string[] }> | undefined,
|
|
88
|
-
mcpManager: import("./mcp
|
|
91
|
+
mcpManager: import("./mcp").MCPManager | undefined,
|
|
89
92
|
initialMessage?: string,
|
|
90
93
|
initialImages?: ImageContent[],
|
|
91
94
|
): Promise<void> {
|
|
@@ -94,7 +97,7 @@ async function runInteractiveMode(
|
|
|
94
97
|
await mode.init();
|
|
95
98
|
|
|
96
99
|
versionCheckPromise
|
|
97
|
-
.then(
|
|
100
|
+
.then(newVersion => {
|
|
98
101
|
if (newVersion) {
|
|
99
102
|
mode.showNewVersionNotification(newVersion);
|
|
100
103
|
}
|
|
@@ -174,13 +177,17 @@ async function prepareInitialMessage(
|
|
|
174
177
|
/**
|
|
175
178
|
* Resolve a session argument to a local or global session match.
|
|
176
179
|
*/
|
|
177
|
-
function resolveSessionMatch(
|
|
178
|
-
|
|
179
|
-
|
|
180
|
+
async function resolveSessionMatch(
|
|
181
|
+
sessionArg: string,
|
|
182
|
+
cwd: string,
|
|
183
|
+
sessionDir?: string,
|
|
184
|
+
): Promise<SessionInfo | undefined> {
|
|
185
|
+
const sessions = await SessionManager.list(cwd, sessionDir);
|
|
186
|
+
let matches = sessions.filter(session => session.id.startsWith(sessionArg));
|
|
180
187
|
|
|
181
188
|
if (matches.length === 0 && !sessionDir) {
|
|
182
|
-
const globalSessions = SessionManager.listAll();
|
|
183
|
-
matches = globalSessions.filter(
|
|
189
|
+
const globalSessions = await SessionManager.listAll();
|
|
190
|
+
matches = globalSessions.filter(session => session.id.startsWith(sessionArg));
|
|
184
191
|
}
|
|
185
192
|
|
|
186
193
|
return matches[0];
|
|
@@ -200,25 +207,25 @@ async function promptForkSession(session: SessionInfo): Promise<boolean> {
|
|
|
200
207
|
}
|
|
201
208
|
}
|
|
202
209
|
|
|
203
|
-
function getChangelogForDisplay(parsed: Args, settingsManager: SettingsManager): string | undefined {
|
|
210
|
+
async function getChangelogForDisplay(parsed: Args, settingsManager: SettingsManager): Promise<string | undefined> {
|
|
204
211
|
if (parsed.continue || parsed.resume) {
|
|
205
212
|
return undefined;
|
|
206
213
|
}
|
|
207
214
|
|
|
208
215
|
const lastVersion = settingsManager.getLastChangelogVersion();
|
|
209
216
|
const changelogPath = getChangelogPath();
|
|
210
|
-
const entries = parseChangelog(changelogPath);
|
|
217
|
+
const entries = await parseChangelog(changelogPath);
|
|
211
218
|
|
|
212
219
|
if (!lastVersion) {
|
|
213
220
|
if (entries.length > 0) {
|
|
214
221
|
settingsManager.setLastChangelogVersion(VERSION);
|
|
215
|
-
return entries.map(
|
|
222
|
+
return entries.map(e => e.content).join("\n\n");
|
|
216
223
|
}
|
|
217
224
|
} else {
|
|
218
225
|
const newEntries = getNewEntries(entries, lastVersion);
|
|
219
226
|
if (newEntries.length > 0) {
|
|
220
227
|
settingsManager.setLastChangelogVersion(VERSION);
|
|
221
|
-
return newEntries.map(
|
|
228
|
+
return newEntries.map(e => e.content).join("\n\n");
|
|
222
229
|
}
|
|
223
230
|
}
|
|
224
231
|
|
|
@@ -234,12 +241,12 @@ async function createSessionManager(parsed: Args, cwd: string): Promise<SessionM
|
|
|
234
241
|
if (sessionArg.includes("/") || sessionArg.includes("\\") || sessionArg.endsWith(".jsonl")) {
|
|
235
242
|
return await SessionManager.open(sessionArg, parsed.sessionDir);
|
|
236
243
|
}
|
|
237
|
-
const match = resolveSessionMatch(sessionArg, cwd, parsed.sessionDir);
|
|
244
|
+
const match = await resolveSessionMatch(sessionArg, cwd, parsed.sessionDir);
|
|
238
245
|
if (!match) {
|
|
239
246
|
throw new Error(`Session "${sessionArg}" not found.`);
|
|
240
247
|
}
|
|
241
|
-
const normalizedCwd = resolve(cwd);
|
|
242
|
-
const normalizedMatchCwd = resolve(match.cwd || cwd);
|
|
248
|
+
const normalizedCwd = path.resolve(cwd);
|
|
249
|
+
const normalizedMatchCwd = path.resolve(match.cwd || cwd);
|
|
243
250
|
if (normalizedCwd !== normalizedMatchCwd) {
|
|
244
251
|
const shouldFork = await promptForkSession(match);
|
|
245
252
|
if (!shouldFork) {
|
|
@@ -266,13 +273,13 @@ async function maybeAutoChdir(parsed: Args): Promise<void> {
|
|
|
266
273
|
return;
|
|
267
274
|
}
|
|
268
275
|
|
|
269
|
-
const home = homedir();
|
|
276
|
+
const home = os.homedir();
|
|
270
277
|
if (!home) {
|
|
271
278
|
return;
|
|
272
279
|
}
|
|
273
280
|
|
|
274
281
|
const normalizePath = (value: string) => {
|
|
275
|
-
const resolved = resolve(value);
|
|
282
|
+
const resolved = path.resolve(value);
|
|
276
283
|
return process.platform === "win32" ? resolved.toLowerCase() : resolved;
|
|
277
284
|
};
|
|
278
285
|
|
|
@@ -282,16 +289,16 @@ async function maybeAutoChdir(parsed: Args): Promise<void> {
|
|
|
282
289
|
return;
|
|
283
290
|
}
|
|
284
291
|
|
|
285
|
-
const isDirectory = async (
|
|
292
|
+
const isDirectory = async (p: string) => {
|
|
286
293
|
try {
|
|
287
|
-
const
|
|
288
|
-
return
|
|
294
|
+
const s = await fs.stat(p);
|
|
295
|
+
return s.isDirectory();
|
|
289
296
|
} catch {
|
|
290
297
|
return false;
|
|
291
298
|
}
|
|
292
299
|
};
|
|
293
300
|
|
|
294
|
-
const candidates = [join(home, "tmp"), "/tmp", "/var/tmp"];
|
|
301
|
+
const candidates = [path.join(home, "tmp"), "/tmp", "/var/tmp"];
|
|
295
302
|
for (const candidate of candidates) {
|
|
296
303
|
try {
|
|
297
304
|
if (!(await isDirectory(candidate))) {
|
|
@@ -305,7 +312,7 @@ async function maybeAutoChdir(parsed: Args): Promise<void> {
|
|
|
305
312
|
}
|
|
306
313
|
|
|
307
314
|
try {
|
|
308
|
-
const fallback = tmpdir();
|
|
315
|
+
const fallback = os.tmpdir();
|
|
309
316
|
if (fallback && normalizePath(fallback) !== cwd && (await isDirectory(fallback))) {
|
|
310
317
|
process.chdir(fallback);
|
|
311
318
|
}
|
|
@@ -384,10 +391,10 @@ async function buildSessionOptions(
|
|
|
384
391
|
const parsedModel = parseModelString(remembered);
|
|
385
392
|
const rememberedModel = parsedModel
|
|
386
393
|
? scopedModels.find(
|
|
387
|
-
|
|
394
|
+
scopedModel =>
|
|
388
395
|
scopedModel.model.provider === parsedModel.provider && scopedModel.model.id === parsedModel.id,
|
|
389
396
|
)
|
|
390
|
-
: scopedModels.find(
|
|
397
|
+
: scopedModels.find(scopedModel => scopedModel.model.id.toLowerCase() === remembered.toLowerCase());
|
|
391
398
|
if (rememberedModel) {
|
|
392
399
|
options.model = rememberedModel.model;
|
|
393
400
|
}
|
|
@@ -412,7 +419,7 @@ async function buildSessionOptions(
|
|
|
412
419
|
// Scoped models for Ctrl+P cycling - fill in default thinking levels when not explicit
|
|
413
420
|
if (scopedModels.length > 0) {
|
|
414
421
|
const defaultThinkingLevel = settingsManager.getDefaultThinkingLevel() ?? "off";
|
|
415
|
-
options.scopedModels = scopedModels.map(
|
|
422
|
+
options.scopedModels = scopedModels.map(scopedModel => ({
|
|
416
423
|
model: scopedModel.model,
|
|
417
424
|
thinkingLevel: scopedModel.explicitThinkingLevel
|
|
418
425
|
? (scopedModel.thinkingLevel ?? defaultThinkingLevel)
|
|
@@ -429,7 +436,7 @@ async function buildSessionOptions(
|
|
|
429
436
|
} else if (resolvedSystemPrompt) {
|
|
430
437
|
options.systemPrompt = resolvedSystemPrompt;
|
|
431
438
|
} else if (resolvedAppendPrompt) {
|
|
432
|
-
options.systemPrompt =
|
|
439
|
+
options.systemPrompt = defaultPrompt => `${defaultPrompt}\n\n${resolvedAppendPrompt}`;
|
|
433
440
|
}
|
|
434
441
|
|
|
435
442
|
// Tools
|
|
@@ -475,7 +482,7 @@ export async function main(args: string[]) {
|
|
|
475
482
|
|
|
476
483
|
// Initialize theme early with defaults (CLI commands need symbols)
|
|
477
484
|
// Will be re-initialized with user preferences later
|
|
478
|
-
initTheme();
|
|
485
|
+
await initTheme();
|
|
479
486
|
|
|
480
487
|
// Handle plugin subcommand before regular parsing
|
|
481
488
|
const pluginCmd = parsePluginArgs(args);
|
|
@@ -521,6 +528,17 @@ export async function main(args: string[]) {
|
|
|
521
528
|
return;
|
|
522
529
|
}
|
|
523
530
|
|
|
531
|
+
// Handle jupyter subcommand
|
|
532
|
+
const jupyterCmd = parseJupyterArgs(args);
|
|
533
|
+
if (jupyterCmd) {
|
|
534
|
+
if (args.includes("--help") || args.includes("-h")) {
|
|
535
|
+
printJupyterHelp();
|
|
536
|
+
return;
|
|
537
|
+
}
|
|
538
|
+
await runJupyterCommand(jupyterCmd);
|
|
539
|
+
return;
|
|
540
|
+
}
|
|
541
|
+
|
|
524
542
|
// Handle stats subcommand
|
|
525
543
|
const statsCmd = parseStatsArgs(args);
|
|
526
544
|
if (statsCmd) {
|
|
@@ -532,6 +550,17 @@ export async function main(args: string[]) {
|
|
|
532
550
|
return;
|
|
533
551
|
}
|
|
534
552
|
|
|
553
|
+
// Handle commit subcommand
|
|
554
|
+
const commitCmd = parseCommitArgs(args);
|
|
555
|
+
if (commitCmd) {
|
|
556
|
+
if (args.includes("--help") || args.includes("-h")) {
|
|
557
|
+
printCommitHelp();
|
|
558
|
+
return;
|
|
559
|
+
}
|
|
560
|
+
await runCommitCommand(commitCmd);
|
|
561
|
+
process.exit(0);
|
|
562
|
+
}
|
|
563
|
+
|
|
535
564
|
const parsed = parseArgs(args);
|
|
536
565
|
time("parseArgs");
|
|
537
566
|
await maybeAutoChdir(parsed);
|
|
@@ -541,7 +570,7 @@ export async function main(args: string[]) {
|
|
|
541
570
|
|
|
542
571
|
// Create AuthStorage and ModelRegistry upfront
|
|
543
572
|
const authStorage = await discoverAuthStorage();
|
|
544
|
-
const modelRegistry =
|
|
573
|
+
const modelRegistry = discoverModels(authStorage);
|
|
545
574
|
time("discoverModels");
|
|
546
575
|
|
|
547
576
|
if (parsed.version) {
|
|
@@ -606,7 +635,12 @@ export async function main(args: string[]) {
|
|
|
606
635
|
settingsManager.applyOverrides({ modelRoles: roleOverrides });
|
|
607
636
|
}
|
|
608
637
|
|
|
609
|
-
initTheme(
|
|
638
|
+
await initTheme(
|
|
639
|
+
settingsManager.getTheme(),
|
|
640
|
+
isInteractive,
|
|
641
|
+
settingsManager.getSymbolPreset(),
|
|
642
|
+
settingsManager.getColorBlindMode(),
|
|
643
|
+
);
|
|
610
644
|
time("initTheme");
|
|
611
645
|
|
|
612
646
|
// Show deprecation warnings in interactive mode
|
|
@@ -627,7 +661,7 @@ export async function main(args: string[]) {
|
|
|
627
661
|
|
|
628
662
|
// Handle --resume: show session picker
|
|
629
663
|
if (parsed.resume) {
|
|
630
|
-
const sessions = SessionManager.list(cwd, parsed.sessionDir);
|
|
664
|
+
const sessions = await SessionManager.list(cwd, parsed.sessionDir);
|
|
631
665
|
time("SessionManager.list");
|
|
632
666
|
if (sessions.length === 0) {
|
|
633
667
|
writeStdout(chalk.dim("No sessions found"));
|
|
@@ -709,12 +743,12 @@ export async function main(args: string[]) {
|
|
|
709
743
|
await runRpcMode(session);
|
|
710
744
|
} else if (isInteractive) {
|
|
711
745
|
const versionCheckPromise = checkForNewVersion(VERSION).catch(() => undefined);
|
|
712
|
-
const changelogMarkdown = getChangelogForDisplay(parsed, settingsManager);
|
|
746
|
+
const changelogMarkdown = await getChangelogForDisplay(parsed, settingsManager);
|
|
713
747
|
|
|
714
748
|
const scopedModelsForDisplay = sessionOptions.scopedModels ?? scopedModels;
|
|
715
749
|
if (scopedModelsForDisplay.length > 0) {
|
|
716
750
|
const modelList = scopedModelsForDisplay
|
|
717
|
-
.map(
|
|
751
|
+
.map(scopedModel => {
|
|
718
752
|
const thinkingStr = scopedModel.thinkingLevel !== "off" ? `:${scopedModel.thinkingLevel}` : "";
|
|
719
753
|
return `${scopedModel.model.id}${thinkingStr}`;
|
|
720
754
|
})
|
package/src/mcp/client.ts
CHANGED
|
@@ -3,7 +3,6 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Handles connection initialization, tool listing, and tool calling.
|
|
5
5
|
*/
|
|
6
|
-
|
|
7
6
|
import { createHttpTransport } from "./transports/http";
|
|
8
7
|
import { createStdioTransport } from "./transports/stdio";
|
|
9
8
|
import type {
|
|
@@ -39,11 +38,11 @@ function withTimeout<T>(promise: Promise<T>, ms: number, message: string): Promi
|
|
|
39
38
|
const { promise: wrapped, resolve, reject } = Promise.withResolvers<T>();
|
|
40
39
|
const timer = setTimeout(() => reject(new Error(message)), ms);
|
|
41
40
|
promise.then(
|
|
42
|
-
|
|
41
|
+
value => {
|
|
43
42
|
clearTimeout(timer);
|
|
44
43
|
resolve(value);
|
|
45
44
|
},
|
|
46
|
-
|
|
45
|
+
error => {
|
|
47
46
|
clearTimeout(timer);
|
|
48
47
|
reject(error);
|
|
49
48
|
},
|
package/src/mcp/config.ts
CHANGED
|
@@ -3,10 +3,9 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Uses the capability system to load MCP servers from multiple sources.
|
|
5
5
|
*/
|
|
6
|
-
|
|
7
|
-
import {
|
|
8
|
-
import
|
|
9
|
-
import { loadCapability } from "@oh-my-pi/pi-coding-agent/discovery";
|
|
6
|
+
import { mcpCapability } from "../capability/mcp";
|
|
7
|
+
import type { MCPServer } from "../discovery";
|
|
8
|
+
import { loadCapability } from "../discovery";
|
|
10
9
|
import type { MCPServerConfig } from "./types";
|
|
11
10
|
|
|
12
11
|
/** Options for loading MCP configs */
|
|
@@ -86,7 +85,7 @@ export async function loadAllMCPConfigs(cwd: string, options?: LoadMCPConfigsOpt
|
|
|
86
85
|
// Filter out project-level configs if disabled
|
|
87
86
|
const servers = enableProjectConfig
|
|
88
87
|
? result.items
|
|
89
|
-
: result.items.filter(
|
|
88
|
+
: result.items.filter(server => server._source.level !== "project");
|
|
90
89
|
|
|
91
90
|
// Convert to legacy format and preserve source metadata
|
|
92
91
|
const configs: Record<string, MCPServerConfig> = {};
|
|
@@ -130,7 +129,7 @@ export function isExaMCPServer(name: string, config: MCPServerConfig): boolean {
|
|
|
130
129
|
// Check by args for stdio servers (e.g., mcp-remote to exa)
|
|
131
130
|
if (!config.type || config.type === "stdio") {
|
|
132
131
|
const stdioConfig = config as { args?: string[] };
|
|
133
|
-
if (stdioConfig.args?.some(
|
|
132
|
+
if (stdioConfig.args?.some(arg => EXA_MCP_URL_PATTERN.test(arg))) {
|
|
134
133
|
return true;
|
|
135
134
|
}
|
|
136
135
|
}
|
package/src/mcp/json-rpc.ts
CHANGED
package/src/mcp/loader.ts
CHANGED
|
@@ -3,10 +3,9 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Integrates MCP tool discovery with the custom tools system.
|
|
5
5
|
*/
|
|
6
|
-
|
|
7
|
-
import type { LoadedCustomTool } from "@oh-my-pi/pi-coding-agent/extensibility/custom-tools/types";
|
|
8
|
-
import { AgentStorage } from "@oh-my-pi/pi-coding-agent/session/agent-storage";
|
|
9
6
|
import { logger } from "@oh-my-pi/pi-utils";
|
|
7
|
+
import type { LoadedCustomTool } from "../extensibility/custom-tools/types";
|
|
8
|
+
import { AgentStorage } from "../session/agent-storage";
|
|
10
9
|
import { type MCPLoadResult, MCPManager } from "./manager";
|
|
11
10
|
import { MCPToolCache } from "./tool-cache";
|
|
12
11
|
|
|
@@ -36,10 +35,10 @@ export interface MCPToolsLoadOptions {
|
|
|
36
35
|
cacheStorage?: AgentStorage | null;
|
|
37
36
|
}
|
|
38
37
|
|
|
39
|
-
function resolveToolCache(storage: AgentStorage | null | undefined): MCPToolCache | null {
|
|
38
|
+
async function resolveToolCache(storage: AgentStorage | null | undefined): Promise<MCPToolCache | null> {
|
|
40
39
|
if (storage === null) return null;
|
|
41
40
|
try {
|
|
42
|
-
const resolved = storage ?? AgentStorage.open();
|
|
41
|
+
const resolved = storage ?? (await AgentStorage.open());
|
|
43
42
|
return new MCPToolCache(resolved);
|
|
44
43
|
} catch (error) {
|
|
45
44
|
logger.warn("MCP tool cache unavailable", { error: String(error) });
|
|
@@ -55,7 +54,7 @@ function resolveToolCache(storage: AgentStorage | null | undefined): MCPToolCach
|
|
|
55
54
|
* @returns MCP tools in LoadedCustomTool format for integration
|
|
56
55
|
*/
|
|
57
56
|
export async function discoverAndLoadMCPTools(cwd: string, options?: MCPToolsLoadOptions): Promise<MCPToolsLoadResult> {
|
|
58
|
-
const toolCache = resolveToolCache(options?.cacheStorage);
|
|
57
|
+
const toolCache = await resolveToolCache(options?.cacheStorage);
|
|
59
58
|
const manager = new MCPManager(cwd, toolCache);
|
|
60
59
|
|
|
61
60
|
let result: MCPLoadResult;
|
|
@@ -78,7 +77,7 @@ export async function discoverAndLoadMCPTools(cwd: string, options?: MCPToolsLoa
|
|
|
78
77
|
}
|
|
79
78
|
|
|
80
79
|
// Convert MCP tools to LoadedCustomTool format
|
|
81
|
-
const loadedTools: LoadedCustomTool[] = result.tools.map(
|
|
80
|
+
const loadedTools: LoadedCustomTool[] = result.tools.map(tool => {
|
|
82
81
|
// MCPTool and DeferredMCPTool have these properties
|
|
83
82
|
const mcpTool = tool as { mcpServerName?: string };
|
|
84
83
|
const serverName = mcpTool.mcpServerName;
|
package/src/mcp/manager.ts
CHANGED
|
@@ -4,10 +4,9 @@
|
|
|
4
4
|
* Discovers, connects to, and manages MCP servers.
|
|
5
5
|
* Handles tool loading and lifecycle.
|
|
6
6
|
*/
|
|
7
|
-
|
|
8
|
-
import type { CustomTool } from "@oh-my-pi/pi-coding-agent/extensibility/custom-tools/types";
|
|
9
7
|
import { logger } from "@oh-my-pi/pi-utils";
|
|
10
8
|
import type { TSchema } from "@sinclair/typebox";
|
|
9
|
+
import type { CustomTool } from "../extensibility/custom-tools/types";
|
|
11
10
|
import { connectToServer, disconnectServer, listTools } from "./client";
|
|
12
11
|
import { loadAllMCPConfigs, validateServerConfig } from "./config";
|
|
13
12
|
import type { MCPToolDetails } from "./tool-bridge";
|
|
@@ -34,11 +33,11 @@ const STARTUP_TIMEOUT_MS = 250;
|
|
|
34
33
|
function trackPromise<T>(promise: Promise<T>): TrackedPromise<T> {
|
|
35
34
|
const tracked: TrackedPromise<T> = { promise, status: "pending" };
|
|
36
35
|
promise.then(
|
|
37
|
-
|
|
36
|
+
value => {
|
|
38
37
|
tracked.status = "fulfilled";
|
|
39
38
|
tracked.value = value;
|
|
40
39
|
},
|
|
41
|
-
|
|
40
|
+
reason => {
|
|
42
41
|
tracked.status = "rejected";
|
|
43
42
|
tracked.reason = reason;
|
|
44
43
|
},
|
|
@@ -156,7 +155,7 @@ export class MCPManager {
|
|
|
156
155
|
}
|
|
157
156
|
|
|
158
157
|
const connectionPromise = connectToServer(name, config).then(
|
|
159
|
-
|
|
158
|
+
connection => {
|
|
160
159
|
if (sources[name]) {
|
|
161
160
|
connection._source = sources[name];
|
|
162
161
|
}
|
|
@@ -166,7 +165,7 @@ export class MCPManager {
|
|
|
166
165
|
}
|
|
167
166
|
return connection;
|
|
168
167
|
},
|
|
169
|
-
|
|
168
|
+
error => {
|
|
170
169
|
if (this.pendingConnections.get(name) === connectionPromise) {
|
|
171
170
|
this.pendingConnections.delete(name);
|
|
172
171
|
}
|
|
@@ -175,7 +174,7 @@ export class MCPManager {
|
|
|
175
174
|
);
|
|
176
175
|
this.pendingConnections.set(name, connectionPromise);
|
|
177
176
|
|
|
178
|
-
const toolsPromise = connectionPromise.then(async
|
|
177
|
+
const toolsPromise = connectionPromise.then(async connection => {
|
|
179
178
|
const serverTools = await listTools(connection);
|
|
180
179
|
return { connection, serverTools };
|
|
181
180
|
});
|
|
@@ -192,7 +191,7 @@ export class MCPManager {
|
|
|
192
191
|
this.replaceServerTools(name, customTools);
|
|
193
192
|
void this.toolCache?.set(name, config, serverTools);
|
|
194
193
|
})
|
|
195
|
-
.catch(
|
|
194
|
+
.catch(error => {
|
|
196
195
|
if (this.pendingToolLoads.get(name) !== toolsPromise) return;
|
|
197
196
|
this.pendingToolLoads.delete(name);
|
|
198
197
|
if (!allowBackgroundLogging || reportedErrors.has(name)) return;
|
|
@@ -203,22 +202,22 @@ export class MCPManager {
|
|
|
203
202
|
|
|
204
203
|
// Notify about servers we're connecting to
|
|
205
204
|
if (connectionTasks.length > 0 && onConnecting) {
|
|
206
|
-
onConnecting(connectionTasks.map(
|
|
205
|
+
onConnecting(connectionTasks.map(task => task.name));
|
|
207
206
|
}
|
|
208
207
|
|
|
209
208
|
if (connectionTasks.length > 0) {
|
|
210
209
|
await Promise.race([
|
|
211
|
-
Promise.allSettled(connectionTasks.map(
|
|
210
|
+
Promise.allSettled(connectionTasks.map(task => task.tracked.promise)),
|
|
212
211
|
delay(STARTUP_TIMEOUT_MS),
|
|
213
212
|
]);
|
|
214
213
|
|
|
215
214
|
const cachedTools = new Map<string, MCPToolDefinition[]>();
|
|
216
|
-
const pendingTasks = connectionTasks.filter(
|
|
215
|
+
const pendingTasks = connectionTasks.filter(task => task.tracked.status === "pending");
|
|
217
216
|
|
|
218
217
|
if (pendingTasks.length > 0) {
|
|
219
218
|
if (this.toolCache) {
|
|
220
219
|
await Promise.all(
|
|
221
|
-
pendingTasks.map(async
|
|
220
|
+
pendingTasks.map(async task => {
|
|
222
221
|
const cached = await this.toolCache?.get(task.name, task.config);
|
|
223
222
|
if (cached) {
|
|
224
223
|
cachedTools.set(task.name, cached);
|
|
@@ -227,9 +226,9 @@ export class MCPManager {
|
|
|
227
226
|
);
|
|
228
227
|
}
|
|
229
228
|
|
|
230
|
-
const pendingWithoutCache = pendingTasks.filter(
|
|
229
|
+
const pendingWithoutCache = pendingTasks.filter(task => !cachedTools.has(task.name));
|
|
231
230
|
if (pendingWithoutCache.length > 0) {
|
|
232
|
-
await Promise.allSettled(pendingWithoutCache.map(
|
|
231
|
+
await Promise.allSettled(pendingWithoutCache.map(task => task.tracked.promise));
|
|
233
232
|
}
|
|
234
233
|
}
|
|
235
234
|
|
|
@@ -269,7 +268,7 @@ export class MCPManager {
|
|
|
269
268
|
}
|
|
270
269
|
|
|
271
270
|
private replaceServerTools(name: string, tools: CustomTool<TSchema, MCPToolDetails>[]): void {
|
|
272
|
-
this.tools = this.tools.filter(
|
|
271
|
+
this.tools = this.tools.filter(t => !t.name.startsWith(`mcp_${name}_`));
|
|
273
272
|
this.tools.push(...tools);
|
|
274
273
|
}
|
|
275
274
|
|
|
@@ -327,14 +326,14 @@ export class MCPManager {
|
|
|
327
326
|
}
|
|
328
327
|
|
|
329
328
|
// Remove tools from this server
|
|
330
|
-
this.tools = this.tools.filter(
|
|
329
|
+
this.tools = this.tools.filter(t => !t.name.startsWith(`mcp_${name}_`));
|
|
331
330
|
}
|
|
332
331
|
|
|
333
332
|
/**
|
|
334
333
|
* Disconnect from all servers.
|
|
335
334
|
*/
|
|
336
335
|
async disconnectAll(): Promise<void> {
|
|
337
|
-
const promises = Array.from(this.connections.values()).map(
|
|
336
|
+
const promises = Array.from(this.connections.values()).map(conn => disconnectServer(conn));
|
|
338
337
|
await Promise.allSettled(promises);
|
|
339
338
|
|
|
340
339
|
this.pendingConnections.clear();
|
|
@@ -367,7 +366,7 @@ export class MCPManager {
|
|
|
367
366
|
* Refresh tools from all servers.
|
|
368
367
|
*/
|
|
369
368
|
async refreshAllTools(): Promise<void> {
|
|
370
|
-
const promises = Array.from(this.connections.keys()).map(
|
|
369
|
+
const promises = Array.from(this.connections.keys()).map(name => this.refreshServerTools(name));
|
|
371
370
|
await Promise.allSettled(promises);
|
|
372
371
|
}
|
|
373
372
|
}
|
package/src/mcp/tool-bridge.ts
CHANGED
|
@@ -3,15 +3,10 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Converts MCP tool definitions to CustomTool format for the agent.
|
|
5
5
|
*/
|
|
6
|
-
|
|
7
6
|
import type { AgentToolUpdateCallback } from "@oh-my-pi/pi-agent-core";
|
|
8
|
-
import type { SourceMeta } from "@oh-my-pi/pi-coding-agent/capability/types";
|
|
9
|
-
import type {
|
|
10
|
-
CustomTool,
|
|
11
|
-
CustomToolContext,
|
|
12
|
-
CustomToolResult,
|
|
13
|
-
} from "@oh-my-pi/pi-coding-agent/extensibility/custom-tools/types";
|
|
14
7
|
import type { TSchema } from "@sinclair/typebox";
|
|
8
|
+
import type { SourceMeta } from "../capability/types";
|
|
9
|
+
import type { CustomTool, CustomToolContext, CustomToolResult } from "../extensibility/custom-tools/types";
|
|
15
10
|
import { callTool } from "./client";
|
|
16
11
|
import type { MCPContent, MCPServerConnection, MCPToolDefinition } from "./types";
|
|
17
12
|
|
|
@@ -125,7 +120,7 @@ export class MCPTool implements CustomTool<TSchema, MCPToolDetails> {
|
|
|
125
120
|
|
|
126
121
|
/** Create MCPTool instances for all tools from an MCP server connection */
|
|
127
122
|
static fromTools(connection: MCPServerConnection, tools: MCPToolDefinition[]): MCPTool[] {
|
|
128
|
-
return tools.map(
|
|
123
|
+
return tools.map(tool => new MCPTool(connection, tool));
|
|
129
124
|
}
|
|
130
125
|
|
|
131
126
|
constructor(
|
|
@@ -209,7 +204,7 @@ export class DeferredMCPTool implements CustomTool<TSchema, MCPToolDetails> {
|
|
|
209
204
|
getConnection: () => Promise<MCPServerConnection>,
|
|
210
205
|
source?: SourceMeta,
|
|
211
206
|
): DeferredMCPTool[] {
|
|
212
|
-
return tools.map(
|
|
207
|
+
return tools.map(tool => new DeferredMCPTool(serverName, tool, getConnection, source));
|
|
213
208
|
}
|
|
214
209
|
|
|
215
210
|
constructor(
|
package/src/mcp/tool-cache.ts
CHANGED
|
@@ -3,9 +3,8 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Stores tool definitions per server in agent.db for fast startup.
|
|
5
5
|
*/
|
|
6
|
-
|
|
7
|
-
import type { AgentStorage } from "@oh-my-pi/pi-coding-agent/session/agent-storage";
|
|
8
6
|
import { logger } from "@oh-my-pi/pi-utils";
|
|
7
|
+
import type { AgentStorage } from "../session/agent-storage";
|
|
9
8
|
import type { MCPServerConfig, MCPToolDefinition } from "./types";
|
|
10
9
|
|
|
11
10
|
const CACHE_VERSION = 1;
|
|
@@ -24,7 +23,7 @@ function isRecord(value: unknown): value is Record<string, unknown> {
|
|
|
24
23
|
|
|
25
24
|
function stableClone(value: unknown): unknown {
|
|
26
25
|
if (Array.isArray(value)) {
|
|
27
|
-
return value.map(
|
|
26
|
+
return value.map(item => stableClone(item));
|
|
28
27
|
}
|
|
29
28
|
if (isRecord(value)) {
|
|
30
29
|
const sorted: Record<string, unknown> = {};
|
|
@@ -4,22 +4,20 @@
|
|
|
4
4
|
* Implements JSON-RPC 2.0 over HTTP POST with optional SSE streaming.
|
|
5
5
|
* Based on MCP spec 2025-03-26.
|
|
6
6
|
*/
|
|
7
|
-
|
|
7
|
+
import { readSseEvents } from "@oh-my-pi/pi-utils";
|
|
8
8
|
import type {
|
|
9
9
|
JsonRpcMessage,
|
|
10
10
|
JsonRpcResponse,
|
|
11
11
|
MCPHttpServerConfig,
|
|
12
12
|
MCPSseServerConfig,
|
|
13
13
|
MCPTransport,
|
|
14
|
-
} from "
|
|
14
|
+
} from "../../mcp/types";
|
|
15
15
|
|
|
16
16
|
/** Generate unique request ID */
|
|
17
17
|
function generateId(): string {
|
|
18
18
|
return Math.random().toString(36).slice(2) + Date.now().toString(36);
|
|
19
19
|
}
|
|
20
20
|
|
|
21
|
-
import { readSseEvents } from "@oh-my-pi/pi-utils";
|
|
22
|
-
|
|
23
21
|
/**
|
|
24
22
|
* HTTP transport for MCP servers.
|
|
25
23
|
* Uses POST for requests, supports SSE responses.
|
|
@@ -4,9 +4,8 @@
|
|
|
4
4
|
* Implements JSON-RPC 2.0 over subprocess stdin/stdout.
|
|
5
5
|
* Messages are newline-delimited JSON.
|
|
6
6
|
*/
|
|
7
|
-
|
|
8
|
-
import type { JsonRpcResponse, MCPStdioServerConfig, MCPTransport } from "@oh-my-pi/pi-coding-agent/mcp/types";
|
|
9
7
|
import { type Subprocess, spawn } from "bun";
|
|
8
|
+
import type { JsonRpcResponse, MCPStdioServerConfig, MCPTransport } from "../../mcp/types";
|
|
10
9
|
|
|
11
10
|
/** Generate unique request ID */
|
|
12
11
|
function generateId(): string {
|