@oh-my-pi/pi-coding-agent 17.0.9 → 17.1.1
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 +78 -0
- package/README.md +1 -1
- package/dist/cli.js +4685 -4614
- package/dist/types/async/job-manager.d.ts +37 -1
- package/dist/types/cli/args.d.ts +2 -0
- package/dist/types/cli/bench-cli.d.ts +41 -0
- package/dist/types/commands/bench.d.ts +15 -3
- package/dist/types/commands/launch.d.ts +4 -0
- package/dist/types/config/model-registry.d.ts +3 -1
- package/dist/types/config/models-config-schema.d.ts +18 -6
- package/dist/types/config/models-config.d.ts +14 -5
- package/dist/types/config/provider-globals.d.ts +2 -2
- package/dist/types/config/service-tier.d.ts +5 -1
- package/dist/types/config/settings-schema.d.ts +374 -47
- package/dist/types/config/settings.d.ts +7 -0
- package/dist/types/dap/client.d.ts +20 -0
- package/dist/types/exec/bash-executor.d.ts +38 -0
- package/dist/types/exec/direnv.d.ts +33 -0
- package/dist/types/export/html/args.d.ts +15 -0
- package/dist/types/export/html/index.d.ts +11 -26
- package/dist/types/export/html/web-palette.d.ts +55 -116
- package/dist/types/extensibility/extensions/loader.d.ts +3 -0
- package/dist/types/extensibility/extensions/types.d.ts +17 -2
- package/dist/types/extensibility/legacy-pi-coding-agent-shim.d.ts +3 -0
- package/dist/types/extensibility/plugins/legacy-pi-compat.d.ts +13 -0
- package/dist/types/live/attestation.d.ts +2 -0
- package/dist/types/live/controller.d.ts +48 -0
- package/dist/types/live/protocol.d.ts +85 -0
- package/dist/types/live/protocol.test.d.ts +1 -0
- package/dist/types/live/transport.d.ts +35 -0
- package/dist/types/live/visualizer.d.ts +30 -0
- package/dist/types/lsp/client.d.ts +16 -1
- package/dist/types/mcp/config-writer.test.d.ts +1 -0
- package/dist/types/mcp/oauth-discovery.d.ts +2 -0
- package/dist/types/mcp/smithery-auth.d.ts +1 -1
- package/dist/types/mcp/smithery-auth.test.d.ts +1 -0
- package/dist/types/memory-backend/tool-names.d.ts +2 -0
- package/dist/types/modes/components/assistant-message.d.ts +1 -0
- package/dist/types/modes/components/custom-message.d.ts +1 -1
- package/dist/types/modes/components/login-dialog.d.ts +2 -2
- package/dist/types/modes/components/message-frame.d.ts +8 -4
- package/dist/types/modes/components/plan-review-overlay.d.ts +26 -0
- package/dist/types/modes/components/session-account-selector.d.ts +11 -0
- package/dist/types/modes/components/settings-defs.d.ts +7 -1
- package/dist/types/modes/components/status-line/component.jj-cache.test.d.ts +1 -0
- package/dist/types/modes/components/tool-execution.d.ts +9 -1
- package/dist/types/modes/controllers/command-controller.d.ts +1 -1
- package/dist/types/modes/controllers/event-controller.d.ts +6 -1
- package/dist/types/modes/controllers/live-command-controller.d.ts +14 -0
- package/dist/types/modes/controllers/selector-controller.d.ts +1 -0
- package/dist/types/modes/interactive-mode.d.ts +6 -0
- package/dist/types/modes/theme/theme.d.ts +1 -1
- package/dist/types/modes/types.d.ts +4 -1
- package/dist/types/modes/utils/context-usage.d.ts +12 -2
- package/dist/types/plan-mode/plan-files.d.ts +10 -0
- package/dist/types/registry/agent-lifecycle.d.ts +21 -9
- package/dist/types/registry/agent-registry.d.ts +11 -4
- package/dist/types/sdk.d.ts +15 -1
- package/dist/types/secrets/index.d.ts +15 -2
- package/dist/types/secrets/obfuscator.d.ts +113 -15
- package/dist/types/session/acp-permission-gate.d.ts +19 -0
- package/dist/types/session/agent-session-events.d.ts +84 -0
- package/dist/types/session/agent-session-types.d.ts +321 -0
- package/dist/types/session/agent-session.d.ts +135 -753
- package/dist/types/session/async-job-delivery.d.ts +28 -0
- package/dist/types/session/auth-storage.d.ts +1 -1
- package/dist/types/session/bash-runner.d.ts +75 -0
- package/dist/types/session/blob-store.d.ts +11 -1
- package/dist/types/session/blob-store.test.d.ts +1 -0
- package/dist/types/session/checkpoint-entries.d.ts +28 -0
- package/dist/types/session/eval-runner.d.ts +51 -0
- package/dist/types/session/irc-bridge.d.ts +46 -0
- package/dist/types/session/messages.d.ts +24 -0
- package/dist/types/session/model-controls.d.ts +180 -0
- package/dist/types/session/prewalk.d.ts +46 -0
- package/dist/types/session/queued-messages.d.ts +22 -0
- package/dist/types/session/redis-session-storage.d.ts +1 -0
- package/dist/types/session/retry-fallback-chains.d.ts +74 -0
- package/dist/types/session/role-models.d.ts +15 -0
- package/dist/types/session/session-advisors.d.ts +228 -0
- package/dist/types/session/session-entries.d.ts +8 -0
- package/dist/types/session/session-handoff.d.ts +70 -0
- package/dist/types/session/session-history-format.d.ts +6 -1
- package/dist/types/session/session-maintenance.d.ts +246 -0
- package/dist/types/session/session-manager.d.ts +41 -0
- package/dist/types/session/session-memory.d.ts +56 -0
- package/dist/types/session/session-provider-boundary.d.ts +62 -0
- package/dist/types/session/session-stats.d.ts +48 -0
- package/dist/types/session/session-tools.d.ts +158 -0
- package/dist/types/session/session-workspace.d.ts +32 -0
- package/dist/types/session/stream-guards.d.ts +44 -0
- package/dist/types/session/streaming-output.d.ts +8 -0
- package/dist/types/session/todo-tracker.d.ts +56 -0
- package/dist/types/session/ttsr-coordinator.d.ts +51 -0
- package/dist/types/session/turn-recovery.d.ts +225 -0
- package/dist/types/slash-commands/helpers/session-pin.d.ts +9 -0
- package/dist/types/stt/index.d.ts +0 -2
- package/dist/types/stt/stt-controller.d.ts +7 -0
- package/dist/types/system-prompt.d.ts +2 -0
- package/dist/types/task/executor.d.ts +4 -1
- package/dist/types/task/output-manager.d.ts +3 -1
- package/dist/types/tiny/title-client.d.ts +10 -0
- package/dist/types/tools/approval.d.ts +1 -0
- package/dist/types/tools/browser/launch.d.ts +5 -0
- package/dist/types/tools/builtin-names.d.ts +1 -1
- package/dist/types/tools/computer/protocol.d.ts +43 -0
- package/dist/types/tools/computer/supervisor.d.ts +32 -0
- package/dist/types/tools/computer/worker-entry.d.ts +1 -0
- package/dist/types/tools/computer/worker.d.ts +15 -0
- package/dist/types/tools/computer-renderer.d.ts +22 -0
- package/dist/types/tools/computer.d.ts +71 -0
- package/dist/types/tools/context.d.ts +2 -0
- package/dist/types/tools/default-renderer.d.ts +21 -0
- package/dist/types/tools/image-gen.d.ts +4 -4
- package/dist/types/tools/image-providers.d.ts +38 -0
- package/dist/types/tools/index.d.ts +7 -0
- package/dist/types/tools/path-utils.d.ts +8 -0
- package/dist/types/tools/todo.d.ts +10 -4
- package/dist/types/tools/xdev.d.ts +5 -1
- package/dist/types/tts/streaming-player.d.ts +10 -29
- package/dist/types/tts/vocalizer.d.ts +5 -0
- package/dist/types/utils/jj.d.ts +29 -0
- package/dist/types/utils/lang-from-path.d.ts +1 -0
- package/dist/types/utils/title-generator.d.ts +30 -0
- package/dist/types/utils/tools-manager.d.ts +1 -2
- package/dist/types/vibe/runtime.d.ts +36 -8
- package/dist/types/web/search/index.d.ts +1 -1
- package/dist/types/web/search/provider.d.ts +15 -5
- package/dist/types/web/search/types.d.ts +94 -0
- package/package.json +12 -12
- package/scripts/generate-share-viewer.ts +4 -6
- package/src/advisor/__tests__/advisor.test.ts +643 -0
- package/src/advisor/runtime.ts +144 -43
- package/src/async/job-manager.ts +90 -2
- package/src/cli/args.ts +3 -0
- package/src/cli/auth-gateway-cli.ts +18 -3
- package/src/cli/bench-cli.ts +395 -29
- package/src/cli/flag-tables.ts +3 -0
- package/src/cli/gc-cli.ts +2 -2
- package/src/cli/setup-cli.ts +2 -14
- package/src/cli/usage-cli.ts +10 -1
- package/src/cli.ts +8 -0
- package/src/collab/host.ts +3 -2
- package/src/commands/bench.ts +18 -4
- package/src/commands/launch.ts +4 -0
- package/src/config/model-registry.ts +16 -2
- package/src/config/models-config-schema.ts +15 -4
- package/src/config/provider-globals.ts +9 -9
- package/src/config/service-tier.ts +26 -1
- package/src/config/settings-schema.ts +270 -51
- package/src/config/settings.ts +81 -2
- package/src/dap/client.ts +37 -4
- package/src/edit/index.ts +49 -12
- package/src/eval/executor-base.ts +1 -0
- package/src/eval/js/executor.ts +2 -0
- package/src/eval/py/executor.ts +103 -33
- package/src/exec/bash-executor.ts +90 -6
- package/src/exec/direnv.ts +145 -0
- package/src/export/html/args.ts +20 -0
- package/src/export/html/index.ts +45 -47
- package/src/export/html/template.css +19 -1
- package/src/export/html/template.html +6 -0
- package/src/export/html/template.js +21 -0
- package/src/export/html/tool-views.generated.js +31 -31
- package/src/export/html/web-palette.ts +116 -132
- package/src/export/share.ts +249 -49
- package/src/extensibility/extensions/loader.ts +29 -1
- package/src/extensibility/extensions/runner.ts +6 -0
- package/src/extensibility/extensions/types.ts +33 -2
- package/src/extensibility/extensions/wrapper.ts +68 -12
- package/src/extensibility/legacy-pi-coding-agent-shim.ts +7 -1
- package/src/extensibility/plugins/legacy-pi-compat.ts +19 -1
- package/src/hindsight/state.ts +64 -6
- package/src/internal-urls/local-protocol.ts +2 -1
- package/src/internal-urls/memory-protocol.ts +2 -2
- package/src/internal-urls/skill-protocol.ts +2 -2
- package/src/internal-urls/ssh-protocol.ts +2 -1
- package/src/internal-urls/vault-protocol.ts +2 -1
- package/src/live/attestation.ts +91 -0
- package/src/live/controller.ts +517 -0
- package/src/live/prompts/agent-final-message.md +3 -0
- package/src/live/prompts/live-instructions.md +23 -0
- package/src/live/protocol.test.ts +140 -0
- package/src/live/protocol.ts +233 -0
- package/src/live/transport.ts +422 -0
- package/src/live/visualizer.ts +214 -0
- package/src/lsp/client.ts +29 -9
- package/src/lsp/index.ts +19 -4
- package/src/main.ts +8 -1
- package/src/mcp/config-writer.test.ts +43 -0
- package/src/mcp/config-writer.ts +109 -82
- package/src/mcp/oauth-discovery.ts +10 -2
- package/src/mcp/smithery-auth.test.ts +29 -0
- package/src/mcp/smithery-auth.ts +3 -2
- package/src/memories/index.ts +40 -20
- package/src/memory-backend/tool-names.ts +2 -0
- package/src/mnemopi/backend.ts +24 -7
- package/src/modes/acp/acp-agent.ts +56 -10
- package/src/modes/acp/acp-event-mapper.ts +8 -1
- package/src/modes/components/agent-hub.ts +1 -1
- package/src/modes/components/assistant-message.ts +7 -2
- package/src/modes/components/custom-message.ts +4 -1
- package/src/modes/components/login-dialog.ts +14 -4
- package/src/modes/components/message-frame.ts +14 -8
- package/src/modes/components/plan-review-overlay.ts +350 -35
- package/src/modes/components/session-account-selector.ts +62 -0
- package/src/modes/components/settings-defs.ts +23 -1
- package/src/modes/components/settings-selector.ts +169 -1
- package/src/modes/components/status-line/component.jj-cache.test.ts +229 -0
- package/src/modes/components/status-line/component.ts +123 -2
- package/src/modes/components/tool-execution.ts +28 -112
- package/src/modes/controllers/command-controller.ts +56 -15
- package/src/modes/controllers/event-controller.ts +111 -16
- package/src/modes/controllers/extension-ui-controller.test.ts +1 -0
- package/src/modes/controllers/extension-ui-controller.ts +20 -4
- package/src/modes/controllers/input-controller.ts +47 -39
- package/src/modes/controllers/live-command-controller.ts +255 -0
- package/src/modes/controllers/mcp-command-controller.ts +10 -1
- package/src/modes/controllers/omfg-controller.ts +44 -40
- package/src/modes/controllers/selector-controller.ts +80 -10
- package/src/modes/controllers/session-focus-controller.ts +6 -1
- package/src/modes/interactive-mode.ts +176 -38
- package/src/modes/runtime-init.ts +2 -0
- package/src/modes/setup-wizard/scenes/web-search.ts +17 -9
- package/src/modes/theme/theme.ts +1 -1
- package/src/modes/types.ts +4 -1
- package/src/modes/utils/context-usage.ts +23 -7
- package/src/modes/utils/ui-helpers.ts +10 -5
- package/src/plan-mode/plan-files.ts +40 -0
- package/src/prompts/bench/cache-prefix-chunk.md +1 -0
- package/src/prompts/bench/cache-prefix.md +3 -0
- package/src/prompts/bench/cache-suffix.md +1 -0
- package/src/prompts/system/computer-safety.md +14 -0
- package/src/prompts/system/custom-system-prompt.md +1 -1
- package/src/prompts/system/project-prompt.md +8 -1
- package/src/prompts/system/subagent-async-pending.md +6 -0
- package/src/prompts/system/system-prompt.md +1 -1
- package/src/prompts/system/workflow-notice.md +48 -40
- package/src/prompts/system/xdev-mount-notice.md +4 -0
- package/src/prompts/tools/computer.md +26 -0
- package/src/prompts/tools/todo.md +3 -1
- package/src/registry/agent-lifecycle.ts +116 -46
- package/src/registry/agent-registry.ts +35 -8
- package/src/registry/persisted-agents.ts +26 -2
- package/src/sdk.ts +215 -136
- package/src/secrets/index.ts +127 -4
- package/src/secrets/obfuscator.ts +2328 -105
- package/src/session/acp-permission-gate.ts +165 -0
- package/src/session/agent-session-error-log.test.ts +1 -1
- package/src/session/agent-session-events.ts +66 -0
- package/src/session/agent-session-types.ts +343 -0
- package/src/session/agent-session.ts +1940 -12218
- package/src/session/artifacts.ts +6 -5
- package/src/session/async-job-delivery.ts +74 -0
- package/src/session/auth-storage.ts +1 -0
- package/src/session/bash-runner.ts +326 -0
- package/src/session/blob-store.test.ts +56 -0
- package/src/session/blob-store.ts +18 -2
- package/src/session/checkpoint-entries.ts +81 -0
- package/src/session/eval-runner.ts +217 -0
- package/src/session/indexed-session-storage.ts +9 -2
- package/src/session/irc-bridge.ts +203 -0
- package/src/session/messages.ts +266 -1
- package/src/session/model-controls.ts +714 -0
- package/src/session/prewalk.ts +252 -0
- package/src/session/queued-messages.ts +93 -0
- package/src/session/redis-session-storage.ts +51 -11
- package/src/session/retry-fallback-chains.ts +455 -0
- package/src/session/role-models.ts +85 -0
- package/src/session/session-advisors.ts +1679 -0
- package/src/session/session-context.ts +6 -3
- package/src/session/session-entries.ts +8 -0
- package/src/session/session-handoff.ts +308 -0
- package/src/session/session-history-format.ts +20 -9
- package/src/session/session-loader.ts +0 -46
- package/src/session/session-maintenance.ts +2983 -0
- package/src/session/session-manager.ts +390 -30
- package/src/session/session-memory.ts +222 -0
- package/src/session/session-provider-boundary.ts +307 -0
- package/src/session/session-stats.ts +293 -0
- package/src/session/session-tools.ts +980 -0
- package/src/session/session-workspace.ts +53 -0
- package/src/session/stream-guards.ts +417 -0
- package/src/session/streaming-output.ts +52 -5
- package/src/session/todo-tracker.ts +380 -0
- package/src/session/ttsr-coordinator.ts +496 -0
- package/src/session/turn-recovery.ts +1629 -0
- package/src/slash-commands/builtin-registry.ts +257 -20
- package/src/slash-commands/helpers/session-pin.ts +44 -0
- package/src/slash-commands/helpers/usage-report.ts +22 -3
- package/src/stt/downloader.ts +0 -2
- package/src/stt/index.ts +0 -2
- package/src/stt/stt-controller.ts +57 -146
- package/src/system-prompt.ts +45 -17
- package/src/task/executor.ts +285 -70
- package/src/task/index.ts +98 -105
- package/src/task/output-manager.ts +25 -3
- package/src/task/persisted-revive.ts +4 -3
- package/src/task/structured-subagent.ts +1 -0
- package/src/tiny/title-client.ts +22 -0
- package/src/tools/approval.ts +55 -10
- package/src/tools/bash-interactive.ts +116 -86
- package/src/tools/bash-skill-urls.ts +28 -2
- package/src/tools/bash.ts +339 -123
- package/src/tools/browser/launch.ts +9 -1
- package/src/tools/browser/tab-supervisor.ts +8 -5
- package/src/tools/browser.ts +94 -47
- package/src/tools/builtin-names.ts +1 -0
- package/src/tools/computer/protocol.ts +28 -0
- package/src/tools/computer/supervisor.ts +258 -0
- package/src/tools/computer/worker-entry.ts +25 -0
- package/src/tools/computer/worker.ts +135 -0
- package/src/tools/computer-renderer.ts +108 -0
- package/src/tools/computer.ts +433 -0
- package/src/tools/context.ts +2 -0
- package/src/tools/default-renderer.ts +139 -0
- package/src/tools/essential-tools.ts +1 -0
- package/src/tools/image-gen.ts +20 -28
- package/src/tools/image-providers.ts +50 -0
- package/src/tools/index.ts +14 -0
- package/src/tools/path-utils.ts +49 -2
- package/src/tools/read.ts +156 -88
- package/src/tools/renderers.ts +9 -1
- package/src/tools/todo.ts +101 -11
- package/src/tools/vibe.ts +1 -2
- package/src/tools/write.ts +51 -1
- package/src/tools/xdev.ts +121 -29
- package/src/tts/streaming-player.ts +82 -283
- package/src/tts/vocalizer.ts +18 -1
- package/src/utils/clipboard.ts +1 -30
- package/src/utils/jj.ts +125 -4
- package/src/utils/lang-from-path.ts +7 -0
- package/src/utils/mac-file-urls.applescript +37 -0
- package/src/utils/title-generator.ts +137 -1
- package/src/utils/tool-choice.ts +14 -0
- package/src/utils/tools-manager.ts +1 -19
- package/src/vibe/runtime.ts +852 -72
- package/src/web/search/index.ts +3 -6
- package/src/web/search/provider.ts +31 -16
- package/src/web/search/providers/xai.ts +7 -1
- package/src/web/search/types.ts +3 -0
- package/dist/types/stt/recorder.d.ts +0 -30
- package/dist/types/stt/transcriber.d.ts +0 -14
- package/dist/types/stt/wav.d.ts +0 -29
- package/dist/types/tts/player.d.ts +0 -32
- package/src/stt/recorder.ts +0 -551
- package/src/stt/transcriber.ts +0 -60
- package/src/stt/wav.ts +0 -173
- package/src/tts/player.ts +0 -137
package/src/tools/write.ts
CHANGED
|
@@ -49,7 +49,14 @@ import {
|
|
|
49
49
|
} from "./conflict-detect";
|
|
50
50
|
import { invalidateFsScanAfterWrite } from "./fs-cache-invalidation";
|
|
51
51
|
import { type OutputMeta, outputMeta } from "./output-meta";
|
|
52
|
-
import {
|
|
52
|
+
import {
|
|
53
|
+
formatPathRelativeToCwd,
|
|
54
|
+
isInternalUrlPath,
|
|
55
|
+
pathTargetsSsh,
|
|
56
|
+
peelWriteUrlSelector,
|
|
57
|
+
probeLiteralPathExists,
|
|
58
|
+
splitPathAndSel,
|
|
59
|
+
} from "./path-utils";
|
|
53
60
|
import { enforcePlanModeWrite, resolvePlanPath, unwrapHashlineHeaderPath } from "./plan-mode-guard";
|
|
54
61
|
import {
|
|
55
62
|
cachedRenderedString,
|
|
@@ -116,6 +123,43 @@ function assertWriteTargetAddressable(target: string, router: InternalUrlRouter)
|
|
|
116
123
|
);
|
|
117
124
|
}
|
|
118
125
|
|
|
126
|
+
/**
|
|
127
|
+
* Fail closed when a local write target looks like a mis-dispatched read.
|
|
128
|
+
*
|
|
129
|
+
* A read-only step that selects `write` instead of `read` passes the full read
|
|
130
|
+
* expression (`src/foo.tsx:1-260:raw`) as the target. Because a literal colon
|
|
131
|
+
* filename is legal on POSIX (issue #4618), that request otherwise resolves to
|
|
132
|
+
* filesystem creation and reports success, leaving a stray zero-byte file the
|
|
133
|
+
* model cannot recover from — the local analogue of the `xd://` near-miss guard
|
|
134
|
+
* ({@link assertWriteTargetAddressable}, issue #6123).
|
|
135
|
+
*
|
|
136
|
+
* Fires only on the high-confidence combination the report identifies: the tail
|
|
137
|
+
* parses as a read-tool selector, the literal target is missing, and no content
|
|
138
|
+
* was supplied. Non-empty content is the escape hatch — it is never blocked, so
|
|
139
|
+
* a deliberate write to a selector-shaped filename still succeeds. An existing
|
|
140
|
+
* literal path or an ambiguous stat (`"unknown"`: EACCES, transient I/O) also
|
|
141
|
+
* passes through so a real file is never shadowed by the guard.
|
|
142
|
+
*/
|
|
143
|
+
function readSelectorForEmptyWrite(target: string, content: string): string | undefined {
|
|
144
|
+
if (content.length > 0) return undefined;
|
|
145
|
+
return splitPathAndSel(target).sel;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
function throwReadSelectorMisfire(target: string, sel: string): never {
|
|
149
|
+
throw new ToolError(
|
|
150
|
+
`write target '${target}' ends with a read-tool selector ':${sel}' and no such file exists — refusing to create a literal file by that name. ` +
|
|
151
|
+
`If you meant to read it, use read({ path: "${target}" }). ` +
|
|
152
|
+
`If you truly intend to create this file, pass its contents in \`content\` (a non-empty write is never blocked).`,
|
|
153
|
+
);
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
async function assertNotReadSelectorMisfire(target: string, content: string, cwd: string): Promise<void> {
|
|
157
|
+
const sel = readSelectorForEmptyWrite(target, content);
|
|
158
|
+
if (sel === undefined) return;
|
|
159
|
+
if ((await probeLiteralPathExists(target, cwd)) !== "missing") return;
|
|
160
|
+
throwReadSelectorMisfire(target, sel);
|
|
161
|
+
}
|
|
162
|
+
|
|
119
163
|
const BULK_DIRECTIVE_RE = /^#?(\d+)\s*[:=]\s*(@ours|@theirs|@base|@both)$/;
|
|
120
164
|
/**
|
|
121
165
|
* The head of a per-id directive line — `<id>:` / `<id>=` (optionally `#`-prefixed),
|
|
@@ -576,6 +620,11 @@ export class WriteTool implements AgentTool<typeof writeSchema, WriteToolDetails
|
|
|
576
620
|
throw new ToolError(error instanceof Error ? error.message : String(error));
|
|
577
621
|
}
|
|
578
622
|
}
|
|
623
|
+
const writeTarget = `${resolvedArchivePath.archivePath}:${resolvedArchivePath.archiveSubPath}`;
|
|
624
|
+
const sel = readSelectorForEmptyWrite(writeTarget, content);
|
|
625
|
+
if (sel !== undefined && !entries.has(resolvedArchivePath.archiveSubPath)) {
|
|
626
|
+
throwReadSelectorMisfire(writeTarget, sel);
|
|
627
|
+
}
|
|
579
628
|
entries.set(resolvedArchivePath.archiveSubPath, content);
|
|
580
629
|
|
|
581
630
|
try {
|
|
@@ -1159,6 +1208,7 @@ export class WriteTool implements AgentTool<typeof writeSchema, WriteToolDetails
|
|
|
1159
1208
|
return sqliteResult;
|
|
1160
1209
|
}
|
|
1161
1210
|
|
|
1211
|
+
await assertNotReadSelectorMisfire(path, cleanContent, this.session.cwd);
|
|
1162
1212
|
enforcePlanModeWrite(this.session, path, { op: "create" });
|
|
1163
1213
|
const absolutePath = resolvePlanPath(this.session, path);
|
|
1164
1214
|
const batchRequest = getLspBatchRequest(context?.toolCall);
|
package/src/tools/xdev.ts
CHANGED
|
@@ -30,10 +30,11 @@ import { parseStreamingJson } from "@oh-my-pi/pi-utils";
|
|
|
30
30
|
import type { RenderResultOptions } from "../extensibility/custom-tools/types";
|
|
31
31
|
import { XD_URL_PREFIX } from "../internal-urls/xd-protocol";
|
|
32
32
|
import type { Theme } from "../modes/theme/theme";
|
|
33
|
+
import { renderDefaultToolExecution } from "./default-renderer";
|
|
33
34
|
import type { Tool } from "./index";
|
|
34
35
|
import { replaceTabs } from "./render-utils";
|
|
35
36
|
import type { ToolRenderer } from "./renderers";
|
|
36
|
-
import { ToolError } from "./tool-errors";
|
|
37
|
+
import { renderError, ToolAbortError, ToolError } from "./tool-errors";
|
|
37
38
|
|
|
38
39
|
/**
|
|
39
40
|
* Discoverable built-ins that must stay top-level even when xdev mounting is
|
|
@@ -60,6 +61,9 @@ export const XDEV_KEEP_TOP_LEVEL: Record<string, true> = {
|
|
|
60
61
|
*/
|
|
61
62
|
export const XDEV_TRANSPORT_TOOLS: Record<string, true> = { read: true, write: true };
|
|
62
63
|
|
|
64
|
+
/** Controls which mounted-device docs are inlined into the system prompt. */
|
|
65
|
+
export type XdevDocsMode = "inline" | "builtins" | "catalog";
|
|
66
|
+
|
|
63
67
|
/**
|
|
64
68
|
* Whether an enabled tool is presented under `xd://` (rather than top-level)
|
|
65
69
|
* while the `xd://` transport is active. Discoverable tools mount unless they
|
|
@@ -170,6 +174,28 @@ function toolSummary(inst: Tool): string {
|
|
|
170
174
|
return firstLine?.trim() ?? inst.label ?? inst.name;
|
|
171
175
|
}
|
|
172
176
|
|
|
177
|
+
function promptCatalogSummary(inst: Tool, maxLength?: number): string {
|
|
178
|
+
const summary =
|
|
179
|
+
toolSummary(inst)
|
|
180
|
+
.split("\n")
|
|
181
|
+
.find(line => line.trim().length > 0)
|
|
182
|
+
?.trim() ?? inst.name;
|
|
183
|
+
if (maxLength === undefined || summary.length <= maxLength) return summary;
|
|
184
|
+
return `${summary.slice(0, maxLength).trimEnd()}…`;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
/** Compile the `tools.xdevInlineDevices` allowlist once per render, dropping
|
|
188
|
+
* non-string entries so malformed user config cannot break prompt builds. */
|
|
189
|
+
function compileInlineGlobs(patterns: readonly string[]): Bun.Glob[] {
|
|
190
|
+
if (!Array.isArray(patterns)) return [];
|
|
191
|
+
const globs: Bun.Glob[] = [];
|
|
192
|
+
for (const pattern of patterns) {
|
|
193
|
+
if (typeof pattern !== "string" || pattern.length === 0) continue;
|
|
194
|
+
globs.push(new Bun.Glob(pattern));
|
|
195
|
+
}
|
|
196
|
+
return globs;
|
|
197
|
+
}
|
|
198
|
+
|
|
173
199
|
/** Decode the (possibly partially streamed) inner args JSON string into display args. */
|
|
174
200
|
function decodeInnerArgs(raw: unknown): Record<string, unknown> {
|
|
175
201
|
if (typeof raw !== "string" || raw.length === 0) return {};
|
|
@@ -230,7 +256,13 @@ export class XdevRegistry {
|
|
|
230
256
|
|
|
231
257
|
/** `{name, summary}` pairs for prompt templates and /tools display. */
|
|
232
258
|
entries(): Array<{ name: string; summary: string }> {
|
|
233
|
-
return this.list().map(tool => ({
|
|
259
|
+
return this.list().map(tool => ({
|
|
260
|
+
name: tool.name,
|
|
261
|
+
summary: promptCatalogSummary(
|
|
262
|
+
tool,
|
|
263
|
+
this.#dynamic.has(tool.name) ? XdevRegistry.EXTERNAL_DESCRIPTION_CAP : undefined,
|
|
264
|
+
),
|
|
265
|
+
}));
|
|
234
266
|
}
|
|
235
267
|
|
|
236
268
|
/** `read xd://` listing with one device per line. */
|
|
@@ -273,11 +305,16 @@ export class XdevRegistry {
|
|
|
273
305
|
* Dynamic mounts embed at most {@link EXTERNAL_DESCRIPTION_CAP} description
|
|
274
306
|
* chars (schema always intact); `read xd://<tool>` returns the full text.
|
|
275
307
|
*/
|
|
276
|
-
docsAll(): string {
|
|
308
|
+
docsAll(mode: XdevDocsMode = "inline", inlinePatterns: readonly string[] = []): string {
|
|
277
309
|
const sections: string[] = [];
|
|
278
310
|
const overflow: Tool[] = [];
|
|
311
|
+
const inlineGlobs = compileInlineGlobs(inlinePatterns);
|
|
279
312
|
let used = 0;
|
|
280
313
|
for (const tool of this.list()) {
|
|
314
|
+
if (!this.#shouldInline(tool, mode, inlineGlobs)) {
|
|
315
|
+
overflow.push(tool);
|
|
316
|
+
continue;
|
|
317
|
+
}
|
|
281
318
|
const descriptionCap = this.#dynamic.has(tool.name) ? XdevRegistry.EXTERNAL_DESCRIPTION_CAP : undefined;
|
|
282
319
|
const docs = renderDocs(tool, "##", descriptionCap);
|
|
283
320
|
if (docs.length > XdevRegistry.DOCS_PER_DEVICE_CAP || used + docs.length > XdevRegistry.DOCS_TOTAL_BUDGET) {
|
|
@@ -291,7 +328,10 @@ export class XdevRegistry {
|
|
|
291
328
|
sections.push(
|
|
292
329
|
[
|
|
293
330
|
"## Additional devices (docs on demand)",
|
|
294
|
-
...overflow.map(tool =>
|
|
331
|
+
...overflow.map(tool => {
|
|
332
|
+
const maxLength = this.#dynamic.has(tool.name) ? XdevRegistry.EXTERNAL_DESCRIPTION_CAP : undefined;
|
|
333
|
+
return `- ${XD_URL_PREFIX}${tool.name} — ${promptCatalogSummary(tool, maxLength)}`;
|
|
334
|
+
}),
|
|
295
335
|
"",
|
|
296
336
|
`Read ${XD_URL_PREFIX}<tool> for full docs + JSON schema before first use.`,
|
|
297
337
|
].join("\n"),
|
|
@@ -300,6 +340,31 @@ export class XdevRegistry {
|
|
|
300
340
|
return sections.join("\n\n");
|
|
301
341
|
}
|
|
302
342
|
|
|
343
|
+
/** Docs for selected mounted devices under the configured prompt-doc policy. */
|
|
344
|
+
docsFor(names: Iterable<string>, mode: XdevDocsMode, inlinePatterns: readonly string[] = []): string {
|
|
345
|
+
const sections: string[] = [];
|
|
346
|
+
const inlineGlobs = compileInlineGlobs(inlinePatterns);
|
|
347
|
+
let used = 0;
|
|
348
|
+
for (const name of names) {
|
|
349
|
+
const tool = this.get(name);
|
|
350
|
+
if (!tool || !this.#shouldInline(tool, mode, inlineGlobs)) continue;
|
|
351
|
+
const descriptionCap = this.#dynamic.has(tool.name) ? XdevRegistry.EXTERNAL_DESCRIPTION_CAP : undefined;
|
|
352
|
+
const docs = renderDocs(tool, "##", descriptionCap);
|
|
353
|
+
if (docs.length > XdevRegistry.DOCS_PER_DEVICE_CAP || used + docs.length > XdevRegistry.DOCS_TOTAL_BUDGET)
|
|
354
|
+
continue;
|
|
355
|
+
used += docs.length;
|
|
356
|
+
sections.push(docs);
|
|
357
|
+
}
|
|
358
|
+
return sections.join("\n\n");
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
#shouldInline(tool: Tool, mode: XdevDocsMode, inlineGlobs: readonly Bun.Glob[]): boolean {
|
|
362
|
+
return (
|
|
363
|
+
mode !== "catalog" &&
|
|
364
|
+
(mode === "inline" || this.#builtins.has(tool.name) || inlineGlobs.some(glob => glob.match(tool.name)))
|
|
365
|
+
);
|
|
366
|
+
}
|
|
367
|
+
|
|
303
368
|
#resolve(name: string): Tool {
|
|
304
369
|
const inst = this.get(name);
|
|
305
370
|
if (!inst) {
|
|
@@ -325,28 +390,45 @@ export class XdevRegistry {
|
|
|
325
390
|
onUpdate?: AgentToolUpdateCallback,
|
|
326
391
|
context?: AgentToolContext,
|
|
327
392
|
): Promise<{ result: AgentToolResult<unknown>; xdev: XdevDispatch }> {
|
|
328
|
-
|
|
393
|
+
let xdev: XdevDispatch = { tool: name, mode: "execute" };
|
|
394
|
+
try {
|
|
395
|
+
const inst = this.#resolve(name);
|
|
396
|
+
|
|
397
|
+
if (HELP_CONTENT_RE.test(content)) {
|
|
398
|
+
return {
|
|
399
|
+
result: { content: [{ type: "text", text: renderDocs(inst) }] },
|
|
400
|
+
xdev: { tool: name, mode: "help" },
|
|
401
|
+
};
|
|
402
|
+
}
|
|
329
403
|
|
|
330
|
-
|
|
404
|
+
const validated = parseDeviceArgs(inst as AiTool, content, toolCallId, () => renderDocs(inst));
|
|
405
|
+
xdev = { ...xdev, args: validated };
|
|
406
|
+
const innerOnUpdate: AgentToolUpdateCallback | undefined = onUpdate
|
|
407
|
+
? partial =>
|
|
408
|
+
onUpdate({
|
|
409
|
+
content: partial.content,
|
|
410
|
+
details: { xdev: { ...xdev, inner: partial.details } },
|
|
411
|
+
isError: partial.isError,
|
|
412
|
+
})
|
|
413
|
+
: undefined;
|
|
414
|
+
const result = await inst.execute(toolCallId, validated as never, signal, innerOnUpdate, context);
|
|
415
|
+
return { result, xdev: { ...xdev, inner: result.details } };
|
|
416
|
+
} catch (error) {
|
|
417
|
+
if (
|
|
418
|
+
error instanceof ToolAbortError ||
|
|
419
|
+
signal?.aborted ||
|
|
420
|
+
(error instanceof Error && error.name === "AbortError")
|
|
421
|
+
) {
|
|
422
|
+
throw error;
|
|
423
|
+
}
|
|
331
424
|
return {
|
|
332
|
-
result: {
|
|
333
|
-
|
|
425
|
+
result: {
|
|
426
|
+
content: [{ type: "text", text: renderError(error) }],
|
|
427
|
+
isError: true,
|
|
428
|
+
},
|
|
429
|
+
xdev,
|
|
334
430
|
};
|
|
335
431
|
}
|
|
336
|
-
|
|
337
|
-
const validated = parseDeviceArgs(inst as AiTool, content, toolCallId, () => renderDocs(inst));
|
|
338
|
-
|
|
339
|
-
const xdevBase: XdevDispatch = { tool: name, mode: "execute", args: validated };
|
|
340
|
-
const innerOnUpdate: AgentToolUpdateCallback | undefined = onUpdate
|
|
341
|
-
? partial =>
|
|
342
|
-
onUpdate({
|
|
343
|
-
content: partial.content,
|
|
344
|
-
details: { xdev: { ...xdevBase, inner: partial.details } },
|
|
345
|
-
isError: partial.isError,
|
|
346
|
-
})
|
|
347
|
-
: undefined;
|
|
348
|
-
const result = await inst.execute(toolCallId, validated as never, signal, innerOnUpdate, context);
|
|
349
|
-
return { result, xdev: { ...xdevBase, inner: result.details } };
|
|
350
432
|
}
|
|
351
433
|
}
|
|
352
434
|
|
|
@@ -359,9 +441,8 @@ export class XdevRegistry {
|
|
|
359
441
|
* map keyed by name. */
|
|
360
442
|
function resolveDeviceRenderer(
|
|
361
443
|
name: string,
|
|
362
|
-
|
|
444
|
+
mounted: Tool | undefined,
|
|
363
445
|
): Pick<ToolRenderer, "renderCall" | "renderResult" | "mergeCallAndResult"> | undefined {
|
|
364
|
-
const mounted = resolveMounted?.(name);
|
|
365
446
|
if (mounted && (mounted.renderCall || mounted.renderResult)) {
|
|
366
447
|
// A mounted AgentTool exposes the same renderCall/renderResult/mergeCallAndResult
|
|
367
448
|
// surface as a static ToolRenderer; only the parameter generics differ, so unify
|
|
@@ -383,11 +464,13 @@ export function renderXdevCall(
|
|
|
383
464
|
theme: Theme,
|
|
384
465
|
resolveMounted?: (name: string) => Tool | undefined,
|
|
385
466
|
): Component | undefined {
|
|
386
|
-
const
|
|
467
|
+
const mounted = resolveMounted?.(name);
|
|
468
|
+
const renderer = resolveDeviceRenderer(name, mounted);
|
|
469
|
+
const args = decodeInnerArgs(content);
|
|
387
470
|
if (renderer?.renderCall) {
|
|
388
|
-
return renderer.renderCall(
|
|
471
|
+
return renderer.renderCall(args, options, theme);
|
|
389
472
|
}
|
|
390
|
-
return
|
|
473
|
+
return renderDefaultToolExecution({ label: mounted?.label ?? name, args, options }, theme);
|
|
391
474
|
}
|
|
392
475
|
|
|
393
476
|
/** Forward an `xd://` dispatch result to the mounted tool's renderer. */
|
|
@@ -405,7 +488,8 @@ export function renderXdevResult(
|
|
|
405
488
|
if (dispatch.mode === "help") {
|
|
406
489
|
return text ? new Text(theme.fg("toolOutput", replaceTabs(text)), 0, 0) : undefined;
|
|
407
490
|
}
|
|
408
|
-
const
|
|
491
|
+
const mounted = resolveMounted?.(dispatch.tool);
|
|
492
|
+
const renderer = resolveDeviceRenderer(dispatch.tool, mounted);
|
|
409
493
|
const innerResult = { content: result.content, details: dispatch.inner, isError: result.isError };
|
|
410
494
|
if (renderer?.renderResult) {
|
|
411
495
|
const parts: Component[] = [];
|
|
@@ -424,5 +508,13 @@ export function renderXdevResult(
|
|
|
424
508
|
return box;
|
|
425
509
|
}
|
|
426
510
|
}
|
|
427
|
-
return
|
|
511
|
+
return renderDefaultToolExecution(
|
|
512
|
+
{
|
|
513
|
+
label: mounted?.label ?? dispatch.tool,
|
|
514
|
+
args: dispatch.args ?? {},
|
|
515
|
+
result: { output: text, isError: result.isError },
|
|
516
|
+
options,
|
|
517
|
+
},
|
|
518
|
+
theme,
|
|
519
|
+
);
|
|
428
520
|
}
|