@oh-my-pi/pi-coding-agent 8.1.0 → 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 +21 -1
- 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 +51 -23
- package/scripts/format-prompts.ts +0 -1
- package/src/capability/context-file.ts +2 -3
- package/src/capability/extension-module.ts +2 -3
- package/src/capability/extension.ts +2 -3
- package/src/capability/fs.ts +20 -21
- package/src/capability/hook.ts +2 -3
- package/src/capability/index.ts +15 -16
- package/src/capability/instruction.ts +2 -3
- package/src/capability/mcp.ts +2 -3
- package/src/capability/prompt.ts +2 -3
- package/src/capability/rule.ts +2 -3
- package/src/capability/settings.ts +1 -2
- package/src/capability/skill.ts +2 -3
- package/src/capability/slash-command.ts +2 -3
- package/src/capability/ssh.ts +2 -3
- package/src/capability/system-prompt.ts +2 -3
- package/src/capability/tool.ts +2 -3
- 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 -21
- 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 +21 -23
- package/src/commit/agentic/fallback.ts +9 -9
- package/src/commit/agentic/index.ts +30 -38
- package/src/commit/agentic/state.ts +1 -6
- package/src/commit/agentic/tools/analyze-file.ts +15 -15
- package/src/commit/agentic/tools/git-file-diff.ts +3 -3
- package/src/commit/agentic/tools/git-hunk.ts +7 -7
- package/src/commit/agentic/tools/git-overview.ts +5 -5
- package/src/commit/agentic/tools/index.ts +14 -14
- package/src/commit/agentic/tools/propose-changelog.ts +6 -6
- package/src/commit/agentic/tools/propose-commit.ts +8 -8
- package/src/commit/agentic/tools/recent-commits.ts +2 -2
- package/src/commit/agentic/tools/split-commit.ts +19 -23
- package/src/commit/agentic/topo-sort.ts +1 -1
- package/src/commit/agentic/trivial.ts +3 -3
- package/src/commit/agentic/validation.ts +12 -12
- package/src/commit/analysis/conventional.ts +7 -11
- package/src/commit/analysis/index.ts +4 -4
- package/src/commit/analysis/scope.ts +4 -4
- package/src/commit/analysis/summary.ts +7 -9
- package/src/commit/analysis/validation.ts +1 -1
- package/src/commit/changelog/detect.ts +6 -6
- package/src/commit/changelog/generate.ts +7 -9
- package/src/commit/changelog/index.ts +13 -13
- package/src/commit/changelog/parse.ts +2 -2
- package/src/commit/cli.ts +1 -1
- package/src/commit/git/diff.ts +3 -3
- package/src/commit/git/index.ts +19 -24
- package/src/commit/index.ts +1 -1
- package/src/commit/map-reduce/index.ts +9 -9
- package/src/commit/map-reduce/map-phase.ts +19 -34
- package/src/commit/map-reduce/reduce-phase.ts +9 -11
- package/src/commit/message.ts +2 -2
- package/src/commit/model-selection.ts +3 -7
- package/src/commit/pipeline.ts +20 -22
- package/src/commit/utils/exclusions.ts +3 -3
- package/src/config/file-lock.ts +17 -7
- package/src/config/keybindings.ts +6 -8
- package/src/config/model-registry.ts +55 -37
- package/src/config/model-resolver.ts +18 -19
- package/src/config/prompt-templates.ts +11 -11
- package/src/config/settings-manager.ts +50 -34
- package/src/config.ts +60 -62
- 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 +16 -18
- 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 +17 -14
- package/src/extensibility/custom-commands/types.ts +1 -2
- package/src/extensibility/custom-tools/loader.ts +10 -11
- package/src/extensibility/custom-tools/types.ts +6 -7
- package/src/extensibility/custom-tools/wrapper.ts +2 -3
- package/src/extensibility/extensions/loader.ts +75 -53
- package/src/extensibility/extensions/runner.ts +11 -12
- package/src/extensibility/extensions/types.ts +19 -26
- package/src/extensibility/extensions/wrapper.ts +3 -4
- package/src/extensibility/hooks/index.ts +1 -1
- package/src/extensibility/hooks/loader.ts +8 -9
- package/src/extensibility/hooks/runner.ts +7 -8
- package/src/extensibility/hooks/tool-wrapper.ts +0 -1
- package/src/extensibility/hooks/types.ts +10 -17
- 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 +46 -46
- 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 +14 -10
- 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 +10 -16
- package/src/lsp/utils.ts +3 -3
- package/src/main.ts +55 -34
- 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 +3 -4
- 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 +60 -49
- package/src/modes/components/armin.ts +4 -5
- package/src/modes/components/assistant-message.ts +6 -6
- 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 +11 -16
- package/src/modes/components/tree-selector.ts +11 -11
- 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 +27 -29
- 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 -25
- package/src/modes/rpc/rpc-types.ts +3 -4
- package/src/modes/theme/mermaid-cache.ts +2 -2
- package/src/modes/theme/theme.ts +128 -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 +10 -11
- 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 +12 -13
- package/src/sdk.ts +60 -63
- package/src/session/agent-session.ts +83 -84
- package/src/session/agent-storage.ts +11 -11
- package/src/session/artifacts.ts +8 -9
- package/src/session/auth-storage.ts +25 -29
- 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 +2 -3
- 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 +27 -34
- 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 +33 -36
- package/src/task/output-manager.ts +3 -4
- package/src/task/parallel.ts +0 -1
- package/src/task/render.ts +19 -20
- package/src/task/subprocess-tool-registry.ts +1 -2
- package/src/task/worker-protocol.ts +3 -3
- package/src/task/worker.ts +32 -38
- package/src/task/worktree.ts +19 -19
- package/src/tools/ask.ts +8 -9
- package/src/tools/bash-interceptor.ts +1 -5
- package/src/tools/bash.ts +19 -18
- package/src/tools/calculator.ts +12 -12
- package/src/tools/complete.ts +3 -4
- package/src/tools/context.ts +2 -2
- package/src/tools/fetch.ts +23 -26
- package/src/tools/find.ts +15 -16
- package/src/tools/gemini-image.ts +14 -14
- package/src/tools/grep.ts +27 -27
- package/src/tools/index.ts +78 -56
- package/src/tools/list-limit.ts +1 -1
- package/src/tools/ls.ts +7 -7
- package/src/tools/notebook.ts +5 -5
- package/src/tools/output-meta.ts +3 -4
- package/src/tools/output-utils.ts +1 -1
- package/src/tools/path-utils.ts +5 -5
- package/src/tools/python.ts +36 -37
- package/src/tools/read.ts +23 -23
- package/src/tools/render-utils.ts +8 -9
- package/src/tools/renderers.ts +6 -7
- package/src/tools/review.ts +8 -11
- package/src/tools/ssh.ts +31 -30
- package/src/tools/todo-write.ts +13 -13
- package/src/tools/tool-errors.ts +3 -3
- package/src/tools/tool-result.ts +3 -8
- package/src/tools/write.ts +11 -16
- package/src/tui/code-cell.ts +3 -9
- package/src/tui/file-list.ts +3 -4
- package/src/tui/output-block.ts +1 -2
- package/src/tui/status-line.ts +2 -3
- package/src/tui/tree-list.ts +2 -3
- package/src/tui/types.ts +1 -2
- package/src/tui/utils.ts +2 -3
- 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 +4 -9
- 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 +16 -18
- package/scripts/generate-wasm-b64.ts +0 -24
- package/src/commit/map-reduce/.map-phase.ts.kate-swp +0 -0
- package/src/task/.executor.ts.kate-swp +0 -0
- package/src/vendor/photon/photon_rs_bg.wasm.b64.js +0 -1
package/src/lsp/render.ts
CHANGED
|
@@ -7,18 +7,12 @@
|
|
|
7
7
|
* - Grouped references and symbols
|
|
8
8
|
* - Collapsible/expandable views
|
|
9
9
|
*/
|
|
10
|
-
|
|
11
10
|
import type { AgentToolResult, RenderResultOptions } from "@oh-my-pi/pi-agent-core";
|
|
12
|
-
import { getLanguageFromPath, type Theme } from "@oh-my-pi/pi-coding-agent/modes/theme/theme";
|
|
13
|
-
import {
|
|
14
|
-
formatExpandHint,
|
|
15
|
-
formatMoreItems,
|
|
16
|
-
TRUNCATE_LENGTHS,
|
|
17
|
-
truncate,
|
|
18
|
-
} from "@oh-my-pi/pi-coding-agent/tools/render-utils";
|
|
19
|
-
import { renderOutputBlock, renderStatusLine } from "@oh-my-pi/pi-coding-agent/tui";
|
|
20
11
|
import { type Component, Text } from "@oh-my-pi/pi-tui";
|
|
21
12
|
import { highlight, supportsLanguage } from "cli-highlight";
|
|
13
|
+
import { getLanguageFromPath, type Theme } from "../modes/theme/theme";
|
|
14
|
+
import { formatExpandHint, formatMoreItems, TRUNCATE_LENGTHS, truncate } from "../tools/render-utils";
|
|
15
|
+
import { renderOutputBlock, renderStatusLine } from "../tui";
|
|
22
16
|
import type { LspParams, LspToolDetails } from "./types";
|
|
23
17
|
|
|
24
18
|
// =============================================================================
|
|
@@ -265,11 +259,11 @@ function renderDiagnostics(
|
|
|
265
259
|
if (warnCount > 0) meta.push(`${warnCount} warning${warnCount !== 1 ? "s" : ""}`);
|
|
266
260
|
if (meta.length === 0) meta.push("No issues");
|
|
267
261
|
|
|
268
|
-
const diagLines = lines.filter(
|
|
262
|
+
const diagLines = lines.filter(l => l.includes(theme.status.error) || /:\d+:\d+/.test(l));
|
|
269
263
|
const parsedDiagnostics = diagLines
|
|
270
|
-
.map(
|
|
264
|
+
.map(line => parseDiagnosticLine(line))
|
|
271
265
|
.filter((diag): diag is ParsedDiagnostic => diag !== null);
|
|
272
|
-
const fallbackDiagnostics: RawDiagnostic[] = diagLines.map(
|
|
266
|
+
const fallbackDiagnostics: RawDiagnostic[] = diagLines.map(line => ({ raw: line.trim() }));
|
|
273
267
|
|
|
274
268
|
if (expanded) {
|
|
275
269
|
let output = `${icon} ${theme.fg("dim", meta.join(theme.sep.dot))}`;
|
|
@@ -343,7 +337,7 @@ function renderReferences(refMatch: RegExpMatchArray, lines: string[], expanded:
|
|
|
343
337
|
const icon =
|
|
344
338
|
refCount > 0 ? theme.styledSymbol("status.success", "success") : theme.styledSymbol("status.warning", "warning");
|
|
345
339
|
|
|
346
|
-
const locLines = lines.filter(
|
|
340
|
+
const locLines = lines.filter(l => /^\s*\S+:\d+:\d+/.test(l));
|
|
347
341
|
|
|
348
342
|
// Group by file
|
|
349
343
|
const byFile = new Map<string, Array<[string, string]>>();
|
|
@@ -436,7 +430,7 @@ function renderSymbols(symbolsMatch: RegExpMatchArray, lines: string[], expanded
|
|
|
436
430
|
icon: string;
|
|
437
431
|
}
|
|
438
432
|
|
|
439
|
-
const symbolLines = lines.filter(
|
|
433
|
+
const symbolLines = lines.filter(l => l.includes("@") && l.includes("line"));
|
|
440
434
|
const symbols: SymbolInfo[] = [];
|
|
441
435
|
|
|
442
436
|
for (const line of symbolLines) {
|
|
@@ -479,7 +473,7 @@ function renderSymbols(symbolsMatch: RegExpMatchArray, lines: string[], expanded
|
|
|
479
473
|
return prefix;
|
|
480
474
|
};
|
|
481
475
|
|
|
482
|
-
const topLevelCount = symbols.filter(
|
|
476
|
+
const topLevelCount = symbols.filter(s => s.indent === 0).length;
|
|
483
477
|
|
|
484
478
|
if (expanded) {
|
|
485
479
|
let output = `${icon} ${theme.fg("dim", `in ${fileName}`)}`;
|
|
@@ -497,7 +491,7 @@ function renderSymbols(symbolsMatch: RegExpMatchArray, lines: string[], expanded
|
|
|
497
491
|
}
|
|
498
492
|
|
|
499
493
|
// Collapsed: show first 3 top-level symbols
|
|
500
|
-
const topLevel = symbols.filter(
|
|
494
|
+
const topLevel = symbols.filter(s => s.indent === 0).slice(0, 3);
|
|
501
495
|
const hasMoreSymbols = symbols.length > topLevel.length;
|
|
502
496
|
const expandHint = formatExpandHint(theme, expanded, hasMoreSymbols);
|
|
503
497
|
let output = `${icon} ${theme.fg("dim", `in ${fileName}`)}${expandHint}`;
|
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,17 +4,17 @@
|
|
|
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";
|
|
@@ -32,6 +32,7 @@ import { exportFromFile } from "./export/html";
|
|
|
32
32
|
import type { ExtensionUIContext } from "./extensibility/extensions/types";
|
|
33
33
|
import { runMigrations, showDeprecationWarnings } from "./migrations";
|
|
34
34
|
import { InteractiveMode, runPrintMode, runRpcMode } from "./modes";
|
|
35
|
+
import { initTheme, stopThemeWatcher } from "./modes/theme/theme";
|
|
35
36
|
import { type CreateAgentSessionOptions, createAgentSession, discoverAuthStorage, discoverModels } from "./sdk";
|
|
36
37
|
import type { AgentSession } from "./session/agent-session";
|
|
37
38
|
import { type SessionInfo, SessionManager } from "./session/session-manager";
|
|
@@ -96,7 +97,7 @@ async function runInteractiveMode(
|
|
|
96
97
|
await mode.init();
|
|
97
98
|
|
|
98
99
|
versionCheckPromise
|
|
99
|
-
.then(
|
|
100
|
+
.then(newVersion => {
|
|
100
101
|
if (newVersion) {
|
|
101
102
|
mode.showNewVersionNotification(newVersion);
|
|
102
103
|
}
|
|
@@ -176,13 +177,17 @@ async function prepareInitialMessage(
|
|
|
176
177
|
/**
|
|
177
178
|
* Resolve a session argument to a local or global session match.
|
|
178
179
|
*/
|
|
179
|
-
function resolveSessionMatch(
|
|
180
|
-
|
|
181
|
-
|
|
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));
|
|
182
187
|
|
|
183
188
|
if (matches.length === 0 && !sessionDir) {
|
|
184
|
-
const globalSessions = SessionManager.listAll();
|
|
185
|
-
matches = globalSessions.filter(
|
|
189
|
+
const globalSessions = await SessionManager.listAll();
|
|
190
|
+
matches = globalSessions.filter(session => session.id.startsWith(sessionArg));
|
|
186
191
|
}
|
|
187
192
|
|
|
188
193
|
return matches[0];
|
|
@@ -202,25 +207,25 @@ async function promptForkSession(session: SessionInfo): Promise<boolean> {
|
|
|
202
207
|
}
|
|
203
208
|
}
|
|
204
209
|
|
|
205
|
-
function getChangelogForDisplay(parsed: Args, settingsManager: SettingsManager): string | undefined {
|
|
210
|
+
async function getChangelogForDisplay(parsed: Args, settingsManager: SettingsManager): Promise<string | undefined> {
|
|
206
211
|
if (parsed.continue || parsed.resume) {
|
|
207
212
|
return undefined;
|
|
208
213
|
}
|
|
209
214
|
|
|
210
215
|
const lastVersion = settingsManager.getLastChangelogVersion();
|
|
211
216
|
const changelogPath = getChangelogPath();
|
|
212
|
-
const entries = parseChangelog(changelogPath);
|
|
217
|
+
const entries = await parseChangelog(changelogPath);
|
|
213
218
|
|
|
214
219
|
if (!lastVersion) {
|
|
215
220
|
if (entries.length > 0) {
|
|
216
221
|
settingsManager.setLastChangelogVersion(VERSION);
|
|
217
|
-
return entries.map(
|
|
222
|
+
return entries.map(e => e.content).join("\n\n");
|
|
218
223
|
}
|
|
219
224
|
} else {
|
|
220
225
|
const newEntries = getNewEntries(entries, lastVersion);
|
|
221
226
|
if (newEntries.length > 0) {
|
|
222
227
|
settingsManager.setLastChangelogVersion(VERSION);
|
|
223
|
-
return newEntries.map(
|
|
228
|
+
return newEntries.map(e => e.content).join("\n\n");
|
|
224
229
|
}
|
|
225
230
|
}
|
|
226
231
|
|
|
@@ -236,12 +241,12 @@ async function createSessionManager(parsed: Args, cwd: string): Promise<SessionM
|
|
|
236
241
|
if (sessionArg.includes("/") || sessionArg.includes("\\") || sessionArg.endsWith(".jsonl")) {
|
|
237
242
|
return await SessionManager.open(sessionArg, parsed.sessionDir);
|
|
238
243
|
}
|
|
239
|
-
const match = resolveSessionMatch(sessionArg, cwd, parsed.sessionDir);
|
|
244
|
+
const match = await resolveSessionMatch(sessionArg, cwd, parsed.sessionDir);
|
|
240
245
|
if (!match) {
|
|
241
246
|
throw new Error(`Session "${sessionArg}" not found.`);
|
|
242
247
|
}
|
|
243
|
-
const normalizedCwd = resolve(cwd);
|
|
244
|
-
const normalizedMatchCwd = resolve(match.cwd || cwd);
|
|
248
|
+
const normalizedCwd = path.resolve(cwd);
|
|
249
|
+
const normalizedMatchCwd = path.resolve(match.cwd || cwd);
|
|
245
250
|
if (normalizedCwd !== normalizedMatchCwd) {
|
|
246
251
|
const shouldFork = await promptForkSession(match);
|
|
247
252
|
if (!shouldFork) {
|
|
@@ -268,13 +273,13 @@ async function maybeAutoChdir(parsed: Args): Promise<void> {
|
|
|
268
273
|
return;
|
|
269
274
|
}
|
|
270
275
|
|
|
271
|
-
const home = homedir();
|
|
276
|
+
const home = os.homedir();
|
|
272
277
|
if (!home) {
|
|
273
278
|
return;
|
|
274
279
|
}
|
|
275
280
|
|
|
276
281
|
const normalizePath = (value: string) => {
|
|
277
|
-
const resolved = resolve(value);
|
|
282
|
+
const resolved = path.resolve(value);
|
|
278
283
|
return process.platform === "win32" ? resolved.toLowerCase() : resolved;
|
|
279
284
|
};
|
|
280
285
|
|
|
@@ -284,16 +289,16 @@ async function maybeAutoChdir(parsed: Args): Promise<void> {
|
|
|
284
289
|
return;
|
|
285
290
|
}
|
|
286
291
|
|
|
287
|
-
const isDirectory = async (
|
|
292
|
+
const isDirectory = async (p: string) => {
|
|
288
293
|
try {
|
|
289
|
-
const
|
|
290
|
-
return
|
|
294
|
+
const s = await fs.stat(p);
|
|
295
|
+
return s.isDirectory();
|
|
291
296
|
} catch {
|
|
292
297
|
return false;
|
|
293
298
|
}
|
|
294
299
|
};
|
|
295
300
|
|
|
296
|
-
const candidates = [join(home, "tmp"), "/tmp", "/var/tmp"];
|
|
301
|
+
const candidates = [path.join(home, "tmp"), "/tmp", "/var/tmp"];
|
|
297
302
|
for (const candidate of candidates) {
|
|
298
303
|
try {
|
|
299
304
|
if (!(await isDirectory(candidate))) {
|
|
@@ -307,7 +312,7 @@ async function maybeAutoChdir(parsed: Args): Promise<void> {
|
|
|
307
312
|
}
|
|
308
313
|
|
|
309
314
|
try {
|
|
310
|
-
const fallback = tmpdir();
|
|
315
|
+
const fallback = os.tmpdir();
|
|
311
316
|
if (fallback && normalizePath(fallback) !== cwd && (await isDirectory(fallback))) {
|
|
312
317
|
process.chdir(fallback);
|
|
313
318
|
}
|
|
@@ -386,10 +391,10 @@ async function buildSessionOptions(
|
|
|
386
391
|
const parsedModel = parseModelString(remembered);
|
|
387
392
|
const rememberedModel = parsedModel
|
|
388
393
|
? scopedModels.find(
|
|
389
|
-
|
|
394
|
+
scopedModel =>
|
|
390
395
|
scopedModel.model.provider === parsedModel.provider && scopedModel.model.id === parsedModel.id,
|
|
391
396
|
)
|
|
392
|
-
: scopedModels.find(
|
|
397
|
+
: scopedModels.find(scopedModel => scopedModel.model.id.toLowerCase() === remembered.toLowerCase());
|
|
393
398
|
if (rememberedModel) {
|
|
394
399
|
options.model = rememberedModel.model;
|
|
395
400
|
}
|
|
@@ -414,7 +419,7 @@ async function buildSessionOptions(
|
|
|
414
419
|
// Scoped models for Ctrl+P cycling - fill in default thinking levels when not explicit
|
|
415
420
|
if (scopedModels.length > 0) {
|
|
416
421
|
const defaultThinkingLevel = settingsManager.getDefaultThinkingLevel() ?? "off";
|
|
417
|
-
options.scopedModels = scopedModels.map(
|
|
422
|
+
options.scopedModels = scopedModels.map(scopedModel => ({
|
|
418
423
|
model: scopedModel.model,
|
|
419
424
|
thinkingLevel: scopedModel.explicitThinkingLevel
|
|
420
425
|
? (scopedModel.thinkingLevel ?? defaultThinkingLevel)
|
|
@@ -431,7 +436,7 @@ async function buildSessionOptions(
|
|
|
431
436
|
} else if (resolvedSystemPrompt) {
|
|
432
437
|
options.systemPrompt = resolvedSystemPrompt;
|
|
433
438
|
} else if (resolvedAppendPrompt) {
|
|
434
|
-
options.systemPrompt =
|
|
439
|
+
options.systemPrompt = defaultPrompt => `${defaultPrompt}\n\n${resolvedAppendPrompt}`;
|
|
435
440
|
}
|
|
436
441
|
|
|
437
442
|
// Tools
|
|
@@ -477,7 +482,7 @@ export async function main(args: string[]) {
|
|
|
477
482
|
|
|
478
483
|
// Initialize theme early with defaults (CLI commands need symbols)
|
|
479
484
|
// Will be re-initialized with user preferences later
|
|
480
|
-
initTheme();
|
|
485
|
+
await initTheme();
|
|
481
486
|
|
|
482
487
|
// Handle plugin subcommand before regular parsing
|
|
483
488
|
const pluginCmd = parsePluginArgs(args);
|
|
@@ -523,6 +528,17 @@ export async function main(args: string[]) {
|
|
|
523
528
|
return;
|
|
524
529
|
}
|
|
525
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
|
+
|
|
526
542
|
// Handle stats subcommand
|
|
527
543
|
const statsCmd = parseStatsArgs(args);
|
|
528
544
|
if (statsCmd) {
|
|
@@ -554,7 +570,7 @@ export async function main(args: string[]) {
|
|
|
554
570
|
|
|
555
571
|
// Create AuthStorage and ModelRegistry upfront
|
|
556
572
|
const authStorage = await discoverAuthStorage();
|
|
557
|
-
const modelRegistry =
|
|
573
|
+
const modelRegistry = discoverModels(authStorage);
|
|
558
574
|
time("discoverModels");
|
|
559
575
|
|
|
560
576
|
if (parsed.version) {
|
|
@@ -619,7 +635,12 @@ export async function main(args: string[]) {
|
|
|
619
635
|
settingsManager.applyOverrides({ modelRoles: roleOverrides });
|
|
620
636
|
}
|
|
621
637
|
|
|
622
|
-
initTheme(
|
|
638
|
+
await initTheme(
|
|
639
|
+
settingsManager.getTheme(),
|
|
640
|
+
isInteractive,
|
|
641
|
+
settingsManager.getSymbolPreset(),
|
|
642
|
+
settingsManager.getColorBlindMode(),
|
|
643
|
+
);
|
|
623
644
|
time("initTheme");
|
|
624
645
|
|
|
625
646
|
// Show deprecation warnings in interactive mode
|
|
@@ -640,7 +661,7 @@ export async function main(args: string[]) {
|
|
|
640
661
|
|
|
641
662
|
// Handle --resume: show session picker
|
|
642
663
|
if (parsed.resume) {
|
|
643
|
-
const sessions = SessionManager.list(cwd, parsed.sessionDir);
|
|
664
|
+
const sessions = await SessionManager.list(cwd, parsed.sessionDir);
|
|
644
665
|
time("SessionManager.list");
|
|
645
666
|
if (sessions.length === 0) {
|
|
646
667
|
writeStdout(chalk.dim("No sessions found"));
|
|
@@ -722,12 +743,12 @@ export async function main(args: string[]) {
|
|
|
722
743
|
await runRpcMode(session);
|
|
723
744
|
} else if (isInteractive) {
|
|
724
745
|
const versionCheckPromise = checkForNewVersion(VERSION).catch(() => undefined);
|
|
725
|
-
const changelogMarkdown = getChangelogForDisplay(parsed, settingsManager);
|
|
746
|
+
const changelogMarkdown = await getChangelogForDisplay(parsed, settingsManager);
|
|
726
747
|
|
|
727
748
|
const scopedModelsForDisplay = sessionOptions.scopedModels ?? scopedModels;
|
|
728
749
|
if (scopedModelsForDisplay.length > 0) {
|
|
729
750
|
const modelList = scopedModelsForDisplay
|
|
730
|
-
.map(
|
|
751
|
+
.map(scopedModel => {
|
|
731
752
|
const thinkingStr = scopedModel.thinkingLevel !== "off" ? `:${scopedModel.thinkingLevel}` : "";
|
|
732
753
|
return `${scopedModel.model.id}${thinkingStr}`;
|
|
733
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
|
|
|
@@ -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 {
|