@draht/coding-agent 2026.3.14 → 2026.3.25
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/README.md +45 -30
- package/dist/bun/cli.d.ts +3 -0
- package/dist/bun/cli.d.ts.map +1 -0
- package/dist/bun/cli.js +7 -0
- package/dist/bun/cli.js.map +1 -0
- package/dist/bun/register-bedrock.d.ts +2 -0
- package/dist/bun/register-bedrock.d.ts.map +1 -0
- package/dist/bun/register-bedrock.js +4 -0
- package/dist/bun/register-bedrock.js.map +1 -0
- package/dist/cli/args.d.ts +1 -0
- package/dist/cli/args.d.ts.map +1 -1
- package/dist/cli/args.js +11 -6
- package/dist/cli/args.js.map +1 -1
- package/dist/cli/file-processor.d.ts.map +1 -1
- package/dist/cli/file-processor.js +4 -0
- package/dist/cli/file-processor.js.map +1 -1
- package/dist/cli/initial-message.d.ts +18 -0
- package/dist/cli/initial-message.d.ts.map +1 -0
- package/dist/cli/initial-message.js +22 -0
- package/dist/cli/initial-message.js.map +1 -0
- package/dist/cli/session-picker.d.ts.map +1 -1
- package/dist/cli/session-picker.js +2 -1
- package/dist/cli/session-picker.js.map +1 -1
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +1 -3
- package/dist/cli.js.map +1 -1
- package/dist/core/agent-session.d.ts +38 -5
- package/dist/core/agent-session.d.ts.map +1 -1
- package/dist/core/agent-session.js +201 -73
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/bash-executor.d.ts +6 -7
- package/dist/core/bash-executor.d.ts.map +1 -1
- package/dist/core/bash-executor.js +8 -107
- package/dist/core/bash-executor.js.map +1 -1
- package/dist/core/compaction/branch-summarization.d.ts.map +1 -1
- package/dist/core/compaction/branch-summarization.js +1 -0
- package/dist/core/compaction/branch-summarization.js.map +1 -1
- package/dist/core/compaction/compaction.d.ts.map +1 -1
- package/dist/core/compaction/compaction.js +2 -0
- package/dist/core/compaction/compaction.js.map +1 -1
- package/dist/core/exec.d.ts.map +1 -1
- package/dist/core/exec.js +7 -3
- package/dist/core/exec.js.map +1 -1
- package/dist/core/export-html/index.d.ts +2 -2
- package/dist/core/export-html/index.d.ts.map +1 -1
- package/dist/core/export-html/index.js +7 -6
- package/dist/core/export-html/index.js.map +1 -1
- package/dist/core/export-html/template.css +43 -13
- package/dist/core/export-html/template.html +1 -0
- package/dist/core/export-html/template.js +107 -0
- package/dist/core/export-html/tool-renderer.d.ts +2 -2
- package/dist/core/export-html/tool-renderer.d.ts.map +1 -1
- package/dist/core/export-html/tool-renderer.js +41 -16
- package/dist/core/export-html/tool-renderer.js.map +1 -1
- package/dist/core/extensions/index.d.ts +4 -3
- package/dist/core/extensions/index.d.ts.map +1 -1
- package/dist/core/extensions/index.js +1 -1
- package/dist/core/extensions/index.js.map +1 -1
- package/dist/core/extensions/loader.d.ts.map +1 -1
- package/dist/core/extensions/loader.js +16 -6
- package/dist/core/extensions/loader.js.map +1 -1
- package/dist/core/extensions/runner.d.ts +9 -9
- package/dist/core/extensions/runner.d.ts.map +1 -1
- package/dist/core/extensions/runner.js +89 -71
- package/dist/core/extensions/runner.js.map +1 -1
- package/dist/core/extensions/types.d.ts +49 -13
- package/dist/core/extensions/types.d.ts.map +1 -1
- package/dist/core/extensions/types.js.map +1 -1
- package/dist/core/extensions/wrapper.d.ts +4 -11
- package/dist/core/extensions/wrapper.d.ts.map +1 -1
- package/dist/core/extensions/wrapper.js +6 -86
- package/dist/core/extensions/wrapper.js.map +1 -1
- package/dist/core/footer-data-provider.d.ts +13 -1
- package/dist/core/footer-data-provider.d.ts.map +1 -1
- package/dist/core/footer-data-provider.js +155 -37
- package/dist/core/footer-data-provider.js.map +1 -1
- package/dist/core/index.d.ts +2 -1
- package/dist/core/index.d.ts.map +1 -1
- package/dist/core/index.js +2 -1
- package/dist/core/index.js.map +1 -1
- package/dist/core/keybindings.d.ts +270 -50
- package/dist/core/keybindings.d.ts.map +1 -1
- package/dist/core/keybindings.js +222 -134
- package/dist/core/keybindings.js.map +1 -1
- package/dist/core/model-registry.d.ts +1 -0
- package/dist/core/model-registry.d.ts.map +1 -1
- package/dist/core/model-registry.js +49 -23
- package/dist/core/model-registry.js.map +1 -1
- package/dist/core/model-resolver.d.ts +6 -0
- package/dist/core/model-resolver.d.ts.map +1 -1
- package/dist/core/model-resolver.js +41 -17
- package/dist/core/model-resolver.js.map +1 -1
- package/dist/core/output-guard.d.ts +6 -0
- package/dist/core/output-guard.d.ts.map +1 -0
- package/dist/core/output-guard.js +59 -0
- package/dist/core/output-guard.js.map +1 -0
- package/dist/core/package-manager.d.ts +22 -1
- package/dist/core/package-manager.d.ts.map +1 -1
- package/dist/core/package-manager.js +373 -53
- package/dist/core/package-manager.js.map +1 -1
- package/dist/core/prompt-templates.d.ts +2 -1
- package/dist/core/prompt-templates.d.ts.map +1 -1
- package/dist/core/prompt-templates.js +39 -39
- package/dist/core/prompt-templates.js.map +1 -1
- package/dist/core/resolve-config-value.d.ts.map +1 -1
- package/dist/core/resolve-config-value.js +43 -8
- package/dist/core/resolve-config-value.js.map +1 -1
- package/dist/core/resource-loader.d.ts +6 -7
- package/dist/core/resource-loader.d.ts.map +1 -1
- package/dist/core/resource-loader.js +141 -118
- package/dist/core/resource-loader.js.map +1 -1
- package/dist/core/sdk.d.ts +3 -3
- package/dist/core/sdk.d.ts.map +1 -1
- package/dist/core/sdk.js +4 -4
- package/dist/core/sdk.js.map +1 -1
- package/dist/core/session-manager.d.ts +6 -0
- package/dist/core/session-manager.d.ts.map +1 -1
- package/dist/core/session-manager.js +9 -10
- package/dist/core/session-manager.js.map +1 -1
- package/dist/core/settings-manager.d.ts +3 -0
- package/dist/core/settings-manager.d.ts.map +1 -1
- package/dist/core/settings-manager.js +8 -0
- package/dist/core/settings-manager.js.map +1 -1
- package/dist/core/skills.d.ts +5 -3
- package/dist/core/skills.d.ts.map +1 -1
- package/dist/core/skills.js +54 -9
- package/dist/core/skills.js.map +1 -1
- package/dist/core/slash-commands.d.ts +2 -3
- package/dist/core/slash-commands.d.ts.map +1 -1
- package/dist/core/slash-commands.js +3 -2
- package/dist/core/slash-commands.js.map +1 -1
- package/dist/core/source-info.d.ts +18 -0
- package/dist/core/source-info.d.ts.map +1 -0
- package/dist/core/source-info.js +19 -0
- package/dist/core/source-info.js.map +1 -0
- package/dist/core/system-prompt.d.ts.map +1 -1
- package/dist/core/system-prompt.js +17 -60
- package/dist/core/system-prompt.js.map +1 -1
- package/dist/core/tools/bash.d.ts +24 -6
- package/dist/core/tools/bash.d.ts.map +1 -1
- package/dist/core/tools/bash.js +210 -110
- package/dist/core/tools/bash.js.map +1 -1
- package/dist/core/tools/edit-diff.d.ts.map +1 -1
- package/dist/core/tools/edit-diff.js +1 -0
- package/dist/core/tools/edit-diff.js.map +1 -1
- package/dist/core/tools/edit.d.ts +14 -2
- package/dist/core/tools/edit.d.ts.map +1 -1
- package/dist/core/tools/edit.js +95 -23
- package/dist/core/tools/edit.js.map +1 -1
- package/dist/core/tools/file-mutation-queue.d.ts +6 -0
- package/dist/core/tools/file-mutation-queue.d.ts.map +1 -0
- package/dist/core/tools/file-mutation-queue.js +37 -0
- package/dist/core/tools/file-mutation-queue.js.map +1 -0
- package/dist/core/tools/find.d.ts +11 -4
- package/dist/core/tools/find.d.ts.map +1 -1
- package/dist/core/tools/find.js +82 -30
- package/dist/core/tools/find.js.map +1 -1
- package/dist/core/tools/grep.d.ts +15 -4
- package/dist/core/tools/grep.d.ts.map +1 -1
- package/dist/core/tools/grep.js +83 -29
- package/dist/core/tools/grep.js.map +1 -1
- package/dist/core/tools/index.d.ts +58 -19
- package/dist/core/tools/index.d.ts.map +1 -1
- package/dist/core/tools/index.js +51 -26
- package/dist/core/tools/index.js.map +1 -1
- package/dist/core/tools/ls.d.ts +9 -3
- package/dist/core/tools/ls.d.ts.map +1 -1
- package/dist/core/tools/ls.js +67 -13
- package/dist/core/tools/ls.js.map +1 -1
- package/dist/core/tools/read.d.ts +10 -3
- package/dist/core/tools/read.d.ts.map +1 -1
- package/dist/core/tools/read.js +110 -51
- package/dist/core/tools/read.js.map +1 -1
- package/dist/core/tools/render-utils.d.ts +21 -0
- package/dist/core/tools/render-utils.d.ts.map +1 -0
- package/dist/core/tools/render-utils.js +49 -0
- package/dist/core/tools/render-utils.js.map +1 -0
- package/dist/core/tools/tool-definition-wrapper.d.ts +14 -0
- package/dist/core/tools/tool-definition-wrapper.d.ts.map +1 -0
- package/dist/core/tools/tool-definition-wrapper.js +30 -0
- package/dist/core/tools/tool-definition-wrapper.js.map +1 -0
- package/dist/core/tools/write.d.ts +9 -3
- package/dist/core/tools/write.d.ts.map +1 -1
- package/dist/core/tools/write.js +168 -30
- package/dist/core/tools/write.js.map +1 -1
- package/dist/index.d.ts +5 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -3
- package/dist/index.js.map +1 -1
- package/dist/main.d.ts.map +1 -1
- package/dist/main.js +105 -226
- package/dist/main.js.map +1 -1
- package/dist/modes/interactive/components/bash-execution.d.ts +0 -1
- package/dist/modes/interactive/components/bash-execution.d.ts.map +1 -1
- package/dist/modes/interactive/components/bash-execution.js +22 -9
- package/dist/modes/interactive/components/bash-execution.js.map +1 -1
- package/dist/modes/interactive/components/bordered-loader.d.ts.map +1 -1
- package/dist/modes/interactive/components/bordered-loader.js +1 -1
- package/dist/modes/interactive/components/bordered-loader.js.map +1 -1
- package/dist/modes/interactive/components/branch-summary-message.d.ts.map +1 -1
- package/dist/modes/interactive/components/branch-summary-message.js +2 -2
- package/dist/modes/interactive/components/branch-summary-message.js.map +1 -1
- package/dist/modes/interactive/components/compaction-summary-message.d.ts.map +1 -1
- package/dist/modes/interactive/components/compaction-summary-message.js +2 -2
- package/dist/modes/interactive/components/compaction-summary-message.js.map +1 -1
- package/dist/modes/interactive/components/config-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/config-selector.js +8 -8
- package/dist/modes/interactive/components/config-selector.js.map +1 -1
- package/dist/modes/interactive/components/custom-editor.d.ts +3 -3
- package/dist/modes/interactive/components/custom-editor.d.ts.map +1 -1
- package/dist/modes/interactive/components/custom-editor.js +6 -6
- package/dist/modes/interactive/components/custom-editor.js.map +1 -1
- package/dist/modes/interactive/components/extension-editor.d.ts.map +1 -1
- package/dist/modes/interactive/components/extension-editor.js +9 -9
- package/dist/modes/interactive/components/extension-editor.js.map +1 -1
- package/dist/modes/interactive/components/extension-input.d.ts.map +1 -1
- package/dist/modes/interactive/components/extension-input.js +5 -5
- package/dist/modes/interactive/components/extension-input.js.map +1 -1
- package/dist/modes/interactive/components/extension-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/extension-selector.js +8 -8
- package/dist/modes/interactive/components/extension-selector.js.map +1 -1
- package/dist/modes/interactive/components/index.d.ts +1 -1
- package/dist/modes/interactive/components/index.d.ts.map +1 -1
- package/dist/modes/interactive/components/index.js +1 -1
- package/dist/modes/interactive/components/index.js.map +1 -1
- package/dist/modes/interactive/components/keybinding-hints.d.ts +3 -36
- package/dist/modes/interactive/components/keybinding-hints.d.ts.map +1 -1
- package/dist/modes/interactive/components/keybinding-hints.js +5 -44
- package/dist/modes/interactive/components/keybinding-hints.js.map +1 -1
- package/dist/modes/interactive/components/login-dialog.d.ts.map +1 -1
- package/dist/modes/interactive/components/login-dialog.js +6 -6
- package/dist/modes/interactive/components/login-dialog.js.map +1 -1
- package/dist/modes/interactive/components/model-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/model-selector.js +13 -9
- package/dist/modes/interactive/components/model-selector.js.map +1 -1
- package/dist/modes/interactive/components/oauth-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/oauth-selector.js +6 -6
- package/dist/modes/interactive/components/oauth-selector.js.map +1 -1
- package/dist/modes/interactive/components/scoped-models-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/scoped-models-selector.js +4 -4
- package/dist/modes/interactive/components/scoped-models-selector.js.map +1 -1
- package/dist/modes/interactive/components/session-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/session-selector.js +32 -35
- package/dist/modes/interactive/components/session-selector.js.map +1 -1
- package/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/settings-selector.js +5 -1
- package/dist/modes/interactive/components/settings-selector.js.map +1 -1
- package/dist/modes/interactive/components/show-images-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/show-images-selector.js +5 -1
- package/dist/modes/interactive/components/show-images-selector.js.map +1 -1
- package/dist/modes/interactive/components/skill-invocation-message.d.ts.map +1 -1
- package/dist/modes/interactive/components/skill-invocation-message.js +2 -2
- package/dist/modes/interactive/components/skill-invocation-message.js.map +1 -1
- package/dist/modes/interactive/components/theme-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/theme-selector.js +5 -1
- package/dist/modes/interactive/components/theme-selector.js.map +1 -1
- package/dist/modes/interactive/components/thinking-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/thinking-selector.js +5 -1
- package/dist/modes/interactive/components/thinking-selector.js.map +1 -1
- package/dist/modes/interactive/components/tool-execution.d.ts +16 -34
- package/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
- package/dist/modes/interactive/components/tool-execution.js +128 -636
- package/dist/modes/interactive/components/tool-execution.js.map +1 -1
- package/dist/modes/interactive/components/tree-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/tree-selector.js +27 -16
- package/dist/modes/interactive/components/tree-selector.js.map +1 -1
- package/dist/modes/interactive/components/user-message-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/user-message-selector.js +6 -6
- package/dist/modes/interactive/components/user-message-selector.js.map +1 -1
- package/dist/modes/interactive/components/user-message.d.ts.map +1 -1
- package/dist/modes/interactive/components/user-message.js +2 -1
- package/dist/modes/interactive/components/user-message.js.map +1 -1
- package/dist/modes/interactive/interactive-mode.d.ts +7 -11
- package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-mode.js +353 -214
- package/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/dist/modes/interactive/theme/theme.d.ts +3 -0
- package/dist/modes/interactive/theme/theme.d.ts.map +1 -1
- package/dist/modes/interactive/theme/theme.js +63 -37
- package/dist/modes/interactive/theme/theme.js.map +1 -1
- package/dist/modes/print-mode.d.ts.map +1 -1
- package/dist/modes/print-mode.js +5 -11
- package/dist/modes/print-mode.js.map +1 -1
- package/dist/modes/rpc/rpc-mode.d.ts.map +1 -1
- package/dist/modes/rpc/rpc-mode.js +27 -17
- package/dist/modes/rpc/rpc-mode.js.map +1 -1
- package/dist/modes/rpc/rpc-types.d.ts +3 -4
- package/dist/modes/rpc/rpc-types.d.ts.map +1 -1
- package/dist/modes/rpc/rpc-types.js.map +1 -1
- package/dist/utils/child-process.d.ts +11 -0
- package/dist/utils/child-process.d.ts.map +1 -0
- package/dist/utils/child-process.js +78 -0
- package/dist/utils/child-process.js.map +1 -0
- package/dist/utils/clipboard-image.d.ts.map +1 -1
- package/dist/utils/clipboard-image.js +94 -11
- package/dist/utils/clipboard-image.js.map +1 -1
- package/dist/utils/clipboard-native.d.ts +1 -0
- package/dist/utils/clipboard-native.d.ts.map +1 -1
- package/dist/utils/clipboard-native.js.map +1 -1
- package/dist/utils/clipboard.d.ts +1 -1
- package/dist/utils/clipboard.d.ts.map +1 -1
- package/dist/utils/clipboard.js +27 -16
- package/dist/utils/clipboard.js.map +1 -1
- package/dist/utils/exif-orientation.d.ts +5 -0
- package/dist/utils/exif-orientation.d.ts.map +1 -0
- package/dist/utils/exif-orientation.js +158 -0
- package/dist/utils/exif-orientation.js.map +1 -0
- package/dist/utils/image-convert.d.ts.map +1 -1
- package/dist/utils/image-convert.js +5 -1
- package/dist/utils/image-convert.js.map +1 -1
- package/dist/utils/image-resize.d.ts +5 -5
- package/dist/utils/image-resize.d.ts.map +1 -1
- package/dist/utils/image-resize.js +51 -95
- package/dist/utils/image-resize.js.map +1 -1
- package/dist/utils/tools-manager.d.ts.map +1 -1
- package/dist/utils/tools-manager.js +5 -4
- package/dist/utils/tools-manager.js.map +1 -1
- package/docs/custom-provider.md +6 -2
- package/docs/extensions.md +108 -21
- package/docs/keybindings.md +103 -112
- package/docs/models.md +39 -1
- package/docs/packages.md +9 -0
- package/docs/providers.md +7 -0
- package/docs/rpc.md +15 -6
- package/docs/sdk.md +2 -2
- package/docs/settings.md +9 -0
- package/docs/terminal-setup.md +11 -0
- package/docs/tui.md +2 -2
- package/examples/extensions/README.md +2 -2
- package/examples/extensions/antigravity-image-gen.ts +5 -3
- package/examples/extensions/built-in-tool-renderer.ts +8 -8
- package/examples/extensions/commands.ts +3 -3
- package/examples/extensions/minimal-mode.ts +14 -14
- package/examples/extensions/question.ts +2 -2
- package/examples/extensions/questionnaire.ts +2 -2
- package/examples/extensions/subagent/index.ts +30 -8
- package/examples/extensions/titlebar-spinner.ts +2 -2
- package/examples/extensions/todo.ts +2 -2
- package/examples/extensions/tool-override.ts +9 -7
- package/examples/extensions/truncated-tool.ts +8 -5
- package/examples/sdk/04-skills.ts +8 -2
- package/examples/sdk/08-prompt-templates.ts +8 -2
- package/examples/sdk/12-full-control.ts +0 -1
- package/examples/sdk/README.md +1 -1
- package/package.json +4 -4
package/docs/rpc.md
CHANGED
|
@@ -58,7 +58,7 @@ With images:
|
|
|
58
58
|
{"type": "prompt", "message": "New instruction", "streamingBehavior": "steer"}
|
|
59
59
|
```
|
|
60
60
|
|
|
61
|
-
- `"steer"`:
|
|
61
|
+
- `"steer"`: Queue the message while the agent is running. It is delivered after the current assistant turn finishes executing its tool calls, before the next LLM call.
|
|
62
62
|
- `"followUp"`: Wait until the agent finishes. Message is delivered only when agent stops.
|
|
63
63
|
|
|
64
64
|
If the agent is streaming and no `streamingBehavior` is specified, the command returns an error.
|
|
@@ -76,7 +76,7 @@ The `images` field is optional. Each image uses `ImageContent` format: `{"type":
|
|
|
76
76
|
|
|
77
77
|
#### steer
|
|
78
78
|
|
|
79
|
-
Queue a steering message
|
|
79
|
+
Queue a steering message while the agent is running. It is delivered after the current assistant turn finishes executing its tool calls, before the next LLM call. Skill commands and prompt templates are expanded. Extension commands are not allowed (use `prompt` instead).
|
|
80
80
|
|
|
81
81
|
```json
|
|
82
82
|
{"type": "steer", "message": "Stop and do this instead"}
|
|
@@ -321,8 +321,8 @@ Control how steering messages (from `steer`) are delivered.
|
|
|
321
321
|
```
|
|
322
322
|
|
|
323
323
|
Modes:
|
|
324
|
-
- `"all"`: Deliver all steering messages
|
|
325
|
-
- `"one-at-a-time"`: Deliver one steering message per
|
|
324
|
+
- `"all"`: Deliver all steering messages after the current assistant turn finishes executing its tool calls
|
|
325
|
+
- `"one-at-a-time"`: Deliver one steering message per completed assistant turn (default)
|
|
326
326
|
|
|
327
327
|
Response:
|
|
328
328
|
```json
|
|
@@ -494,7 +494,7 @@ Response:
|
|
|
494
494
|
|
|
495
495
|
#### get_session_stats
|
|
496
496
|
|
|
497
|
-
Get token usage and
|
|
497
|
+
Get token usage, cost statistics, and current context window usage.
|
|
498
498
|
|
|
499
499
|
```json
|
|
500
500
|
{"type": "get_session_stats"}
|
|
@@ -521,11 +521,20 @@ Response:
|
|
|
521
521
|
"cacheWrite": 5000,
|
|
522
522
|
"total": 105000
|
|
523
523
|
},
|
|
524
|
-
"cost": 0.45
|
|
524
|
+
"cost": 0.45,
|
|
525
|
+
"contextUsage": {
|
|
526
|
+
"tokens": 60000,
|
|
527
|
+
"contextWindow": 200000,
|
|
528
|
+
"percent": 30
|
|
529
|
+
}
|
|
525
530
|
}
|
|
526
531
|
}
|
|
527
532
|
```
|
|
528
533
|
|
|
534
|
+
`tokens` contains assistant usage totals for the current session state. `contextUsage` contains the actual current context-window estimate used for compaction and footer display.
|
|
535
|
+
|
|
536
|
+
`contextUsage` is omitted when no model or context window is available. `contextUsage.tokens` and `contextUsage.percent` are `null` immediately after compaction until a fresh post-compaction assistant response provides valid usage data.
|
|
537
|
+
|
|
529
538
|
#### export_html
|
|
530
539
|
|
|
531
540
|
Export session to an HTML file.
|
package/docs/sdk.md
CHANGED
|
@@ -78,7 +78,7 @@ interface AgentSession {
|
|
|
78
78
|
prompt(text: string, options?: PromptOptions): Promise<void>;
|
|
79
79
|
|
|
80
80
|
// Queue messages during streaming
|
|
81
|
-
steer(text: string): Promise<void>; //
|
|
81
|
+
steer(text: string): Promise<void>; // Queue for delivery after the current assistant turn finishes its tool calls
|
|
82
82
|
followUp(text: string): Promise<void>; // Wait: delivered only when agent finishes
|
|
83
83
|
|
|
84
84
|
// Subscribe to events (returns unsubscribe function)
|
|
@@ -150,7 +150,7 @@ await session.prompt("After you're done, also check X", { streamingBehavior: "fo
|
|
|
150
150
|
For explicit queueing during streaming:
|
|
151
151
|
|
|
152
152
|
```typescript
|
|
153
|
-
//
|
|
153
|
+
// Queue a steering message for delivery after the current assistant turn finishes its tool calls
|
|
154
154
|
await session.steer("New instruction");
|
|
155
155
|
|
|
156
156
|
// Wait for agent to finish (delivered only when agent stops)
|
package/docs/settings.md
CHANGED
|
@@ -117,6 +117,15 @@ When a provider requests a retry delay longer than `maxDelayMs` (e.g., Google's
|
|
|
117
117
|
|---------|------|---------|-------------|
|
|
118
118
|
| `shellPath` | string | - | Custom shell path (e.g., for Cygwin on Windows) |
|
|
119
119
|
| `shellCommandPrefix` | string | - | Prefix for every bash command (e.g., `"shopt -s expand_aliases"`) |
|
|
120
|
+
| `npmCommand` | string[] | - | Command argv used for npm package lookup/install operations (e.g., `["mise", "exec", "node@20", "--", "npm"]`) |
|
|
121
|
+
|
|
122
|
+
```json
|
|
123
|
+
{
|
|
124
|
+
"npmCommand": ["mise", "exec", "node@20", "--", "npm"]
|
|
125
|
+
}
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
`npmCommand` is used for all npm package-manager operations, including `npm root -g`, installs, uninstalls, and `npm install` inside git packages. Use argv-style entries exactly as the process should be launched.
|
|
120
129
|
|
|
121
130
|
### Model Cycling
|
|
122
131
|
|
package/docs/terminal-setup.md
CHANGED
|
@@ -86,6 +86,17 @@ Add to `settings.json` (Ctrl+Shift+, or Settings → Open JSON file) to forward
|
|
|
86
86
|
|
|
87
87
|
If you already have an `actions` array, add the objects to it. If the old fullscreen behavior persists, fully close and reopen Windows Terminal.
|
|
88
88
|
|
|
89
|
+
## xfce4-terminal, terminator
|
|
90
|
+
|
|
91
|
+
These terminals have limited escape sequence support. Modified Enter keys like `Ctrl+Enter` and `Shift+Enter` cannot be distinguished from plain `Enter`, preventing custom keybindings such as `submit: ["ctrl+enter"]` from working.
|
|
92
|
+
|
|
93
|
+
For the best experience, use a terminal that supports the Kitty keyboard protocol:
|
|
94
|
+
- [Kitty](https://sw.kovidgoyal.net/kitty/)
|
|
95
|
+
- [Ghostty](https://ghostty.org/)
|
|
96
|
+
- [WezTerm](https://wezfurlong.org/wezterm/)
|
|
97
|
+
- [iTerm2](https://iterm2.com/)
|
|
98
|
+
- [Alacritty](https://github.com/alacritty/alacritty) (requires compilation with Kitty protocol support)
|
|
99
|
+
|
|
89
100
|
## IntelliJ IDEA (Integrated Terminal)
|
|
90
101
|
|
|
91
102
|
The built-in terminal has limited escape sequence support. Shift+Enter cannot be distinguished from Enter in IntelliJ's terminal.
|
package/docs/tui.md
CHANGED
|
@@ -394,7 +394,7 @@ Components accept theme objects for styling.
|
|
|
394
394
|
**In `renderCall`/`renderResult`**, use the `theme` parameter:
|
|
395
395
|
|
|
396
396
|
```typescript
|
|
397
|
-
renderResult(result, options, theme) {
|
|
397
|
+
renderResult(result, options, theme, context) {
|
|
398
398
|
// Use theme.fg() for foreground colors
|
|
399
399
|
return new Text(theme.fg("success", "Done!"), 0, 0);
|
|
400
400
|
|
|
@@ -428,7 +428,7 @@ renderResult(result, options, theme) {
|
|
|
428
428
|
import { getMarkdownTheme } from "@draht/coding-agent";
|
|
429
429
|
import { Markdown } from "@draht/tui";
|
|
430
430
|
|
|
431
|
-
renderResult(result, options, theme) {
|
|
431
|
+
renderResult(result, options, theme, context) {
|
|
432
432
|
const mdTheme = getMarkdownTheme();
|
|
433
433
|
return new Markdown(result.details.markdown, 0, 0, mdTheme);
|
|
434
434
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Extension Examples
|
|
2
2
|
|
|
3
|
-
Example extensions for
|
|
3
|
+
Example extensions for @draht/coding-agent.
|
|
4
4
|
|
|
5
5
|
## Usage
|
|
6
6
|
|
|
@@ -119,7 +119,7 @@ cp permission-gate.ts ~/.draht/agent/extensions/
|
|
|
119
119
|
| Extension | Description |
|
|
120
120
|
|-----------|-------------|
|
|
121
121
|
| `custom-provider-anthropic/` | Custom Anthropic provider with OAuth support and custom streaming implementation |
|
|
122
|
-
| `custom-provider-gitlab-duo/` | GitLab Duo provider using
|
|
122
|
+
| `custom-provider-gitlab-duo/` | GitLab Duo provider using @draht/ai's built-in Anthropic/OpenAI streaming via proxy |
|
|
123
123
|
| `custom-provider-qwen-cli/` | Qwen CLI provider with OAuth device flow and OpenAI-compatible models |
|
|
124
124
|
|
|
125
125
|
### External Dependencies
|
|
@@ -30,7 +30,7 @@ import { existsSync, readFileSync } from "node:fs";
|
|
|
30
30
|
import { mkdir, writeFile } from "node:fs/promises";
|
|
31
31
|
import { join } from "node:path";
|
|
32
32
|
import { StringEnum } from "@draht/ai";
|
|
33
|
-
import { type ExtensionAPI, getAgentDir } from "@draht/coding-agent";
|
|
33
|
+
import { type ExtensionAPI, getAgentDir, withFileMutationQueue } from "@draht/coding-agent";
|
|
34
34
|
import { type Static, Type } from "@sinclair/typebox";
|
|
35
35
|
|
|
36
36
|
const PROVIDER = "google-antigravity";
|
|
@@ -228,12 +228,14 @@ function imageExtension(mimeType: string): string {
|
|
|
228
228
|
}
|
|
229
229
|
|
|
230
230
|
async function saveImage(base64Data: string, mimeType: string, outputDir: string): Promise<string> {
|
|
231
|
-
await mkdir(outputDir, { recursive: true });
|
|
232
231
|
const timestamp = new Date().toISOString().replace(/[:.]/g, "-");
|
|
233
232
|
const ext = imageExtension(mimeType);
|
|
234
233
|
const filename = `image-${timestamp}-${randomUUID().slice(0, 8)}.${ext}`;
|
|
235
234
|
const filePath = join(outputDir, filename);
|
|
236
|
-
await
|
|
235
|
+
await withFileMutationQueue(filePath, async () => {
|
|
236
|
+
await mkdir(outputDir, { recursive: true });
|
|
237
|
+
await writeFile(filePath, Buffer.from(base64Data, "base64"));
|
|
238
|
+
});
|
|
237
239
|
return filePath;
|
|
238
240
|
}
|
|
239
241
|
|
|
@@ -42,7 +42,7 @@ export default function (pi: ExtensionAPI) {
|
|
|
42
42
|
return originalRead.execute(toolCallId, params, signal, onUpdate);
|
|
43
43
|
},
|
|
44
44
|
|
|
45
|
-
renderCall(args, theme) {
|
|
45
|
+
renderCall(args, theme, _context) {
|
|
46
46
|
let text = theme.fg("toolTitle", theme.bold("read "));
|
|
47
47
|
text += theme.fg("accent", args.path);
|
|
48
48
|
if (args.offset || args.limit) {
|
|
@@ -54,7 +54,7 @@ export default function (pi: ExtensionAPI) {
|
|
|
54
54
|
return new Text(text, 0, 0);
|
|
55
55
|
},
|
|
56
56
|
|
|
57
|
-
renderResult(result, { expanded, isPartial }, theme) {
|
|
57
|
+
renderResult(result, { expanded, isPartial }, theme, _context) {
|
|
58
58
|
if (isPartial) return new Text(theme.fg("warning", "Reading..."), 0, 0);
|
|
59
59
|
|
|
60
60
|
const details = result.details as ReadToolDetails | undefined;
|
|
@@ -101,7 +101,7 @@ export default function (pi: ExtensionAPI) {
|
|
|
101
101
|
return originalBash.execute(toolCallId, params, signal, onUpdate);
|
|
102
102
|
},
|
|
103
103
|
|
|
104
|
-
renderCall(args, theme) {
|
|
104
|
+
renderCall(args, theme, _context) {
|
|
105
105
|
let text = theme.fg("toolTitle", theme.bold("$ "));
|
|
106
106
|
const cmd = args.command.length > 80 ? `${args.command.slice(0, 77)}...` : args.command;
|
|
107
107
|
text += theme.fg("accent", cmd);
|
|
@@ -111,7 +111,7 @@ export default function (pi: ExtensionAPI) {
|
|
|
111
111
|
return new Text(text, 0, 0);
|
|
112
112
|
},
|
|
113
113
|
|
|
114
|
-
renderResult(result, { expanded, isPartial }, theme) {
|
|
114
|
+
renderResult(result, { expanded, isPartial }, theme, _context) {
|
|
115
115
|
if (isPartial) return new Text(theme.fg("warning", "Running..."), 0, 0);
|
|
116
116
|
|
|
117
117
|
const details = result.details as BashToolDetails | undefined;
|
|
@@ -160,13 +160,13 @@ export default function (pi: ExtensionAPI) {
|
|
|
160
160
|
return originalEdit.execute(toolCallId, params, signal, onUpdate);
|
|
161
161
|
},
|
|
162
162
|
|
|
163
|
-
renderCall(args, theme) {
|
|
163
|
+
renderCall(args, theme, _context) {
|
|
164
164
|
let text = theme.fg("toolTitle", theme.bold("edit "));
|
|
165
165
|
text += theme.fg("accent", args.path);
|
|
166
166
|
return new Text(text, 0, 0);
|
|
167
167
|
},
|
|
168
168
|
|
|
169
|
-
renderResult(result, { expanded, isPartial }, theme) {
|
|
169
|
+
renderResult(result, { expanded, isPartial }, theme, _context) {
|
|
170
170
|
if (isPartial) return new Text(theme.fg("warning", "Editing..."), 0, 0);
|
|
171
171
|
|
|
172
172
|
const details = result.details as EditToolDetails | undefined;
|
|
@@ -224,7 +224,7 @@ export default function (pi: ExtensionAPI) {
|
|
|
224
224
|
return originalWrite.execute(toolCallId, params, signal, onUpdate);
|
|
225
225
|
},
|
|
226
226
|
|
|
227
|
-
renderCall(args, theme) {
|
|
227
|
+
renderCall(args, theme, _context) {
|
|
228
228
|
let text = theme.fg("toolTitle", theme.bold("write "));
|
|
229
229
|
text += theme.fg("accent", args.path);
|
|
230
230
|
const lineCount = args.content.split("\n").length;
|
|
@@ -232,7 +232,7 @@ export default function (pi: ExtensionAPI) {
|
|
|
232
232
|
return new Text(text, 0, 0);
|
|
233
233
|
},
|
|
234
234
|
|
|
235
|
-
renderResult(result, { isPartial }, theme) {
|
|
235
|
+
renderResult(result, { isPartial }, theme, _context) {
|
|
236
236
|
if (isPartial) return new Text(theme.fg("warning", "Writing..."), 0, 0);
|
|
237
237
|
|
|
238
238
|
const content = result.content[0];
|
|
@@ -60,10 +60,10 @@ export default function commandsExtension(pi: ExtensionAPI) {
|
|
|
60
60
|
if (selected && !selected.startsWith("---")) {
|
|
61
61
|
const cmdName = selected.split(" - ")[0].slice(1); // Remove leading /
|
|
62
62
|
const cmd = commands.find((c) => c.name === cmdName);
|
|
63
|
-
if (cmd?.path) {
|
|
64
|
-
const showPath = await ctx.ui.confirm(cmd.name, `View source path?\n${cmd.path}`);
|
|
63
|
+
if (cmd?.sourceInfo.path) {
|
|
64
|
+
const showPath = await ctx.ui.confirm(cmd.name, `View source path?\n${cmd.sourceInfo.path}`);
|
|
65
65
|
if (showPath) {
|
|
66
|
-
ctx.ui.notify(cmd.path, "info");
|
|
66
|
+
ctx.ui.notify(cmd.sourceInfo.path, "info");
|
|
67
67
|
}
|
|
68
68
|
}
|
|
69
69
|
}
|
|
@@ -80,7 +80,7 @@ export default function (pi: ExtensionAPI) {
|
|
|
80
80
|
return tools.read.execute(toolCallId, params, signal, onUpdate);
|
|
81
81
|
},
|
|
82
82
|
|
|
83
|
-
renderCall(args, theme) {
|
|
83
|
+
renderCall(args, theme, _context) {
|
|
84
84
|
const path = shortenPath(args.path || "");
|
|
85
85
|
let pathDisplay = path ? theme.fg("accent", path) : theme.fg("toolOutput", "...");
|
|
86
86
|
|
|
@@ -94,7 +94,7 @@ export default function (pi: ExtensionAPI) {
|
|
|
94
94
|
return new Text(`${theme.fg("toolTitle", theme.bold("read"))} ${pathDisplay}`, 0, 0);
|
|
95
95
|
},
|
|
96
96
|
|
|
97
|
-
renderResult(result, { expanded }, theme) {
|
|
97
|
+
renderResult(result, { expanded }, theme, _context) {
|
|
98
98
|
// Minimal mode: show nothing in collapsed state
|
|
99
99
|
if (!expanded) {
|
|
100
100
|
return new Text("", 0, 0);
|
|
@@ -127,7 +127,7 @@ export default function (pi: ExtensionAPI) {
|
|
|
127
127
|
return tools.bash.execute(toolCallId, params, signal, onUpdate);
|
|
128
128
|
},
|
|
129
129
|
|
|
130
|
-
renderCall(args, theme) {
|
|
130
|
+
renderCall(args, theme, _context) {
|
|
131
131
|
const command = args.command || "...";
|
|
132
132
|
const timeout = args.timeout as number | undefined;
|
|
133
133
|
const timeoutSuffix = timeout ? theme.fg("muted", ` (timeout ${timeout}s)`) : "";
|
|
@@ -135,7 +135,7 @@ export default function (pi: ExtensionAPI) {
|
|
|
135
135
|
return new Text(theme.fg("toolTitle", theme.bold(`$ ${command}`)) + timeoutSuffix, 0, 0);
|
|
136
136
|
},
|
|
137
137
|
|
|
138
|
-
renderResult(result, { expanded }, theme) {
|
|
138
|
+
renderResult(result, { expanded }, theme, _context) {
|
|
139
139
|
// Minimal mode: show nothing in collapsed state
|
|
140
140
|
if (!expanded) {
|
|
141
141
|
return new Text("", 0, 0);
|
|
@@ -176,7 +176,7 @@ export default function (pi: ExtensionAPI) {
|
|
|
176
176
|
return tools.write.execute(toolCallId, params, signal, onUpdate);
|
|
177
177
|
},
|
|
178
178
|
|
|
179
|
-
renderCall(args, theme) {
|
|
179
|
+
renderCall(args, theme, _context) {
|
|
180
180
|
const path = shortenPath(args.path || "");
|
|
181
181
|
const pathDisplay = path ? theme.fg("accent", path) : theme.fg("toolOutput", "...");
|
|
182
182
|
const lineCount = args.content ? args.content.split("\n").length : 0;
|
|
@@ -185,7 +185,7 @@ export default function (pi: ExtensionAPI) {
|
|
|
185
185
|
return new Text(`${theme.fg("toolTitle", theme.bold("write"))} ${pathDisplay}${lineInfo}`, 0, 0);
|
|
186
186
|
},
|
|
187
187
|
|
|
188
|
-
renderResult(result, { expanded }, theme) {
|
|
188
|
+
renderResult(result, { expanded }, theme, _context) {
|
|
189
189
|
// Minimal mode: show nothing (file was written)
|
|
190
190
|
if (!expanded) {
|
|
191
191
|
return new Text("", 0, 0);
|
|
@@ -218,14 +218,14 @@ export default function (pi: ExtensionAPI) {
|
|
|
218
218
|
return tools.edit.execute(toolCallId, params, signal, onUpdate);
|
|
219
219
|
},
|
|
220
220
|
|
|
221
|
-
renderCall(args, theme) {
|
|
221
|
+
renderCall(args, theme, _context) {
|
|
222
222
|
const path = shortenPath(args.path || "");
|
|
223
223
|
const pathDisplay = path ? theme.fg("accent", path) : theme.fg("toolOutput", "...");
|
|
224
224
|
|
|
225
225
|
return new Text(`${theme.fg("toolTitle", theme.bold("edit"))} ${pathDisplay}`, 0, 0);
|
|
226
226
|
},
|
|
227
227
|
|
|
228
|
-
renderResult(result, { expanded }, theme) {
|
|
228
|
+
renderResult(result, { expanded }, theme, _context) {
|
|
229
229
|
// Minimal mode: show nothing in collapsed state
|
|
230
230
|
if (!expanded) {
|
|
231
231
|
return new Text("", 0, 0);
|
|
@@ -263,7 +263,7 @@ export default function (pi: ExtensionAPI) {
|
|
|
263
263
|
return tools.find.execute(toolCallId, params, signal, onUpdate);
|
|
264
264
|
},
|
|
265
265
|
|
|
266
|
-
renderCall(args, theme) {
|
|
266
|
+
renderCall(args, theme, _context) {
|
|
267
267
|
const pattern = args.pattern || "";
|
|
268
268
|
const path = shortenPath(args.path || ".");
|
|
269
269
|
const limit = args.limit;
|
|
@@ -277,7 +277,7 @@ export default function (pi: ExtensionAPI) {
|
|
|
277
277
|
return new Text(text, 0, 0);
|
|
278
278
|
},
|
|
279
279
|
|
|
280
|
-
renderResult(result, { expanded }, theme) {
|
|
280
|
+
renderResult(result, { expanded }, theme, _context) {
|
|
281
281
|
if (!expanded) {
|
|
282
282
|
// Minimal: just show count
|
|
283
283
|
const textContent = result.content.find((c) => c.type === "text");
|
|
@@ -321,7 +321,7 @@ export default function (pi: ExtensionAPI) {
|
|
|
321
321
|
return tools.grep.execute(toolCallId, params, signal, onUpdate);
|
|
322
322
|
},
|
|
323
323
|
|
|
324
|
-
renderCall(args, theme) {
|
|
324
|
+
renderCall(args, theme, _context) {
|
|
325
325
|
const pattern = args.pattern || "";
|
|
326
326
|
const path = shortenPath(args.path || ".");
|
|
327
327
|
const glob = args.glob;
|
|
@@ -339,7 +339,7 @@ export default function (pi: ExtensionAPI) {
|
|
|
339
339
|
return new Text(text, 0, 0);
|
|
340
340
|
},
|
|
341
341
|
|
|
342
|
-
renderResult(result, { expanded }, theme) {
|
|
342
|
+
renderResult(result, { expanded }, theme, _context) {
|
|
343
343
|
if (!expanded) {
|
|
344
344
|
// Minimal: just show match count
|
|
345
345
|
const textContent = result.content.find((c) => c.type === "text");
|
|
@@ -383,7 +383,7 @@ export default function (pi: ExtensionAPI) {
|
|
|
383
383
|
return tools.ls.execute(toolCallId, params, signal, onUpdate);
|
|
384
384
|
},
|
|
385
385
|
|
|
386
|
-
renderCall(args, theme) {
|
|
386
|
+
renderCall(args, theme, _context) {
|
|
387
387
|
const path = shortenPath(args.path || ".");
|
|
388
388
|
const limit = args.limit;
|
|
389
389
|
|
|
@@ -395,7 +395,7 @@ export default function (pi: ExtensionAPI) {
|
|
|
395
395
|
return new Text(text, 0, 0);
|
|
396
396
|
},
|
|
397
397
|
|
|
398
|
-
renderResult(result, { expanded }, theme) {
|
|
398
|
+
renderResult(result, { expanded }, theme, _context) {
|
|
399
399
|
if (!expanded) {
|
|
400
400
|
// Minimal: just show entry count
|
|
401
401
|
const textContent = result.content.find((c) => c.type === "text");
|
|
@@ -227,7 +227,7 @@ export default function question(pi: ExtensionAPI) {
|
|
|
227
227
|
};
|
|
228
228
|
},
|
|
229
229
|
|
|
230
|
-
renderCall(args, theme) {
|
|
230
|
+
renderCall(args, theme, _context) {
|
|
231
231
|
let text = theme.fg("toolTitle", theme.bold("question ")) + theme.fg("muted", args.question);
|
|
232
232
|
const opts = Array.isArray(args.options) ? args.options : [];
|
|
233
233
|
if (opts.length) {
|
|
@@ -238,7 +238,7 @@ export default function question(pi: ExtensionAPI) {
|
|
|
238
238
|
return new Text(text, 0, 0);
|
|
239
239
|
},
|
|
240
240
|
|
|
241
|
-
renderResult(result, _options, theme) {
|
|
241
|
+
renderResult(result, _options, theme, _context) {
|
|
242
242
|
const details = result.details as QuestionDetails | undefined;
|
|
243
243
|
if (!details) {
|
|
244
244
|
const text = result.content[0];
|
|
@@ -393,7 +393,7 @@ export default function questionnaire(pi: ExtensionAPI) {
|
|
|
393
393
|
};
|
|
394
394
|
},
|
|
395
395
|
|
|
396
|
-
renderCall(args, theme) {
|
|
396
|
+
renderCall(args, theme, _context) {
|
|
397
397
|
const qs = (args.questions as Question[]) || [];
|
|
398
398
|
const count = qs.length;
|
|
399
399
|
const labels = qs.map((q) => q.label || q.id).join(", ");
|
|
@@ -405,7 +405,7 @@ export default function questionnaire(pi: ExtensionAPI) {
|
|
|
405
405
|
return new Text(text, 0, 0);
|
|
406
406
|
},
|
|
407
407
|
|
|
408
|
-
renderResult(result, _options, theme) {
|
|
408
|
+
renderResult(result, _options, theme, _context) {
|
|
409
409
|
const details = result.details as QuestionnaireResult | undefined;
|
|
410
410
|
if (!details) {
|
|
411
411
|
const text = result.content[0];
|
|
@@ -19,7 +19,7 @@ import * as path from "node:path";
|
|
|
19
19
|
import type { AgentToolResult } from "@draht/agent-core";
|
|
20
20
|
import type { Message } from "@draht/ai";
|
|
21
21
|
import { StringEnum } from "@draht/ai";
|
|
22
|
-
import { type ExtensionAPI, getMarkdownTheme } from "@draht/coding-agent";
|
|
22
|
+
import { type ExtensionAPI, getMarkdownTheme, withFileMutationQueue } from "@draht/coding-agent";
|
|
23
23
|
import { Container, Markdown, Spacer, Text } from "@draht/tui";
|
|
24
24
|
import { Type } from "@sinclair/typebox";
|
|
25
25
|
import { type AgentConfig, type AgentScope, discoverAgents } from "./agents.js";
|
|
@@ -207,14 +207,31 @@ async function mapWithConcurrencyLimit<TIn, TOut>(
|
|
|
207
207
|
return results;
|
|
208
208
|
}
|
|
209
209
|
|
|
210
|
-
function writePromptToTempFile(agentName: string, prompt: string): { dir: string; filePath: string } {
|
|
211
|
-
const tmpDir = fs.
|
|
210
|
+
async function writePromptToTempFile(agentName: string, prompt: string): Promise<{ dir: string; filePath: string }> {
|
|
211
|
+
const tmpDir = await fs.promises.mkdtemp(path.join(os.tmpdir(), "pi-subagent-"));
|
|
212
212
|
const safeName = agentName.replace(/[^\w.-]+/g, "_");
|
|
213
213
|
const filePath = path.join(tmpDir, `prompt-${safeName}.md`);
|
|
214
|
-
|
|
214
|
+
await withFileMutationQueue(filePath, async () => {
|
|
215
|
+
await fs.promises.writeFile(filePath, prompt, { encoding: "utf-8", mode: 0o600 });
|
|
216
|
+
});
|
|
215
217
|
return { dir: tmpDir, filePath };
|
|
216
218
|
}
|
|
217
219
|
|
|
220
|
+
function getPiInvocation(args: string[]): { command: string; args: string[] } {
|
|
221
|
+
const currentScript = process.argv[1];
|
|
222
|
+
if (currentScript && fs.existsSync(currentScript)) {
|
|
223
|
+
return { command: process.execPath, args: [currentScript, ...args] };
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
const execName = path.basename(process.execPath).toLowerCase();
|
|
227
|
+
const isGenericRuntime = /^(node|bun)(\.exe)?$/.test(execName);
|
|
228
|
+
if (!isGenericRuntime) {
|
|
229
|
+
return { command: process.execPath, args };
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
return { command: "pi", args };
|
|
233
|
+
}
|
|
234
|
+
|
|
218
235
|
type OnUpdateCallback = (partial: AgentToolResult<SubagentDetails>) => void;
|
|
219
236
|
|
|
220
237
|
async function runSingleAgent(
|
|
@@ -274,7 +291,7 @@ async function runSingleAgent(
|
|
|
274
291
|
|
|
275
292
|
try {
|
|
276
293
|
if (agent.systemPrompt.trim()) {
|
|
277
|
-
const tmp = writePromptToTempFile(agent.name, agent.systemPrompt);
|
|
294
|
+
const tmp = await writePromptToTempFile(agent.name, agent.systemPrompt);
|
|
278
295
|
tmpPromptDir = tmp.dir;
|
|
279
296
|
tmpPromptPath = tmp.filePath;
|
|
280
297
|
args.push("--append-system-prompt", tmpPromptPath);
|
|
@@ -284,7 +301,12 @@ async function runSingleAgent(
|
|
|
284
301
|
let wasAborted = false;
|
|
285
302
|
|
|
286
303
|
const exitCode = await new Promise<number>((resolve) => {
|
|
287
|
-
const
|
|
304
|
+
const invocation = getPiInvocation(args);
|
|
305
|
+
const proc = spawn(invocation.command, invocation.args, {
|
|
306
|
+
cwd: cwd ?? defaultCwd,
|
|
307
|
+
shell: false,
|
|
308
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
309
|
+
});
|
|
288
310
|
let buffer = "";
|
|
289
311
|
|
|
290
312
|
const processLine = (line: string) => {
|
|
@@ -646,7 +668,7 @@ export default function (pi: ExtensionAPI) {
|
|
|
646
668
|
};
|
|
647
669
|
},
|
|
648
670
|
|
|
649
|
-
renderCall(args, theme) {
|
|
671
|
+
renderCall(args, theme, _context) {
|
|
650
672
|
const scope: AgentScope = args.agentScope ?? "user";
|
|
651
673
|
if (args.chain && args.chain.length > 0) {
|
|
652
674
|
let text =
|
|
@@ -690,7 +712,7 @@ export default function (pi: ExtensionAPI) {
|
|
|
690
712
|
return new Text(text, 0, 0);
|
|
691
713
|
},
|
|
692
714
|
|
|
693
|
-
renderResult(result, { expanded }, theme) {
|
|
715
|
+
renderResult(result, { expanded }, theme, _context) {
|
|
694
716
|
const details = result.details as SubagentDetails | undefined;
|
|
695
717
|
if (!details || details.results.length === 0) {
|
|
696
718
|
const text = result.content[0];
|
|
@@ -16,7 +16,7 @@ const BRAILLE_FRAMES = ["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧",
|
|
|
16
16
|
function getBaseTitle(pi: ExtensionAPI): string {
|
|
17
17
|
const cwd = path.basename(process.cwd());
|
|
18
18
|
const session = pi.getSessionName();
|
|
19
|
-
return session ?
|
|
19
|
+
return session ? `D - ${session} - ${cwd}` : `D - ${cwd}`;
|
|
20
20
|
}
|
|
21
21
|
|
|
22
22
|
export default function (pi: ExtensionAPI) {
|
|
@@ -38,7 +38,7 @@ export default function (pi: ExtensionAPI) {
|
|
|
38
38
|
const frame = BRAILLE_FRAMES[frameIndex % BRAILLE_FRAMES.length];
|
|
39
39
|
const cwd = path.basename(process.cwd());
|
|
40
40
|
const session = pi.getSessionName();
|
|
41
|
-
const title = session ? `${frame}
|
|
41
|
+
const title = session ? `${frame} D - ${session} - ${cwd}` : `${frame} D - ${cwd}`;
|
|
42
42
|
ctx.ui.setTitle(title);
|
|
43
43
|
frameIndex++;
|
|
44
44
|
}, 80);
|
|
@@ -220,14 +220,14 @@ export default function (pi: ExtensionAPI) {
|
|
|
220
220
|
}
|
|
221
221
|
},
|
|
222
222
|
|
|
223
|
-
renderCall(args, theme) {
|
|
223
|
+
renderCall(args, theme, _context) {
|
|
224
224
|
let text = theme.fg("toolTitle", theme.bold("todo ")) + theme.fg("muted", args.action);
|
|
225
225
|
if (args.text) text += ` ${theme.fg("dim", `"${args.text}"`)}`;
|
|
226
226
|
if (args.id !== undefined) text += ` ${theme.fg("accent", `#${args.id}`)}`;
|
|
227
227
|
return new Text(text, 0, 0);
|
|
228
228
|
},
|
|
229
229
|
|
|
230
|
-
renderResult(result, { expanded }, theme) {
|
|
230
|
+
renderResult(result, { expanded }, theme, _context) {
|
|
231
231
|
const details = result.details as TodoDetails | undefined;
|
|
232
232
|
if (!details) {
|
|
233
233
|
const text = result.content[0];
|
|
@@ -21,10 +21,10 @@
|
|
|
21
21
|
*/
|
|
22
22
|
|
|
23
23
|
import type { TextContent } from "@draht/ai";
|
|
24
|
-
import { type ExtensionAPI, getAgentDir } from "@draht/coding-agent";
|
|
24
|
+
import { type ExtensionAPI, getAgentDir, withFileMutationQueue } from "@draht/coding-agent";
|
|
25
25
|
import { Type } from "@sinclair/typebox";
|
|
26
|
-
import {
|
|
27
|
-
import { access, readFile } from "fs/promises";
|
|
26
|
+
import { constants, readFileSync } from "fs";
|
|
27
|
+
import { access, appendFile, readFile } from "fs/promises";
|
|
28
28
|
import { join, resolve } from "path";
|
|
29
29
|
|
|
30
30
|
const LOG_FILE = join(getAgentDir(), "read-access.log");
|
|
@@ -44,14 +44,16 @@ function isBlockedPath(path: string): boolean {
|
|
|
44
44
|
return BLOCKED_PATTERNS.some((pattern) => pattern.test(path));
|
|
45
45
|
}
|
|
46
46
|
|
|
47
|
-
function logAccess(path: string, allowed: boolean, reason?: string) {
|
|
47
|
+
async function logAccess(path: string, allowed: boolean, reason?: string) {
|
|
48
48
|
const timestamp = new Date().toISOString();
|
|
49
49
|
const status = allowed ? "ALLOWED" : "BLOCKED";
|
|
50
50
|
const msg = reason ? ` (${reason})` : "";
|
|
51
51
|
const line = `[${timestamp}] ${status}: ${path}${msg}\n`;
|
|
52
52
|
|
|
53
53
|
try {
|
|
54
|
-
|
|
54
|
+
await withFileMutationQueue(LOG_FILE, async () => {
|
|
55
|
+
await appendFile(LOG_FILE, line);
|
|
56
|
+
});
|
|
55
57
|
} catch {
|
|
56
58
|
// Ignore logging errors
|
|
57
59
|
}
|
|
@@ -77,7 +79,7 @@ export default function (pi: ExtensionAPI) {
|
|
|
77
79
|
|
|
78
80
|
// Check if path is blocked
|
|
79
81
|
if (isBlockedPath(absolutePath)) {
|
|
80
|
-
logAccess(absolutePath, false, "matches blocked pattern");
|
|
82
|
+
await logAccess(absolutePath, false, "matches blocked pattern");
|
|
81
83
|
return {
|
|
82
84
|
content: [
|
|
83
85
|
{
|
|
@@ -90,7 +92,7 @@ export default function (pi: ExtensionAPI) {
|
|
|
90
92
|
}
|
|
91
93
|
|
|
92
94
|
// Log allowed access
|
|
93
|
-
logAccess(absolutePath, true);
|
|
95
|
+
await logAccess(absolutePath, true);
|
|
94
96
|
|
|
95
97
|
// Perform the actual read (simplified implementation)
|
|
96
98
|
try {
|
|
@@ -14,6 +14,7 @@
|
|
|
14
14
|
* built-in `grep` tool in src/core/tools/grep.ts for a more complete implementation.
|
|
15
15
|
*/
|
|
16
16
|
|
|
17
|
+
import { mkdtemp, writeFile } from "node:fs/promises";
|
|
17
18
|
import type { ExtensionAPI } from "@draht/coding-agent";
|
|
18
19
|
import {
|
|
19
20
|
DEFAULT_MAX_BYTES,
|
|
@@ -21,11 +22,11 @@ import {
|
|
|
21
22
|
formatSize,
|
|
22
23
|
type TruncationResult,
|
|
23
24
|
truncateHead,
|
|
25
|
+
withFileMutationQueue,
|
|
24
26
|
} from "@draht/coding-agent";
|
|
25
27
|
import { Text } from "@draht/tui";
|
|
26
28
|
import { Type } from "@sinclair/typebox";
|
|
27
29
|
import { execSync } from "child_process";
|
|
28
|
-
import { mkdtempSync, writeFileSync } from "fs";
|
|
29
30
|
import { tmpdir } from "os";
|
|
30
31
|
import { join } from "path";
|
|
31
32
|
|
|
@@ -108,9 +109,11 @@ export default function (pi: ExtensionAPI) {
|
|
|
108
109
|
|
|
109
110
|
if (truncation.truncated) {
|
|
110
111
|
// Save full output to a temp file so LLM can access it if needed
|
|
111
|
-
const tempDir =
|
|
112
|
+
const tempDir = await mkdtemp(join(tmpdir(), "pi-rg-"));
|
|
112
113
|
const tempFile = join(tempDir, "output.txt");
|
|
113
|
-
|
|
114
|
+
await withFileMutationQueue(tempFile, async () => {
|
|
115
|
+
await writeFile(tempFile, output, "utf8");
|
|
116
|
+
});
|
|
114
117
|
|
|
115
118
|
details.truncation = truncation;
|
|
116
119
|
details.fullOutputPath = tempFile;
|
|
@@ -132,7 +135,7 @@ export default function (pi: ExtensionAPI) {
|
|
|
132
135
|
},
|
|
133
136
|
|
|
134
137
|
// Custom rendering of the tool call (shown before/during execution)
|
|
135
|
-
renderCall(args, theme) {
|
|
138
|
+
renderCall(args, theme, _context) {
|
|
136
139
|
let text = theme.fg("toolTitle", theme.bold("rg "));
|
|
137
140
|
text += theme.fg("accent", `"${args.pattern}"`);
|
|
138
141
|
if (args.path) {
|
|
@@ -145,7 +148,7 @@ export default function (pi: ExtensionAPI) {
|
|
|
145
148
|
},
|
|
146
149
|
|
|
147
150
|
// Custom rendering of the tool result
|
|
148
|
-
renderResult(result, { expanded, isPartial }, theme) {
|
|
151
|
+
renderResult(result, { expanded, isPartial }, theme, _context) {
|
|
149
152
|
const details = result.details as RgDetails | undefined;
|
|
150
153
|
|
|
151
154
|
// Handle streaming/partial results
|