@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/patch/index.ts
CHANGED
|
@@ -7,24 +7,23 @@
|
|
|
7
7
|
*
|
|
8
8
|
* The mode is determined by the `edit.patchMode` setting.
|
|
9
9
|
*/
|
|
10
|
-
|
|
11
|
-
import { mkdir } from "node:fs/promises";
|
|
10
|
+
import * as fs from "node:fs/promises";
|
|
12
11
|
import type { AgentTool, AgentToolContext, AgentToolResult, AgentToolUpdateCallback } from "@oh-my-pi/pi-agent-core";
|
|
13
12
|
import { StringEnum } from "@oh-my-pi/pi-ai";
|
|
14
|
-
import {
|
|
13
|
+
import { Type } from "@sinclair/typebox";
|
|
14
|
+
import { renderPromptTemplate } from "../config/prompt-templates";
|
|
15
15
|
import {
|
|
16
16
|
createLspWritethrough,
|
|
17
17
|
type FileDiagnosticsResult,
|
|
18
18
|
flushLspWritethroughBatch,
|
|
19
19
|
type WritethroughCallback,
|
|
20
20
|
writethroughNoop,
|
|
21
|
-
} from "
|
|
22
|
-
import patchDescription from "
|
|
23
|
-
import replaceDescription from "
|
|
24
|
-
import type { ToolSession } from "
|
|
25
|
-
import { outputMeta } from "
|
|
26
|
-
import { resolveToCwd } from "
|
|
27
|
-
import { Type } from "@sinclair/typebox";
|
|
21
|
+
} from "../lsp";
|
|
22
|
+
import patchDescription from "../prompts/tools/patch.md" with { type: "text" };
|
|
23
|
+
import replaceDescription from "../prompts/tools/replace.md" with { type: "text" };
|
|
24
|
+
import type { ToolSession } from "../tools";
|
|
25
|
+
import { outputMeta } from "../tools/output-meta";
|
|
26
|
+
import { resolveToCwd } from "../tools/path-utils";
|
|
28
27
|
import { applyPatch } from "./applicator";
|
|
29
28
|
import { generateDiffString, generateUnifiedDiffString, replaceText } from "./diff";
|
|
30
29
|
import { DEFAULT_FUZZY_THRESHOLD, findMatch } from "./fuzzy";
|
|
@@ -48,13 +47,7 @@ export { computeEditDiff, computePatchDiff, generateDiffString, generateUnifiedD
|
|
|
48
47
|
export { DEFAULT_FUZZY_THRESHOLD, findContextLine, findMatch as findEditMatch, findMatch, seekSequence } from "./fuzzy";
|
|
49
48
|
|
|
50
49
|
// Normalization
|
|
51
|
-
export {
|
|
52
|
-
adjustIndentation,
|
|
53
|
-
detectLineEnding,
|
|
54
|
-
normalizeToLF,
|
|
55
|
-
restoreLineEndings,
|
|
56
|
-
stripBom,
|
|
57
|
-
} from "./normalize";
|
|
50
|
+
export { adjustIndentation, detectLineEnding, normalizeToLF, restoreLineEndings, stripBom } from "./normalize";
|
|
58
51
|
|
|
59
52
|
// Parsing
|
|
60
53
|
export { normalizeCreateContent, normalizeDiff, parseHunks as parseDiffHunks } from "./parser";
|
|
@@ -166,7 +159,7 @@ class LspFileSystem implements FileSystem {
|
|
|
166
159
|
}
|
|
167
160
|
|
|
168
161
|
async mkdir(path: string): Promise<void> {
|
|
169
|
-
await mkdir(path, { recursive: true });
|
|
162
|
+
await fs.mkdir(path, { recursive: true });
|
|
170
163
|
}
|
|
171
164
|
|
|
172
165
|
getDiagnostics(): FileDiagnosticsResult | undefined {
|
package/src/patch/normalize.ts
CHANGED
|
@@ -189,7 +189,7 @@ export function convertLeadingTabsToSpaces(text: string, spacesPerTab: number):
|
|
|
189
189
|
if (spacesPerTab <= 0) return text;
|
|
190
190
|
return text
|
|
191
191
|
.split("\n")
|
|
192
|
-
.map(
|
|
192
|
+
.map(line => {
|
|
193
193
|
const trimmed = line.trimStart();
|
|
194
194
|
if (trimmed.length === 0) return line;
|
|
195
195
|
const leading = getLeadingWhitespace(line);
|
|
@@ -212,7 +212,7 @@ export function normalizeUnicode(s: string): string {
|
|
|
212
212
|
return s
|
|
213
213
|
.trim()
|
|
214
214
|
.split("")
|
|
215
|
-
.map(
|
|
215
|
+
.map(c => {
|
|
216
216
|
const code = c.charCodeAt(0);
|
|
217
217
|
|
|
218
218
|
// Various dash/hyphen code-points → ASCII '-'
|
|
@@ -367,7 +367,7 @@ export function adjustIndentation(oldText: string, actualText: string, newText:
|
|
|
367
367
|
}
|
|
368
368
|
|
|
369
369
|
const delta = deltas[0];
|
|
370
|
-
if (!deltas.every(
|
|
370
|
+
if (!deltas.every(value => value === delta)) {
|
|
371
371
|
return newText;
|
|
372
372
|
}
|
|
373
373
|
|
|
@@ -380,7 +380,7 @@ export function adjustIndentation(oldText: string, actualText: string, newText:
|
|
|
380
380
|
}
|
|
381
381
|
|
|
382
382
|
const indentChar = actualProfile.char ?? oldProfile.char ?? detectIndentChar(actualText);
|
|
383
|
-
const adjusted = newText.split("\n").map(
|
|
383
|
+
const adjusted = newText.split("\n").map(line => {
|
|
384
384
|
if (line.trim().length === 0) {
|
|
385
385
|
return line;
|
|
386
386
|
}
|
package/src/patch/normative.ts
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Normalize applied patch output into a canonical edit tool payload.
|
|
3
3
|
*/
|
|
4
|
-
|
|
5
4
|
import { generateUnifiedDiffString } from "./diff";
|
|
6
5
|
import { normalizeToLF, stripBom } from "./normalize";
|
|
7
6
|
import { parseHunks } from "./parser";
|
|
@@ -37,7 +36,7 @@ function applyAnchors(diff: string, anchors: Array<string | undefined> | undefin
|
|
|
37
36
|
|
|
38
37
|
function deriveAnchors(diff: string): Array<string | undefined> {
|
|
39
38
|
const hunks = parseHunks(diff);
|
|
40
|
-
return hunks.map(
|
|
39
|
+
return hunks.map(hunk => {
|
|
41
40
|
if (hunk.oldLines.length === 0 || hunk.newLines.length === 0) {
|
|
42
41
|
return undefined;
|
|
43
42
|
}
|
package/src/patch/parser.ts
CHANGED
|
@@ -6,7 +6,6 @@
|
|
|
6
6
|
* - Unified diff format (@@ -X,Y +A,B @@)
|
|
7
7
|
* - Codex-style wrapped patches (*** Begin Patch / *** End Patch)
|
|
8
8
|
*/
|
|
9
|
-
|
|
10
9
|
import type { DiffHunk } from "./types";
|
|
11
10
|
import { ApplyPatchError, ParseError } from "./types";
|
|
12
11
|
|
|
@@ -90,7 +89,7 @@ export function normalizeDiff(diff: string): string {
|
|
|
90
89
|
// Layer 2: Strip Codex-style file operation markers and unified diff metadata
|
|
91
90
|
// NOTE: Do NOT strip "*** End of File" - that's a valid marker within hunks, not a wrapper
|
|
92
91
|
// IMPORTANT: Only strip actual metadata lines, NOT diff content lines (starting with space, +, or -)
|
|
93
|
-
lines = lines.filter(
|
|
92
|
+
lines = lines.filter(line => {
|
|
94
93
|
// Preserve diff content lines even if their content looks like metadata
|
|
95
94
|
// Note: `--- ` and `+++ ` are metadata, not content lines
|
|
96
95
|
if (isDiffContentLine(line)) {
|
|
@@ -130,12 +129,12 @@ export function normalizeDiff(diff: string): string {
|
|
|
130
129
|
*/
|
|
131
130
|
export function normalizeCreateContent(content: string): string {
|
|
132
131
|
const lines = content.split("\n");
|
|
133
|
-
const nonEmptyLines = lines.filter(
|
|
132
|
+
const nonEmptyLines = lines.filter(l => l.length > 0);
|
|
134
133
|
|
|
135
134
|
// Check if all non-empty lines start with "+ " or "+"
|
|
136
|
-
if (nonEmptyLines.length > 0 && nonEmptyLines.every(
|
|
135
|
+
if (nonEmptyLines.length > 0 && nonEmptyLines.every(l => l.startsWith("+ ") || l.startsWith("+"))) {
|
|
137
136
|
return lines
|
|
138
|
-
.map(
|
|
137
|
+
.map(l => {
|
|
139
138
|
if (l.startsWith("+ ")) return l.slice(2);
|
|
140
139
|
if (l.startsWith("+")) return l.slice(1);
|
|
141
140
|
return l;
|
|
@@ -390,18 +389,18 @@ function parseOneHunk(lines: string[], lineNumber: number, allowMissingContext:
|
|
|
390
389
|
}
|
|
391
390
|
|
|
392
391
|
function stripLineNumberPrefixes(hunk: DiffHunk): void {
|
|
393
|
-
const allLines = [...hunk.oldLines, ...hunk.newLines].filter(
|
|
392
|
+
const allLines = [...hunk.oldLines, ...hunk.newLines].filter(line => line.trim().length > 0);
|
|
394
393
|
if (allLines.length < 2) return;
|
|
395
394
|
|
|
396
395
|
const numberMatches = allLines
|
|
397
|
-
.map(
|
|
396
|
+
.map(line => line.match(/^\s*(\d{1,6})\s+(.+)$/u))
|
|
398
397
|
.filter((match): match is RegExpMatchArray => match !== null);
|
|
399
398
|
|
|
400
399
|
if (numberMatches.length < Math.max(2, Math.ceil(allLines.length * 0.6))) {
|
|
401
400
|
return;
|
|
402
401
|
}
|
|
403
402
|
|
|
404
|
-
const numbers = numberMatches.map(
|
|
403
|
+
const numbers = numberMatches.map(match => Number(match[1]));
|
|
405
404
|
let sequential = 0;
|
|
406
405
|
for (let i = 1; i < numbers.length; i++) {
|
|
407
406
|
if (numbers[i] === numbers[i - 1] + 1) {
|
|
@@ -515,7 +514,7 @@ export function parseHunks(diff: string): DiffHunk[] {
|
|
|
515
514
|
continue;
|
|
516
515
|
}
|
|
517
516
|
|
|
518
|
-
if (trimmed.startsWith("@@") && lines.slice(i + 1).every(
|
|
517
|
+
if (trimmed.startsWith("@@") && lines.slice(i + 1).every(l => l.trim() === "")) {
|
|
519
518
|
break;
|
|
520
519
|
}
|
|
521
520
|
|
package/src/patch/shared.ts
CHANGED
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Shared utilities for edit tool TUI rendering.
|
|
3
3
|
*/
|
|
4
|
-
|
|
5
4
|
import type { ToolCallContext } from "@oh-my-pi/pi-agent-core";
|
|
6
|
-
import type {
|
|
7
|
-
import
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
import
|
|
5
|
+
import type { Component } from "@oh-my-pi/pi-tui";
|
|
6
|
+
import { Text } from "@oh-my-pi/pi-tui";
|
|
7
|
+
import type { RenderResultOptions } from "../extensibility/custom-tools/types";
|
|
8
|
+
import type { FileDiagnosticsResult } from "../lsp";
|
|
9
|
+
import { renderDiff as renderDiffColored } from "../modes/components/diff";
|
|
10
|
+
import { getLanguageFromPath, type Theme } from "../modes/theme/theme";
|
|
11
|
+
import type { OutputMeta } from "../tools/output-meta";
|
|
11
12
|
import {
|
|
12
13
|
formatExpandHint,
|
|
13
14
|
formatStatusIcon,
|
|
@@ -15,10 +16,9 @@ import {
|
|
|
15
16
|
shortenPath,
|
|
16
17
|
ToolUIKit,
|
|
17
18
|
truncateDiffByHunk,
|
|
18
|
-
} from "
|
|
19
|
-
import type { RenderCallOptions } from "
|
|
20
|
-
import
|
|
21
|
-
import { Text } from "@oh-my-pi/pi-tui";
|
|
19
|
+
} from "../tools/render-utils";
|
|
20
|
+
import type { RenderCallOptions } from "../tools/renderers";
|
|
21
|
+
import { renderStatusLine } from "../tui";
|
|
22
22
|
import type { DiffError, DiffResult, Operation } from "./types";
|
|
23
23
|
|
|
24
24
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
@@ -37,7 +37,7 @@ export function getLspBatchRequest(toolCall: ToolCallContext | undefined): { id:
|
|
|
37
37
|
if (!hasOtherWrites) {
|
|
38
38
|
return undefined;
|
|
39
39
|
}
|
|
40
|
-
const hasLaterWrites = toolCall.toolCalls.slice(toolCall.index + 1).some(
|
|
40
|
+
const hasLaterWrites = toolCall.toolCalls.slice(toolCall.index + 1).some(call => LSP_BATCH_TOOLS.has(call.name));
|
|
41
41
|
return { id: toolCall.batchId, flush: !hasLaterWrites };
|
|
42
42
|
}
|
|
43
43
|
|
|
@@ -178,9 +178,28 @@ export const editToolRenderer = {
|
|
|
178
178
|
let text = `${ui.title(opTitle)} ${spinner ? `${spinner} ` : ""}${editIcon} ${pathDisplay}`;
|
|
179
179
|
|
|
180
180
|
// Show streaming preview of diff/content
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
181
|
+
if (args.diff && args.op) {
|
|
182
|
+
text += formatStreamingDiff(args.diff, rawPath, uiTheme);
|
|
183
|
+
} else if (args.diff) {
|
|
184
|
+
const previewLines = args.diff.split("\n");
|
|
185
|
+
const maxLines = 6;
|
|
186
|
+
text += "\n\n";
|
|
187
|
+
for (const line of previewLines.slice(0, maxLines)) {
|
|
188
|
+
text += `${uiTheme.fg("toolOutput", ui.truncate(line, 80))}\n`;
|
|
189
|
+
}
|
|
190
|
+
if (previewLines.length > maxLines) {
|
|
191
|
+
text += uiTheme.fg("dim", `${uiTheme.format.ellipsis} ${previewLines.length - maxLines} more lines`);
|
|
192
|
+
}
|
|
193
|
+
} else if (args.newText || args.patch) {
|
|
194
|
+
const previewLines = (args.newText ?? args.patch ?? "").split("\n");
|
|
195
|
+
const maxLines = 6;
|
|
196
|
+
text += "\n\n";
|
|
197
|
+
for (const line of previewLines.slice(0, maxLines)) {
|
|
198
|
+
text += `${uiTheme.fg("toolOutput", ui.truncate(line, 80))}\n`;
|
|
199
|
+
}
|
|
200
|
+
if (previewLines.length > maxLines) {
|
|
201
|
+
text += uiTheme.fg("dim", `${uiTheme.format.ellipsis} ${previewLines.length - maxLines} more lines`);
|
|
202
|
+
}
|
|
184
203
|
}
|
|
185
204
|
|
|
186
205
|
return new Text(text, 0, 0);
|
|
@@ -221,7 +240,15 @@ export const editToolRenderer = {
|
|
|
221
240
|
|
|
222
241
|
// Show operation type for patch mode
|
|
223
242
|
const opTitle = op === "create" ? "Create" : op === "delete" ? "Delete" : "Edit";
|
|
224
|
-
|
|
243
|
+
const header = renderStatusLine(
|
|
244
|
+
{
|
|
245
|
+
icon: result.isError ? "error" : "success",
|
|
246
|
+
title: opTitle,
|
|
247
|
+
description: `${editIcon} ${pathDisplay}`,
|
|
248
|
+
},
|
|
249
|
+
uiTheme,
|
|
250
|
+
);
|
|
251
|
+
let text = header;
|
|
225
252
|
|
|
226
253
|
// Skip metadata line for delete operations
|
|
227
254
|
if (op !== "delete") {
|
|
@@ -231,7 +258,7 @@ export const editToolRenderer = {
|
|
|
231
258
|
|
|
232
259
|
if (result.isError) {
|
|
233
260
|
// Show error from result
|
|
234
|
-
const errorText = result.content?.find(
|
|
261
|
+
const errorText = result.content?.find(c => c.type === "text")?.text ?? "";
|
|
235
262
|
if (errorText) {
|
|
236
263
|
text += `\n\n${uiTheme.fg("error", errorText)}`;
|
|
237
264
|
}
|
|
@@ -59,6 +59,8 @@ Results are keyed by task `id` (e.g., "AuthProvider", "AuthApi").
|
|
|
59
59
|
If you discussed requirements, plans, schemas, or decisions with the user, you MUST include that information in `context`. Subagents cannot see prior messages—they start fresh with only what you explicitly pass them.
|
|
60
60
|
|
|
61
61
|
**Never call Task multiple times in parallel.** Use a single Task call with multiple entries in the `tasks` array. Parallel Task calls waste resources and bypass coordination.
|
|
62
|
+
|
|
63
|
+
**For code changes, subagents write files directly.** Never ask an agent to "return the changes" for you to apply—they have Edit and Write tools. Their context window holds the work; asking them to report back wastes it.
|
|
62
64
|
</critical>
|
|
63
65
|
|
|
64
66
|
<example>
|
package/src/sdk.ts
CHANGED
|
@@ -25,32 +25,30 @@
|
|
|
25
25
|
* });
|
|
26
26
|
* ```
|
|
27
27
|
*/
|
|
28
|
-
|
|
29
|
-
import
|
|
28
|
+
import * as fs from "node:fs";
|
|
29
|
+
import * as path from "node:path";
|
|
30
30
|
import { Agent, type AgentEvent, type AgentMessage, type AgentTool, type ThinkingLevel } from "@oh-my-pi/pi-agent-core";
|
|
31
31
|
import { type Message, type Model, supportsXhigh } from "@oh-my-pi/pi-ai";
|
|
32
|
-
import { loadCapability } from "@oh-my-pi/pi-coding-agent/capability/index";
|
|
33
|
-
import { type Rule, ruleCapability } from "@oh-my-pi/pi-coding-agent/capability/rule";
|
|
34
|
-
import { getAgentDir, getConfigDirPaths } from "@oh-my-pi/pi-coding-agent/config";
|
|
35
32
|
import type { Component } from "@oh-my-pi/pi-tui";
|
|
36
|
-
// Import discovery to register all providers on startup
|
|
37
33
|
import { logger, postmortem } from "@oh-my-pi/pi-utils";
|
|
34
|
+
import { YAML } from "bun";
|
|
38
35
|
import chalk from "chalk";
|
|
39
|
-
|
|
40
|
-
import {
|
|
41
|
-
import {
|
|
42
|
-
import {
|
|
43
|
-
import { disposeAllKernelSessions } from "@oh-my-pi/pi-coding-agent/ipy/executor";
|
|
44
|
-
import { closeAllConnections } from "@oh-my-pi/pi-coding-agent/ssh/connection-manager";
|
|
45
|
-
import { unmountAll } from "@oh-my-pi/pi-coding-agent/ssh/sshfs-mount";
|
|
36
|
+
// Import discovery to register all providers on startup
|
|
37
|
+
import { loadCapability } from "./capability";
|
|
38
|
+
import { type Rule, ruleCapability } from "./capability/rule";
|
|
39
|
+
import { getAgentDir, getConfigDirPaths } from "./config";
|
|
46
40
|
import { ModelRegistry } from "./config/model-registry";
|
|
47
41
|
import { formatModelString, parseModelString } from "./config/model-resolver";
|
|
48
42
|
import { loadPromptTemplates as loadPromptTemplatesInternal, type PromptTemplate } from "./config/prompt-templates";
|
|
49
43
|
import { type Settings, SettingsManager, type SkillsSettings } from "./config/settings-manager";
|
|
44
|
+
import { CursorExecHandlers } from "./cursor";
|
|
45
|
+
import "./discovery";
|
|
46
|
+
import { initializeWithSettings } from "./discovery";
|
|
47
|
+
import { TtsrManager } from "./export/ttsr";
|
|
50
48
|
import {
|
|
51
49
|
type CustomCommandsLoadResult,
|
|
52
50
|
loadCustomCommands as loadCustomCommandsInternal,
|
|
53
|
-
} from "./extensibility/custom-commands
|
|
51
|
+
} from "./extensibility/custom-commands";
|
|
54
52
|
import type { CustomTool, CustomToolContext, CustomToolSessionEvent } from "./extensibility/custom-tools/types";
|
|
55
53
|
import {
|
|
56
54
|
discoverAndLoadExtensions,
|
|
@@ -64,7 +62,7 @@ import {
|
|
|
64
62
|
loadExtensions,
|
|
65
63
|
type ToolDefinition,
|
|
66
64
|
wrapRegisteredTools,
|
|
67
|
-
} from "./extensibility/extensions
|
|
65
|
+
} from "./extensibility/extensions";
|
|
68
66
|
import { loadSkills as loadSkillsInternal, type Skill, type SkillWarning } from "./extensibility/skills";
|
|
69
67
|
import { type FileSlashCommand, loadSlashCommands as loadSlashCommandsInternal } from "./extensibility/slash-commands";
|
|
70
68
|
import {
|
|
@@ -74,18 +72,20 @@ import {
|
|
|
74
72
|
RuleProtocolHandler,
|
|
75
73
|
SkillProtocolHandler,
|
|
76
74
|
} from "./internal-urls";
|
|
77
|
-
import {
|
|
75
|
+
import { disposeAllKernelSessions } from "./ipy/executor";
|
|
76
|
+
import { discoverAndLoadMCPTools, type MCPManager, type MCPToolsLoadResult } from "./mcp";
|
|
78
77
|
import { AgentSession } from "./session/agent-session";
|
|
79
78
|
import { AuthStorage } from "./session/auth-storage";
|
|
80
79
|
import { convertToLlm } from "./session/messages";
|
|
81
80
|
import { SessionManager } from "./session/session-manager";
|
|
82
81
|
import { migrateJsonStorage } from "./session/storage-migration";
|
|
82
|
+
import { closeAllConnections } from "./ssh/connection-manager";
|
|
83
|
+
import { unmountAll } from "./ssh/sshfs-mount";
|
|
83
84
|
import {
|
|
84
85
|
buildSystemPrompt as buildSystemPromptInternal,
|
|
85
86
|
loadProjectContextFiles as loadContextFilesInternal,
|
|
86
87
|
} from "./system-prompt";
|
|
87
|
-
import {
|
|
88
|
-
import { getGeminiImageTools } from "./tools/gemini-image";
|
|
88
|
+
import { AgentOutputManager } from "./task/output-manager";
|
|
89
89
|
import {
|
|
90
90
|
BashTool,
|
|
91
91
|
BUILTIN_TOOLS,
|
|
@@ -104,7 +104,9 @@ import {
|
|
|
104
104
|
type ToolSession,
|
|
105
105
|
WriteTool,
|
|
106
106
|
warmupLspServers,
|
|
107
|
-
} from "./tools
|
|
107
|
+
} from "./tools";
|
|
108
|
+
import { ToolContextStore } from "./tools/context";
|
|
109
|
+
import { getGeminiImageTools } from "./tools/gemini-image";
|
|
108
110
|
import { wrapToolsWithMetaNotice } from "./tools/output-meta";
|
|
109
111
|
import { EventBus } from "./utils/event-bus";
|
|
110
112
|
import { time } from "./utils/timings";
|
|
@@ -201,24 +203,21 @@ export interface CreateAgentSessionResult {
|
|
|
201
203
|
|
|
202
204
|
// Re-exports
|
|
203
205
|
|
|
204
|
-
export type { PromptTemplate } from "
|
|
205
|
-
export type { Settings, SkillsSettings } from "
|
|
206
|
-
export type {
|
|
207
|
-
|
|
208
|
-
CustomCommandFactory,
|
|
209
|
-
} from "@oh-my-pi/pi-coding-agent/extensibility/custom-commands/types";
|
|
210
|
-
export type { CustomTool, CustomToolFactory } from "@oh-my-pi/pi-coding-agent/extensibility/custom-tools/types";
|
|
206
|
+
export type { PromptTemplate } from "./config/prompt-templates";
|
|
207
|
+
export type { Settings, SkillsSettings } from "./config/settings-manager";
|
|
208
|
+
export type { CustomCommand, CustomCommandFactory } from "./extensibility/custom-commands/types";
|
|
209
|
+
export type { CustomTool, CustomToolFactory } from "./extensibility/custom-tools/types";
|
|
211
210
|
export type {
|
|
212
211
|
ExtensionAPI,
|
|
213
212
|
ExtensionCommandContext,
|
|
214
213
|
ExtensionContext,
|
|
215
214
|
ExtensionFactory,
|
|
216
215
|
ToolDefinition,
|
|
217
|
-
} from "
|
|
218
|
-
export type { Skill } from "
|
|
219
|
-
export type { FileSlashCommand } from "
|
|
220
|
-
export type { MCPManager, MCPServerConfig, MCPServerConnection, MCPToolsLoadResult } from "./mcp
|
|
221
|
-
export type { Tool } from "./tools
|
|
216
|
+
} from "./extensibility/extensions";
|
|
217
|
+
export type { Skill } from "./extensibility/skills";
|
|
218
|
+
export type { FileSlashCommand } from "./extensibility/slash-commands";
|
|
219
|
+
export type { MCPManager, MCPServerConfig, MCPServerConnection, MCPToolsLoadResult } from "./mcp";
|
|
220
|
+
export type { Tool } from "./tools";
|
|
222
221
|
|
|
223
222
|
export {
|
|
224
223
|
// Individual tool classes (for custom usage)
|
|
@@ -250,43 +249,80 @@ function getDefaultAgentDir(): string {
|
|
|
250
249
|
* Reads from primary path first, then falls back to legacy paths (.pi, .claude).
|
|
251
250
|
*/
|
|
252
251
|
export async function discoverAuthStorage(agentDir: string = getDefaultAgentDir()): Promise<AuthStorage> {
|
|
253
|
-
const primaryPath = join(agentDir, "auth.json");
|
|
252
|
+
const primaryPath = path.join(agentDir, "auth.json");
|
|
254
253
|
// Get all auth.json paths (user-level only), excluding the primary
|
|
255
254
|
const allPaths = getConfigDirPaths("auth.json", { project: false });
|
|
256
|
-
const fallbackPaths = allPaths.filter(
|
|
255
|
+
const fallbackPaths = allPaths.filter(p => p !== primaryPath);
|
|
257
256
|
|
|
258
257
|
logger.debug("discoverAuthStorage", { agentDir, primaryPath, allPaths, fallbackPaths });
|
|
259
258
|
|
|
260
259
|
// Migrate legacy JSON files (settings.json, auth.json) to SQLite before loading
|
|
261
260
|
await migrateJsonStorage({
|
|
262
261
|
agentDir,
|
|
263
|
-
settingsPath: join(agentDir, "settings.json"),
|
|
262
|
+
settingsPath: path.join(agentDir, "settings.json"),
|
|
264
263
|
authPaths: [primaryPath, ...fallbackPaths],
|
|
265
264
|
});
|
|
266
265
|
|
|
267
|
-
const storage =
|
|
266
|
+
const storage = await AuthStorage.create(primaryPath, fallbackPaths);
|
|
268
267
|
await storage.reload();
|
|
269
268
|
return storage;
|
|
270
269
|
}
|
|
271
270
|
|
|
272
271
|
/**
|
|
273
272
|
* Create a ModelRegistry with fallback support.
|
|
274
|
-
* Reads from primary path first,
|
|
273
|
+
* Prefers models.yml over models.json. Reads from primary path first,
|
|
274
|
+
* then falls back to legacy paths (.pi, .claude).
|
|
275
275
|
*/
|
|
276
|
-
export
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
276
|
+
export function discoverModels(authStorage: AuthStorage, agentDir: string = getDefaultAgentDir()): ModelRegistry {
|
|
277
|
+
const yamlPath = path.join(agentDir, "models.yml");
|
|
278
|
+
const jsonPath = path.join(agentDir, "models.json");
|
|
279
|
+
|
|
280
|
+
// Check existence of yaml and json files
|
|
281
|
+
let yamlExists = fs.existsSync(yamlPath);
|
|
282
|
+
let jsonExists = fs.existsSync(jsonPath);
|
|
283
|
+
|
|
284
|
+
// Migrate models.json to models.yml if yaml doesn't exist but json does
|
|
285
|
+
if (!yamlExists && jsonExists) {
|
|
286
|
+
migrateModelsJsonToYaml(jsonPath, yamlPath);
|
|
287
|
+
yamlExists = fs.existsSync(yamlPath);
|
|
288
|
+
jsonExists = fs.existsSync(jsonPath);
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
// Prefer models.yml, fall back to models.json
|
|
292
|
+
const primaryPath = yamlExists ? yamlPath : jsonPath;
|
|
293
|
+
|
|
294
|
+
// Get all models config paths (user-level only), excluding the primary
|
|
295
|
+
const yamlPaths = getConfigDirPaths("models.yml", { project: false });
|
|
296
|
+
const jsonPaths = getConfigDirPaths("models.json", { project: false });
|
|
297
|
+
const allPaths = [...yamlPaths, ...jsonPaths];
|
|
298
|
+
const existenceResults = allPaths.map(p => {
|
|
299
|
+
return { p, exists: fs.existsSync(p) };
|
|
300
|
+
});
|
|
301
|
+
const fallbackPaths = existenceResults.filter(({ p, exists }) => p !== primaryPath && exists).map(({ p }) => p);
|
|
284
302
|
|
|
285
303
|
logger.debug("discoverModels", { primaryPath, fallbackPaths });
|
|
304
|
+
return new ModelRegistry(authStorage, primaryPath, fallbackPaths);
|
|
305
|
+
}
|
|
286
306
|
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
307
|
+
/**
|
|
308
|
+
* Migrate models.json to models.yml.
|
|
309
|
+
* Creates models.yml from models.json and renames the json file to .bak.
|
|
310
|
+
*/
|
|
311
|
+
function migrateModelsJsonToYaml(jsonPath: string, yamlPath: string): void {
|
|
312
|
+
try {
|
|
313
|
+
const content = fs.readFileSync(jsonPath, "utf-8");
|
|
314
|
+
const parsed = JSON.parse(content);
|
|
315
|
+
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
316
|
+
logger.warn("migrateModelsJsonToYaml: invalid models.json structure", { path: jsonPath });
|
|
317
|
+
return;
|
|
318
|
+
}
|
|
319
|
+
fs.mkdirSync(path.dirname(yamlPath), { recursive: true });
|
|
320
|
+
fs.writeFileSync(yamlPath, YAML.stringify(parsed, null, 2));
|
|
321
|
+
fs.renameSync(jsonPath, `${jsonPath}.bak`);
|
|
322
|
+
logger.debug("migrateModelsJsonToYaml: migrated models.json to models.yml", { from: jsonPath, to: yamlPath });
|
|
323
|
+
} catch (error) {
|
|
324
|
+
logger.warn("migrateModelsJsonToYaml: migration failed", { error: String(error) });
|
|
325
|
+
}
|
|
290
326
|
}
|
|
291
327
|
|
|
292
328
|
/**
|
|
@@ -487,7 +523,7 @@ function customToolToDefinition(tool: CustomTool): ToolDefinition {
|
|
|
487
523
|
}
|
|
488
524
|
|
|
489
525
|
function createCustomToolsExtension(tools: CustomTool[]): ExtensionFactory {
|
|
490
|
-
return
|
|
526
|
+
return api => {
|
|
491
527
|
for (const tool of tools) {
|
|
492
528
|
api.registerTool(customToolToDefinition(tool));
|
|
493
529
|
}
|
|
@@ -564,7 +600,7 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
|
|
|
564
600
|
|
|
565
601
|
// Use provided or create AuthStorage and ModelRegistry
|
|
566
602
|
const authStorage = options.authStorage ?? (await discoverAuthStorage(agentDir));
|
|
567
|
-
const modelRegistry = options.modelRegistry ??
|
|
603
|
+
const modelRegistry = options.modelRegistry ?? discoverModels(authStorage, agentDir);
|
|
568
604
|
time("discoverModels");
|
|
569
605
|
|
|
570
606
|
const settingsManager = options.settingsManager ?? (await SettingsManager.create(cwd, agentDir));
|
|
@@ -622,9 +658,9 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
|
|
|
622
658
|
if (!model) {
|
|
623
659
|
const allModels = modelRegistry.getAll();
|
|
624
660
|
const keyResults = await Promise.all(
|
|
625
|
-
allModels.map(async
|
|
661
|
+
allModels.map(async m => ({ model: m, hasKey: !!(await modelRegistry.getApiKey(m, sessionId)) })),
|
|
626
662
|
);
|
|
627
|
-
model = keyResults.find(
|
|
663
|
+
model = keyResults.find(r => r.hasKey)?.model;
|
|
628
664
|
time("findAvailableModel");
|
|
629
665
|
if (model) {
|
|
630
666
|
if (modelFallbackMessage) {
|
|
@@ -734,6 +770,7 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
|
|
|
734
770
|
);
|
|
735
771
|
toolSession.internalRouter = internalRouter;
|
|
736
772
|
toolSession.getArtifactsDir = getArtifactsDir;
|
|
773
|
+
toolSession.agentOutputManager = new AgentOutputManager(getArtifactsDir);
|
|
737
774
|
|
|
738
775
|
// Create and wrap tools with meta notice formatting
|
|
739
776
|
const rawBuiltinTools = await createTools(toolSession, options.toolNames);
|
|
@@ -746,7 +783,7 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
|
|
|
746
783
|
const customTools: CustomTool[] = [];
|
|
747
784
|
if (enableMCP) {
|
|
748
785
|
const mcpResult = await discoverAndLoadMCPTools(cwd, {
|
|
749
|
-
onConnecting:
|
|
786
|
+
onConnecting: serverNames => {
|
|
750
787
|
if (options.hasUI && serverNames.length > 0) {
|
|
751
788
|
process.stderr.write(
|
|
752
789
|
chalk.gray(`Connecting to MCP servers: ${serverNames.join(", ")}...
|
|
@@ -775,7 +812,7 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
|
|
|
775
812
|
|
|
776
813
|
if (mcpResult.tools.length > 0) {
|
|
777
814
|
// MCP tools are LoadedCustomTool, extract the tool property
|
|
778
|
-
customTools.push(...mcpResult.tools.map(
|
|
815
|
+
customTools.push(...mcpResult.tools.map(loaded => loaded.tool));
|
|
779
816
|
}
|
|
780
817
|
}
|
|
781
818
|
|
|
@@ -794,7 +831,7 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
|
|
|
794
831
|
enableCompany: exaSettings.enableCompany,
|
|
795
832
|
});
|
|
796
833
|
// Filter out the base web_search (already in built-in tools), add specialized Exa tools
|
|
797
|
-
const specializedTools = exaWebSearchTools.filter(
|
|
834
|
+
const specializedTools = exaWebSearchTools.filter(t => t.name !== "web_search");
|
|
798
835
|
if (specializedTools.length > 0) {
|
|
799
836
|
customTools.push(...specializedTools);
|
|
800
837
|
}
|
|
@@ -884,7 +921,7 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
|
|
|
884
921
|
const registeredTools = extensionRunner?.getAllRegisteredTools() ?? [];
|
|
885
922
|
const allCustomTools = [
|
|
886
923
|
...registeredTools,
|
|
887
|
-
...(options.customTools?.map(
|
|
924
|
+
...(options.customTools?.map(tool => {
|
|
888
925
|
const definition = isCustomTool(tool) ? customToolToDefinition(tool) : tool;
|
|
889
926
|
return { definition, extensionPath: "<sdk>" };
|
|
890
927
|
}) ?? []),
|
|
@@ -914,7 +951,7 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
|
|
|
914
951
|
cwd,
|
|
915
952
|
tools: toolRegistry,
|
|
916
953
|
getToolContext: () => toolContextStore.getContext(),
|
|
917
|
-
emitEvent:
|
|
954
|
+
emitEvent: event => cursorEventEmitter?.(event),
|
|
918
955
|
});
|
|
919
956
|
|
|
920
957
|
const rebuildSystemPrompt = async (toolNames: string[], tools: Map<string, AgentTool>): Promise<string> => {
|
|
@@ -964,16 +1001,14 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
|
|
|
964
1001
|
return converted;
|
|
965
1002
|
}
|
|
966
1003
|
// Filter out ImageContent from all messages, replacing with text placeholder
|
|
967
|
-
return converted.map(
|
|
1004
|
+
return converted.map(msg => {
|
|
968
1005
|
if (msg.role === "user" || msg.role === "toolResult") {
|
|
969
1006
|
const content = msg.content;
|
|
970
1007
|
if (Array.isArray(content)) {
|
|
971
|
-
const hasImages = content.some(
|
|
1008
|
+
const hasImages = content.some(c => c.type === "image");
|
|
972
1009
|
if (hasImages) {
|
|
973
1010
|
const filteredContent = content
|
|
974
|
-
.map((c)
|
|
975
|
-
c.type === "image" ? { type: "text" as const, text: "Image reading is disabled." } : c,
|
|
976
|
-
)
|
|
1011
|
+
.map(c => (c.type === "image" ? { type: "text" as const, text: "Image reading is disabled." } : c))
|
|
977
1012
|
.filter(
|
|
978
1013
|
(c, i, arr) =>
|
|
979
1014
|
// Dedupe consecutive "Image reading is disabled." texts
|
|
@@ -1007,7 +1042,7 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
|
|
|
1007
1042
|
convertToLlm: convertToLlmWithBlockImages,
|
|
1008
1043
|
sessionId: sessionManager.getSessionId(),
|
|
1009
1044
|
transformContext: extensionRunner
|
|
1010
|
-
? async
|
|
1045
|
+
? async messages => {
|
|
1011
1046
|
return extensionRunner.emitContext(messages);
|
|
1012
1047
|
}
|
|
1013
1048
|
: undefined,
|
|
@@ -1015,7 +1050,7 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
|
|
|
1015
1050
|
followUpMode: settingsManager.getFollowUpMode(),
|
|
1016
1051
|
interruptMode: settingsManager.getInterruptMode(),
|
|
1017
1052
|
thinkingBudgets: settingsManager.getThinkingBudgets(),
|
|
1018
|
-
getToolContext:
|
|
1053
|
+
getToolContext: tc => toolContextStore.getContext(tc),
|
|
1019
1054
|
getApiKey: async () => {
|
|
1020
1055
|
const currentModel = agent.state.model;
|
|
1021
1056
|
if (!currentModel) {
|
|
@@ -1029,7 +1064,7 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
|
|
|
1029
1064
|
},
|
|
1030
1065
|
cursorExecHandlers,
|
|
1031
1066
|
});
|
|
1032
|
-
cursorEventEmitter =
|
|
1067
|
+
cursorEventEmitter = event => agent.emitExternalEvent(event);
|
|
1033
1068
|
time("createAgent");
|
|
1034
1069
|
|
|
1035
1070
|
// Restore messages if session has existing data
|
|
@@ -1067,7 +1102,7 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
|
|
|
1067
1102
|
if (enableLsp && settingsManager.getLspDiagnosticsOnWrite()) {
|
|
1068
1103
|
try {
|
|
1069
1104
|
const result = await warmupLspServers(cwd, {
|
|
1070
|
-
onConnecting:
|
|
1105
|
+
onConnecting: serverNames => {
|
|
1071
1106
|
if (options.hasUI && serverNames.length > 0) {
|
|
1072
1107
|
process.stderr.write(chalk.gray(`Starting LSP servers: ${serverNames.join(", ")}...\n`));
|
|
1073
1108
|
}
|