@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/tools/read.ts
CHANGED
|
@@ -1,27 +1,28 @@
|
|
|
1
|
-
import
|
|
1
|
+
import * as os from "node:os";
|
|
2
2
|
import path from "node:path";
|
|
3
3
|
import type { AgentTool, AgentToolContext, AgentToolResult, AgentToolUpdateCallback } from "@oh-my-pi/pi-agent-core";
|
|
4
4
|
import type { ImageContent, TextContent } from "@oh-my-pi/pi-ai";
|
|
5
|
-
import { CONFIG_DIR_NAME } from "@oh-my-pi/pi-coding-agent/config";
|
|
6
|
-
import { renderPromptTemplate } from "@oh-my-pi/pi-coding-agent/config/prompt-templates";
|
|
7
|
-
import type { RenderResultOptions } from "@oh-my-pi/pi-coding-agent/extensibility/custom-tools/types";
|
|
8
|
-
import type { Theme } from "@oh-my-pi/pi-coding-agent/modes/theme/theme";
|
|
9
|
-
import readDescription from "@oh-my-pi/pi-coding-agent/prompts/tools/read.md" with { type: "text" };
|
|
10
|
-
import type { ToolSession } from "@oh-my-pi/pi-coding-agent/sdk";
|
|
11
|
-
import type { OutputMeta } from "@oh-my-pi/pi-coding-agent/tools/output-meta";
|
|
12
|
-
import { ToolAbortError, ToolError, throwIfAborted } from "@oh-my-pi/pi-coding-agent/tools/tool-errors";
|
|
13
|
-
import { formatDimensionNote, resizeImage } from "@oh-my-pi/pi-coding-agent/utils/image-resize";
|
|
14
|
-
import { detectSupportedImageMimeTypeFromFile } from "@oh-my-pi/pi-coding-agent/utils/mime";
|
|
15
|
-
import { ensureTool } from "@oh-my-pi/pi-coding-agent/utils/tools-manager";
|
|
16
5
|
import type { Component } from "@oh-my-pi/pi-tui";
|
|
17
6
|
import { Text } from "@oh-my-pi/pi-tui";
|
|
18
7
|
import { ptree } from "@oh-my-pi/pi-utils";
|
|
19
8
|
import { Type } from "@sinclair/typebox";
|
|
9
|
+
import { CONFIG_DIR_NAME } from "../config";
|
|
10
|
+
import { renderPromptTemplate } from "../config/prompt-templates";
|
|
11
|
+
import type { RenderResultOptions } from "../extensibility/custom-tools/types";
|
|
12
|
+
import { getLanguageFromPath, type Theme } from "../modes/theme/theme";
|
|
13
|
+
import readDescription from "../prompts/tools/read.md" with { type: "text" };
|
|
14
|
+
import type { ToolSession } from "../sdk";
|
|
15
|
+
import { renderCodeCell, renderOutputBlock, renderStatusLine } from "../tui";
|
|
16
|
+
import { formatDimensionNote, resizeImage } from "../utils/image-resize";
|
|
17
|
+
import { detectSupportedImageMimeTypeFromFile } from "../utils/mime";
|
|
18
|
+
import { ensureTool } from "../utils/tools-manager";
|
|
20
19
|
import { runFd } from "./find";
|
|
21
20
|
import { applyListLimit } from "./list-limit";
|
|
22
21
|
import { LsTool } from "./ls";
|
|
22
|
+
import type { OutputMeta } from "./output-meta";
|
|
23
23
|
import { resolveReadPath, resolveToCwd } from "./path-utils";
|
|
24
24
|
import { shortenPath, wrapBrackets } from "./render-utils";
|
|
25
|
+
import { ToolAbortError, ToolError, throwIfAborted } from "./tool-errors";
|
|
25
26
|
import { toolResult } from "./tool-result";
|
|
26
27
|
import {
|
|
27
28
|
DEFAULT_MAX_BYTES,
|
|
@@ -36,7 +37,7 @@ import {
|
|
|
36
37
|
const CONVERTIBLE_EXTENSIONS = new Set([".pdf", ".doc", ".docx", ".ppt", ".pptx", ".xls", ".xlsx", ".rtf", ".epub"]);
|
|
37
38
|
|
|
38
39
|
// Remote mount path prefix (sshfs mounts) - skip fuzzy matching to avoid hangs
|
|
39
|
-
const REMOTE_MOUNT_PREFIX = path.join(homedir(), CONFIG_DIR_NAME, "remote") + path.sep;
|
|
40
|
+
const REMOTE_MOUNT_PREFIX = path.join(os.homedir(), CONFIG_DIR_NAME, "remote") + path.sep;
|
|
40
41
|
|
|
41
42
|
function isRemoteMountPath(absolutePath: string): boolean {
|
|
42
43
|
return absolutePath.startsWith(REMOTE_MOUNT_PREFIX);
|
|
@@ -201,8 +202,8 @@ async function listCandidateFiles(
|
|
|
201
202
|
if (output) {
|
|
202
203
|
const nestedGitignores = output
|
|
203
204
|
.split("\n")
|
|
204
|
-
.map(
|
|
205
|
-
.filter(
|
|
205
|
+
.map(line => line.replace(/\r$/, "").trim())
|
|
206
|
+
.filter(line => line.length > 0);
|
|
206
207
|
for (const file of nestedGitignores) {
|
|
207
208
|
const normalized = file.replace(/\\/g, "/");
|
|
208
209
|
if (normalized.includes("/node_modules/") || normalized.includes("/.git/")) {
|
|
@@ -237,8 +238,8 @@ async function listCandidateFiles(
|
|
|
237
238
|
|
|
238
239
|
const files = output
|
|
239
240
|
.split("\n")
|
|
240
|
-
.map(
|
|
241
|
-
.filter(
|
|
241
|
+
.map(line => line.replace(/\r$/, "").trim())
|
|
242
|
+
.filter(line => line.length > 0);
|
|
242
243
|
|
|
243
244
|
return { files, truncated: files.length >= MAX_FUZZY_CANDIDATES };
|
|
244
245
|
}
|
|
@@ -336,7 +337,7 @@ async function findReadPathSuggestions(
|
|
|
336
337
|
});
|
|
337
338
|
|
|
338
339
|
const listLimit = applyListLimit(matches, { limit: MAX_FUZZY_RESULTS });
|
|
339
|
-
const suggestions = listLimit.items.map(
|
|
340
|
+
const suggestions = listLimit.items.map(match => match.path);
|
|
340
341
|
|
|
341
342
|
return { suggestions, scopeLabel, truncated };
|
|
342
343
|
}
|
|
@@ -378,6 +379,7 @@ const readSchema = Type.Object({
|
|
|
378
379
|
export interface ReadToolDetails {
|
|
379
380
|
truncation?: TruncationResult;
|
|
380
381
|
redirectedTo?: "ls";
|
|
382
|
+
resolvedPath?: string;
|
|
381
383
|
meta?: OutputMeta;
|
|
382
384
|
}
|
|
383
385
|
|
|
@@ -444,7 +446,7 @@ export class ReadTool implements AgentTool<typeof readSchema, ReadToolDetails> {
|
|
|
444
446
|
|
|
445
447
|
if (suggestions?.suggestions.length) {
|
|
446
448
|
const scopeLabel = suggestions.scopeLabel ? ` in ${suggestions.scopeLabel}` : "";
|
|
447
|
-
message += `\n\nClosest matches${scopeLabel}:\n${suggestions.suggestions.map(
|
|
449
|
+
message += `\n\nClosest matches${scopeLabel}:\n${suggestions.suggestions.map(match => `- ${match}`).join("\n")}`;
|
|
448
450
|
if (suggestions.truncated) {
|
|
449
451
|
message += `\n[Search truncated to first ${MAX_FUZZY_CANDIDATES} paths. Refine the path if the match isn't listed.]`;
|
|
450
452
|
}
|
|
@@ -708,11 +710,11 @@ export class ReadTool implements AgentTool<typeof readSchema, ReadToolDetails> {
|
|
|
708
710
|
|
|
709
711
|
// If extraction was used, return directly (no pagination)
|
|
710
712
|
if (hasExtraction) {
|
|
711
|
-
|
|
713
|
+
const details: ReadToolDetails = {};
|
|
712
714
|
if (resource.sourcePath) {
|
|
713
|
-
|
|
715
|
+
details.resolvedPath = resource.sourcePath;
|
|
714
716
|
}
|
|
715
|
-
return toolResult
|
|
717
|
+
return toolResult(details).text(resource.content).sourceInternal(url).done();
|
|
716
718
|
}
|
|
717
719
|
|
|
718
720
|
// Apply pagination similar to file reading
|
|
@@ -806,9 +808,8 @@ export class ReadTool implements AgentTool<typeof readSchema, ReadToolDetails> {
|
|
|
806
808
|
details = {};
|
|
807
809
|
}
|
|
808
810
|
|
|
809
|
-
// Append resolved path notice
|
|
810
811
|
if (resource.sourcePath) {
|
|
811
|
-
|
|
812
|
+
details.resolvedPath = resource.sourcePath;
|
|
812
813
|
}
|
|
813
814
|
|
|
814
815
|
const resultBuilder = toolResult(details).text(outputText).sourceInternal(url);
|
|
@@ -837,14 +838,14 @@ export const readToolRenderer = {
|
|
|
837
838
|
const offset = args.offset;
|
|
838
839
|
const limit = args.limit;
|
|
839
840
|
|
|
840
|
-
let pathDisplay = filePath
|
|
841
|
+
let pathDisplay = filePath || uiTheme.format.ellipsis;
|
|
841
842
|
if (offset !== undefined || limit !== undefined) {
|
|
842
843
|
const startLine = offset ?? 1;
|
|
843
844
|
const endLine = limit !== undefined ? startLine + limit - 1 : "";
|
|
844
|
-
pathDisplay +=
|
|
845
|
+
pathDisplay += `:${startLine}${endLine ? `-${endLine}` : ""}`;
|
|
845
846
|
}
|
|
846
847
|
|
|
847
|
-
const text =
|
|
848
|
+
const text = renderStatusLine({ icon: "pending", title: "Read", description: pathDisplay }, uiTheme);
|
|
848
849
|
return new Text(text, 0, 0);
|
|
849
850
|
},
|
|
850
851
|
|
|
@@ -852,15 +853,24 @@ export const readToolRenderer = {
|
|
|
852
853
|
result: { content: Array<{ type: string; text?: string }>; details?: ReadToolDetails },
|
|
853
854
|
_options: RenderResultOptions,
|
|
854
855
|
uiTheme: Theme,
|
|
855
|
-
|
|
856
|
+
args?: ReadRenderArgs,
|
|
856
857
|
): Component {
|
|
857
858
|
const details = result.details;
|
|
858
|
-
const
|
|
859
|
-
|
|
860
|
-
|
|
859
|
+
const contentText = result.content?.find(c => c.type === "text")?.text ?? "";
|
|
860
|
+
const imageContent = result.content?.find(c => c.type === "image");
|
|
861
|
+
const rawPath = args?.file_path || args?.path || "";
|
|
862
|
+
const filePath = shortenPath(rawPath);
|
|
863
|
+
const lang = getLanguageFromPath(rawPath);
|
|
861
864
|
|
|
865
|
+
const warningLines: string[] = [];
|
|
862
866
|
const truncation = details?.meta?.truncation;
|
|
863
867
|
const fallback = details?.truncation;
|
|
868
|
+
if (details?.redirectedTo) {
|
|
869
|
+
warningLines.push(uiTheme.fg("warning", wrapBrackets(`Redirected to ${details.redirectedTo}`, uiTheme)));
|
|
870
|
+
}
|
|
871
|
+
if (details?.resolvedPath) {
|
|
872
|
+
warningLines.push(uiTheme.fg("dim", wrapBrackets(`Resolved path: ${details.resolvedPath}`, uiTheme)));
|
|
873
|
+
}
|
|
864
874
|
if (truncation) {
|
|
865
875
|
let warning: string;
|
|
866
876
|
if (fallback?.firstLineExceedsLimit) {
|
|
@@ -874,9 +884,58 @@ export const readToolRenderer = {
|
|
|
874
884
|
if (truncation.artifactId) {
|
|
875
885
|
warning += `. Full output: artifact://${truncation.artifactId}`;
|
|
876
886
|
}
|
|
877
|
-
|
|
887
|
+
warningLines.push(uiTheme.fg("warning", wrapBrackets(warning, uiTheme)));
|
|
878
888
|
}
|
|
879
889
|
|
|
880
|
-
|
|
890
|
+
if (imageContent) {
|
|
891
|
+
const header = renderStatusLine(
|
|
892
|
+
{ icon: "success", title: "Read", description: filePath || rawPath || "image" },
|
|
893
|
+
uiTheme,
|
|
894
|
+
);
|
|
895
|
+
const detailLines = contentText ? contentText.split("\n").map(line => uiTheme.fg("toolOutput", line)) : [];
|
|
896
|
+
const lines = [...detailLines, ...warningLines];
|
|
897
|
+
return {
|
|
898
|
+
render: (width: number) =>
|
|
899
|
+
renderOutputBlock(
|
|
900
|
+
{
|
|
901
|
+
header,
|
|
902
|
+
state: "success",
|
|
903
|
+
sections: [
|
|
904
|
+
{
|
|
905
|
+
label: uiTheme.fg("toolTitle", "Details"),
|
|
906
|
+
lines: lines.length > 0 ? lines : [uiTheme.fg("dim", "(image)")],
|
|
907
|
+
},
|
|
908
|
+
],
|
|
909
|
+
width,
|
|
910
|
+
},
|
|
911
|
+
uiTheme,
|
|
912
|
+
),
|
|
913
|
+
invalidate: () => {},
|
|
914
|
+
};
|
|
915
|
+
}
|
|
916
|
+
|
|
917
|
+
let title = filePath ? `Read ${filePath}` : "Read";
|
|
918
|
+
if (args?.offset !== undefined || args?.limit !== undefined) {
|
|
919
|
+
const startLine = args.offset ?? 1;
|
|
920
|
+
const endLine = args.limit !== undefined ? startLine + args.limit - 1 : "";
|
|
921
|
+
title += `:${startLine}${endLine ? `-${endLine}` : ""}`;
|
|
922
|
+
}
|
|
923
|
+
return {
|
|
924
|
+
render: (width: number) =>
|
|
925
|
+
renderCodeCell(
|
|
926
|
+
{
|
|
927
|
+
code: contentText,
|
|
928
|
+
language: lang,
|
|
929
|
+
title,
|
|
930
|
+
status: "complete",
|
|
931
|
+
output: warningLines.length > 0 ? warningLines.join("\n") : undefined,
|
|
932
|
+
expanded: true,
|
|
933
|
+
width,
|
|
934
|
+
},
|
|
935
|
+
uiTheme,
|
|
936
|
+
),
|
|
937
|
+
invalidate: () => {},
|
|
938
|
+
};
|
|
881
939
|
},
|
|
940
|
+
mergeCallAndResult: true,
|
|
882
941
|
};
|
|
@@ -4,9 +4,9 @@
|
|
|
4
4
|
* Provides consistent formatting, truncation, and display patterns across all
|
|
5
5
|
* tool renderers to ensure a unified TUI experience.
|
|
6
6
|
*/
|
|
7
|
-
|
|
8
|
-
import {
|
|
9
|
-
import
|
|
7
|
+
import * as os from "node:os";
|
|
8
|
+
import type { Theme } from "../modes/theme/theme";
|
|
9
|
+
import { getTreeBranch } from "../tui/utils";
|
|
10
10
|
|
|
11
11
|
// =============================================================================
|
|
12
12
|
// Standardized Display Constants
|
|
@@ -61,8 +61,8 @@ export function truncate(text: string, maxLen: number, ellipsis: string): string
|
|
|
61
61
|
* Get first N lines of text as preview, with each line truncated.
|
|
62
62
|
*/
|
|
63
63
|
export function getPreviewLines(text: string, maxLines: number, maxLineLen: number, ellipsis: string): string[] {
|
|
64
|
-
const lines = text.split("\n").filter(
|
|
65
|
-
return lines.slice(0, maxLines).map(
|
|
64
|
+
const lines = text.split("\n").filter(l => l.trim());
|
|
65
|
+
return lines.slice(0, maxLines).map(l => truncate(l.trim(), maxLineLen, ellipsis));
|
|
66
66
|
}
|
|
67
67
|
|
|
68
68
|
// =============================================================================
|
|
@@ -553,7 +553,7 @@ export function truncateDiffByHunk(
|
|
|
553
553
|
|
|
554
554
|
const segments = parseDiffSegments(lines);
|
|
555
555
|
|
|
556
|
-
const changeSegments = segments.filter(
|
|
556
|
+
const changeSegments = segments.filter(s => s.isChange);
|
|
557
557
|
const changeLineCount = changeSegments.reduce((sum, s) => sum + s.lines.length, 0);
|
|
558
558
|
|
|
559
559
|
if (changeLineCount > maxLines) {
|
|
@@ -578,7 +578,7 @@ export function truncateDiffByHunk(
|
|
|
578
578
|
}
|
|
579
579
|
|
|
580
580
|
const contextBudget = maxLines - changeLineCount;
|
|
581
|
-
const contextSegments = segments.filter(
|
|
581
|
+
const contextSegments = segments.filter(s => !s.isChange && !s.isEllipsis);
|
|
582
582
|
const totalContextLines = contextSegments.reduce((sum, s) => sum + s.lines.length, 0);
|
|
583
583
|
|
|
584
584
|
const kept: string[] = [];
|
|
@@ -642,7 +642,7 @@ export function truncateDiffByHunk(
|
|
|
642
642
|
// =============================================================================
|
|
643
643
|
|
|
644
644
|
export function shortenPath(filePath: string, homeDir?: string): string {
|
|
645
|
-
const home = homeDir ?? homedir();
|
|
645
|
+
const home = homeDir ?? os.homedir();
|
|
646
646
|
if (home && filePath.startsWith(home)) {
|
|
647
647
|
return `~${filePath.slice(home.length)}`;
|
|
648
648
|
}
|
|
@@ -667,21 +667,6 @@ function pluralize(label: string, count: number): string {
|
|
|
667
667
|
// =============================================================================
|
|
668
668
|
// Tree Rendering Utilities
|
|
669
669
|
// =============================================================================
|
|
670
|
-
|
|
671
|
-
/**
|
|
672
|
-
* Get the branch character for a tree item.
|
|
673
|
-
*/
|
|
674
|
-
export function getTreeBranch(isLast: boolean, theme: Theme): string {
|
|
675
|
-
return isLast ? theme.tree.last : theme.tree.branch;
|
|
676
|
-
}
|
|
677
|
-
|
|
678
|
-
/**
|
|
679
|
-
* Get the continuation prefix for nested content under a tree item.
|
|
680
|
-
*/
|
|
681
|
-
export function getTreeContinuePrefix(isLast: boolean, theme: Theme): string {
|
|
682
|
-
return isLast ? " " : `${theme.tree.vertical} `;
|
|
683
|
-
}
|
|
684
|
-
|
|
685
670
|
/**
|
|
686
671
|
* Render a list of items with tree branches, handling truncation.
|
|
687
672
|
*
|
package/src/tools/renderers.ts
CHANGED
|
@@ -3,14 +3,13 @@
|
|
|
3
3
|
*
|
|
4
4
|
* These provide rich visualization for tool calls and results in the TUI.
|
|
5
5
|
*/
|
|
6
|
-
|
|
7
|
-
import type { RenderResultOptions } from "@oh-my-pi/pi-coding-agent/extensibility/custom-tools/types";
|
|
8
|
-
import { lspToolRenderer } from "@oh-my-pi/pi-coding-agent/lsp/render";
|
|
9
|
-
import type { Theme } from "@oh-my-pi/pi-coding-agent/modes/theme/theme";
|
|
10
|
-
import { editToolRenderer } from "@oh-my-pi/pi-coding-agent/patch";
|
|
11
|
-
import { taskToolRenderer } from "@oh-my-pi/pi-coding-agent/task/render";
|
|
12
|
-
import { webSearchToolRenderer } from "@oh-my-pi/pi-coding-agent/web/search/render";
|
|
13
6
|
import type { Component } from "@oh-my-pi/pi-tui";
|
|
7
|
+
import type { RenderResultOptions } from "../extensibility/custom-tools/types";
|
|
8
|
+
import { lspToolRenderer } from "../lsp/render";
|
|
9
|
+
import type { Theme } from "../modes/theme/theme";
|
|
10
|
+
import { editToolRenderer } from "../patch";
|
|
11
|
+
import { taskToolRenderer } from "../task/render";
|
|
12
|
+
import { webSearchToolRenderer } from "../web/search/render";
|
|
14
13
|
import { askToolRenderer } from "./ask";
|
|
15
14
|
import { bashToolRenderer } from "./bash";
|
|
16
15
|
import { calculatorToolRenderer } from "./calculator";
|
package/src/tools/review.ts
CHANGED
|
@@ -5,12 +5,17 @@
|
|
|
5
5
|
* Hidden by default - only enabled when explicitly listed in agent's tools.
|
|
6
6
|
* Reviewers finish via `complete` tool with SubmitReviewDetails schema.
|
|
7
7
|
*/
|
|
8
|
-
|
|
8
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
9
|
+
// Subprocess tool handlers - registered for extraction/rendering in task tool
|
|
10
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
11
|
+
import path from "node:path";
|
|
9
12
|
import type { AgentTool } from "@oh-my-pi/pi-agent-core";
|
|
10
|
-
import
|
|
13
|
+
import { StringEnum } from "@oh-my-pi/pi-ai";
|
|
11
14
|
import type { Component } from "@oh-my-pi/pi-tui";
|
|
12
15
|
import { Container, Text } from "@oh-my-pi/pi-tui";
|
|
13
16
|
import { Type } from "@sinclair/typebox";
|
|
17
|
+
import type { Theme, ThemeColor } from "../modes/theme/theme";
|
|
18
|
+
import { subprocessToolRegistry } from "../task/subprocess-tool-registry";
|
|
14
19
|
|
|
15
20
|
export type FindingPriority = "P0" | "P1" | "P2" | "P3";
|
|
16
21
|
|
|
@@ -145,17 +150,9 @@ export interface SubmitReviewDetails {
|
|
|
145
150
|
// Re-export types for external use
|
|
146
151
|
export type { ReportFindingDetails };
|
|
147
152
|
|
|
148
|
-
// ─────────────────────────────────────────────────────────────────────────────
|
|
149
|
-
// Subprocess tool handlers - registered for extraction/rendering in task tool
|
|
150
|
-
// ─────────────────────────────────────────────────────────────────────────────
|
|
151
|
-
|
|
152
|
-
import path from "node:path";
|
|
153
|
-
import { StringEnum } from "@oh-my-pi/pi-ai";
|
|
154
|
-
import { subprocessToolRegistry } from "@oh-my-pi/pi-coding-agent/task/subprocess-tool-registry";
|
|
155
|
-
|
|
156
153
|
// Register report_finding handler
|
|
157
154
|
subprocessToolRegistry.register<ReportFindingDetails>("report_finding", {
|
|
158
|
-
extractData:
|
|
155
|
+
extractData: event => event.result?.details as ReportFindingDetails | undefined,
|
|
159
156
|
|
|
160
157
|
renderInline: (data, theme) => {
|
|
161
158
|
const { label, icon, color } = getPriorityDisplay(data.priority, theme);
|
package/src/tools/ssh.ts
CHANGED
|
@@ -1,22 +1,23 @@
|
|
|
1
1
|
import type { AgentTool, AgentToolContext, AgentToolResult, AgentToolUpdateCallback } from "@oh-my-pi/pi-agent-core";
|
|
2
|
-
import type { SSHHost } from "@oh-my-pi/pi-coding-agent/capability/ssh";
|
|
3
|
-
import { sshCapability } from "@oh-my-pi/pi-coding-agent/capability/ssh";
|
|
4
|
-
import { renderPromptTemplate } from "@oh-my-pi/pi-coding-agent/config/prompt-templates";
|
|
5
|
-
import { loadCapability } from "@oh-my-pi/pi-coding-agent/discovery/index";
|
|
6
|
-
import type { RenderResultOptions } from "@oh-my-pi/pi-coding-agent/extensibility/custom-tools/types";
|
|
7
|
-
import type { Theme } from "@oh-my-pi/pi-coding-agent/modes/theme/theme";
|
|
8
|
-
import sshDescriptionBase from "@oh-my-pi/pi-coding-agent/prompts/tools/ssh.md" with { type: "text" };
|
|
9
|
-
import type { SSHHostInfo } from "@oh-my-pi/pi-coding-agent/ssh/connection-manager";
|
|
10
|
-
import { ensureHostInfo, getHostInfoForHost } from "@oh-my-pi/pi-coding-agent/ssh/connection-manager";
|
|
11
|
-
import { executeSSH } from "@oh-my-pi/pi-coding-agent/ssh/ssh-executor";
|
|
12
|
-
import type { OutputMeta } from "@oh-my-pi/pi-coding-agent/tools/output-meta";
|
|
13
|
-
import { ToolError } from "@oh-my-pi/pi-coding-agent/tools/tool-errors";
|
|
14
2
|
import type { Component } from "@oh-my-pi/pi-tui";
|
|
15
3
|
import { Text } from "@oh-my-pi/pi-tui";
|
|
16
4
|
import { Type } from "@sinclair/typebox";
|
|
17
|
-
import type {
|
|
5
|
+
import type { SSHHost } from "../capability/ssh";
|
|
6
|
+
import { sshCapability } from "../capability/ssh";
|
|
7
|
+
import { renderPromptTemplate } from "../config/prompt-templates";
|
|
8
|
+
import { loadCapability } from "../discovery";
|
|
9
|
+
import type { RenderResultOptions } from "../extensibility/custom-tools/types";
|
|
10
|
+
import type { Theme } from "../modes/theme/theme";
|
|
11
|
+
import sshDescriptionBase from "../prompts/tools/ssh.md" with { type: "text" };
|
|
12
|
+
import type { SSHHostInfo } from "../ssh/connection-manager";
|
|
13
|
+
import { ensureHostInfo, getHostInfoForHost } from "../ssh/connection-manager";
|
|
14
|
+
import { executeSSH } from "../ssh/ssh-executor";
|
|
15
|
+
import { renderOutputBlock, renderStatusLine } from "../tui";
|
|
16
|
+
import type { ToolSession } from ".";
|
|
17
|
+
import type { OutputMeta } from "./output-meta";
|
|
18
18
|
import { allocateOutputArtifact, createTailBuffer } from "./output-utils";
|
|
19
|
-
import {
|
|
19
|
+
import { formatBytes, wrapBrackets } from "./render-utils";
|
|
20
|
+
import { ToolError } from "./tool-errors";
|
|
20
21
|
import { toolResult } from "./tool-result";
|
|
21
22
|
import { DEFAULT_MAX_BYTES } from "./truncate";
|
|
22
23
|
|
|
@@ -31,8 +32,8 @@ export interface SSHToolDetails {
|
|
|
31
32
|
meta?: OutputMeta;
|
|
32
33
|
}
|
|
33
34
|
|
|
34
|
-
function formatHostEntry(host: SSHHost): string {
|
|
35
|
-
const info = getHostInfoForHost(host);
|
|
35
|
+
async function formatHostEntry(host: SSHHost): Promise<string> {
|
|
36
|
+
const info = await getHostInfoForHost(host);
|
|
36
37
|
|
|
37
38
|
let shell: string;
|
|
38
39
|
if (!info) {
|
|
@@ -57,12 +58,12 @@ function formatHostEntry(host: SSHHost): string {
|
|
|
57
58
|
return `- ${host.name} (${host.host}) | ${shell}`;
|
|
58
59
|
}
|
|
59
60
|
|
|
60
|
-
function formatDescription(hosts: SSHHost[]): string {
|
|
61
|
+
async function formatDescription(hosts: SSHHost[]): Promise<string> {
|
|
61
62
|
const baseDescription = renderPromptTemplate(sshDescriptionBase);
|
|
62
63
|
if (hosts.length === 0) {
|
|
63
64
|
return baseDescription;
|
|
64
65
|
}
|
|
65
|
-
const hostList = hosts.map(formatHostEntry).join("\n");
|
|
66
|
+
const hostList = (await Promise.all(hosts.map(formatHostEntry))).join("\n");
|
|
66
67
|
return `${baseDescription}\n\nAvailable hosts:\n${hostList}`;
|
|
67
68
|
}
|
|
68
69
|
|
|
@@ -134,17 +135,12 @@ export class SshTool implements AgentTool<typeof sshSchema, SSHToolDetails> {
|
|
|
134
135
|
private readonly hostsByName: Map<string, SSHHost>;
|
|
135
136
|
private readonly hostNames: string[];
|
|
136
137
|
|
|
137
|
-
constructor(session: ToolSession, hostNames: string[], hostsByName: Map<string, SSHHost
|
|
138
|
+
constructor(session: ToolSession, hostNames: string[], hostsByName: Map<string, SSHHost>, description: string) {
|
|
138
139
|
this.session = session;
|
|
139
140
|
this.hostNames = hostNames;
|
|
140
141
|
this.hostsByName = hostsByName;
|
|
141
142
|
this.allowedHosts = new Set(hostNames);
|
|
142
|
-
|
|
143
|
-
const descriptionHosts = hostNames
|
|
144
|
-
.map((name) => hostsByName.get(name))
|
|
145
|
-
.filter((host): host is SSHHost => host !== undefined);
|
|
146
|
-
|
|
147
|
-
this.description = formatDescription(descriptionHosts);
|
|
143
|
+
this.description = description;
|
|
148
144
|
}
|
|
149
145
|
|
|
150
146
|
public async execute(
|
|
@@ -181,7 +177,7 @@ export class SshTool implements AgentTool<typeof sshSchema, SSHToolDetails> {
|
|
|
181
177
|
compatEnabled: hostInfo.compatEnabled,
|
|
182
178
|
artifactPath,
|
|
183
179
|
artifactId,
|
|
184
|
-
onChunk:
|
|
180
|
+
onChunk: chunk => {
|
|
185
181
|
tailBuffer.append(chunk);
|
|
186
182
|
if (onUpdate) {
|
|
187
183
|
onUpdate({
|
|
@@ -213,7 +209,13 @@ export async function loadSshTool(session: ToolSession): Promise<SshTool | null>
|
|
|
213
209
|
if (hostNames.length === 0) {
|
|
214
210
|
return null;
|
|
215
211
|
}
|
|
216
|
-
|
|
212
|
+
|
|
213
|
+
const descriptionHosts = hostNames
|
|
214
|
+
.map(name => hostsByName.get(name))
|
|
215
|
+
.filter((host): host is SSHHost => host !== undefined);
|
|
216
|
+
const description = await formatDescription(descriptionHosts);
|
|
217
|
+
|
|
218
|
+
return new SshTool(session, hostNames, hostsByName, description);
|
|
217
219
|
}
|
|
218
220
|
|
|
219
221
|
// =============================================================================
|
|
@@ -237,10 +239,9 @@ interface SshRenderContext {
|
|
|
237
239
|
|
|
238
240
|
export const sshToolRenderer = {
|
|
239
241
|
renderCall(args: SshRenderArgs, uiTheme: Theme): Component {
|
|
240
|
-
const ui = new ToolUIKit(uiTheme);
|
|
241
242
|
const host = args.host || uiTheme.format.ellipsis;
|
|
242
243
|
const command = args.command || uiTheme.format.ellipsis;
|
|
243
|
-
const text =
|
|
244
|
+
const text = renderStatusLine({ icon: "pending", title: "SSH", description: `[${host}] $ ${command}` }, uiTheme);
|
|
244
245
|
return new Text(text, 0, 0);
|
|
245
246
|
},
|
|
246
247
|
|
|
@@ -251,42 +252,48 @@ export const sshToolRenderer = {
|
|
|
251
252
|
},
|
|
252
253
|
options: RenderResultOptions & { renderContext?: SshRenderContext },
|
|
253
254
|
uiTheme: Theme,
|
|
255
|
+
args?: SshRenderArgs,
|
|
254
256
|
): Component {
|
|
255
|
-
const ui = new ToolUIKit(uiTheme);
|
|
256
257
|
const { expanded, renderContext } = options;
|
|
257
258
|
const details = result.details;
|
|
258
|
-
const
|
|
259
|
+
const host = args?.host || uiTheme.format.ellipsis;
|
|
260
|
+
const command = args?.command || uiTheme.format.ellipsis;
|
|
261
|
+
const header = renderStatusLine(
|
|
262
|
+
{ icon: "success", title: "SSH", description: `[${host}] $ ${command}` },
|
|
263
|
+
uiTheme,
|
|
264
|
+
);
|
|
265
|
+
const outputLines: string[] = [];
|
|
259
266
|
|
|
260
|
-
const textContent = result.content?.find(
|
|
261
|
-
const output = textContent.
|
|
267
|
+
const textContent = result.content?.find(c => c.type === "text")?.text ?? "";
|
|
268
|
+
const output = textContent.trimEnd();
|
|
262
269
|
|
|
263
270
|
if (output) {
|
|
264
271
|
if (expanded) {
|
|
265
|
-
|
|
266
|
-
.split("\n")
|
|
267
|
-
.map((line) => uiTheme.fg("toolOutput", line))
|
|
268
|
-
.join("\n");
|
|
269
|
-
lines.push(styledOutput);
|
|
272
|
+
outputLines.push(...output.split("\n").map(line => uiTheme.fg("toolOutput", line)));
|
|
270
273
|
} else if (renderContext?.visualLines) {
|
|
271
274
|
const { visualLines, skippedCount = 0, totalVisualLines = visualLines.length } = renderContext;
|
|
272
275
|
if (skippedCount > 0) {
|
|
273
|
-
|
|
276
|
+
outputLines.push(
|
|
274
277
|
uiTheme.fg(
|
|
275
278
|
"dim",
|
|
276
279
|
`${uiTheme.format.ellipsis} (${skippedCount} earlier lines, showing ${visualLines.length} of ${totalVisualLines}) (ctrl+o to expand)`,
|
|
277
280
|
),
|
|
278
281
|
);
|
|
279
282
|
}
|
|
280
|
-
|
|
283
|
+
const styledVisual = visualLines.map(line =>
|
|
284
|
+
line.includes("\x1b[") ? line : uiTheme.fg("toolOutput", line),
|
|
285
|
+
);
|
|
286
|
+
outputLines.push(...styledVisual);
|
|
281
287
|
} else {
|
|
282
|
-
const
|
|
288
|
+
const outputLinesRaw = output.split("\n");
|
|
283
289
|
const maxLines = 5;
|
|
284
|
-
const displayLines =
|
|
285
|
-
const remaining =
|
|
286
|
-
|
|
287
|
-
lines.push(...displayLines.map((line) => uiTheme.fg("toolOutput", line)));
|
|
290
|
+
const displayLines = outputLinesRaw.slice(0, maxLines);
|
|
291
|
+
const remaining = outputLinesRaw.length - maxLines;
|
|
292
|
+
outputLines.push(...displayLines.map(line => uiTheme.fg("toolOutput", line)));
|
|
288
293
|
if (remaining > 0) {
|
|
289
|
-
|
|
294
|
+
outputLines.push(
|
|
295
|
+
uiTheme.fg("dim", `${uiTheme.format.ellipsis} (${remaining} more lines) (ctrl+o to expand)`),
|
|
296
|
+
);
|
|
290
297
|
}
|
|
291
298
|
}
|
|
292
299
|
}
|
|
@@ -301,12 +308,25 @@ export const sshToolRenderer = {
|
|
|
301
308
|
warnings.push(`Truncated: showing ${truncation.outputLines} of ${truncation.totalLines} lines`);
|
|
302
309
|
} else {
|
|
303
310
|
warnings.push(
|
|
304
|
-
`Truncated: ${truncation.outputLines} lines shown (${
|
|
311
|
+
`Truncated: ${truncation.outputLines} lines shown (${formatBytes(truncation.outputBytes)} limit)`,
|
|
305
312
|
);
|
|
306
313
|
}
|
|
307
|
-
|
|
314
|
+
outputLines.push(uiTheme.fg("warning", wrapBrackets(warnings.join(". "), uiTheme)));
|
|
308
315
|
}
|
|
309
316
|
|
|
310
|
-
return
|
|
317
|
+
return {
|
|
318
|
+
render: (width: number) =>
|
|
319
|
+
renderOutputBlock(
|
|
320
|
+
{
|
|
321
|
+
header,
|
|
322
|
+
state: "success",
|
|
323
|
+
sections: [{ label: uiTheme.fg("toolTitle", "Output"), lines: outputLines }],
|
|
324
|
+
width,
|
|
325
|
+
},
|
|
326
|
+
uiTheme,
|
|
327
|
+
),
|
|
328
|
+
invalidate: () => {},
|
|
329
|
+
};
|
|
311
330
|
},
|
|
331
|
+
mergeCallAndResult: true,
|
|
312
332
|
};
|