@draht/coding-agent 2026.3.6 → 2026.3.14
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 +88 -0
- package/README.md +6 -2
- package/bin/draht-tools.cjs +187 -32
- package/dist/cli/args.d.ts +6 -0
- package/dist/cli/args.d.ts.map +1 -1
- package/dist/cli/args.js +24 -0
- package/dist/cli/args.js.map +1 -1
- package/dist/cli/attach-mode.d.ts +13 -0
- package/dist/cli/attach-mode.d.ts.map +1 -0
- package/dist/cli/attach-mode.js +97 -0
- package/dist/cli/attach-mode.js.map +1 -0
- package/dist/cli/list-sessions.d.ts +8 -0
- package/dist/cli/list-sessions.d.ts.map +1 -0
- package/dist/cli/list-sessions.js +52 -0
- package/dist/cli/list-sessions.js.map +1 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +2 -2
- package/dist/config.js.map +1 -1
- package/dist/core/agent-session.d.ts +1 -0
- package/dist/core/agent-session.d.ts.map +1 -1
- package/dist/core/agent-session.js +50 -17
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/auth-storage.d.ts +2 -1
- package/dist/core/auth-storage.d.ts.map +1 -1
- package/dist/core/auth-storage.js +25 -1
- package/dist/core/auth-storage.js.map +1 -1
- package/dist/core/compaction/utils.d.ts +3 -0
- package/dist/core/compaction/utils.d.ts.map +1 -1
- package/dist/core/compaction/utils.js +16 -1
- package/dist/core/compaction/utils.js.map +1 -1
- package/dist/core/export-html/index.d.ts +5 -2
- package/dist/core/export-html/index.d.ts.map +1 -1
- package/dist/core/export-html/index.js +4 -3
- package/dist/core/export-html/index.js.map +1 -1
- package/dist/core/export-html/template.js +11 -14
- package/dist/core/export-html/tool-renderer.d.ts +5 -2
- package/dist/core/export-html/tool-renderer.d.ts.map +1 -1
- package/dist/core/export-html/tool-renderer.js +12 -5
- package/dist/core/export-html/tool-renderer.js.map +1 -1
- package/dist/core/extensions/index.d.ts +1 -1
- package/dist/core/extensions/index.d.ts.map +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 +6 -6
- package/dist/core/extensions/loader.js.map +1 -1
- package/dist/core/extensions/runner.d.ts +3 -2
- package/dist/core/extensions/runner.d.ts.map +1 -1
- package/dist/core/extensions/runner.js +32 -0
- package/dist/core/extensions/runner.js.map +1 -1
- package/dist/core/extensions/types.d.ts +21 -2
- package/dist/core/extensions/types.d.ts.map +1 -1
- package/dist/core/extensions/types.js.map +1 -1
- package/dist/core/model-resolver.d.ts.map +1 -1
- package/dist/core/model-resolver.js +2 -2
- package/dist/core/model-resolver.js.map +1 -1
- package/dist/core/package-manager.d.ts.map +1 -1
- package/dist/core/package-manager.js +2 -2
- package/dist/core/package-manager.js.map +1 -1
- package/dist/core/resource-loader.d.ts.map +1 -1
- package/dist/core/resource-loader.js +1 -1
- package/dist/core/resource-loader.js.map +1 -1
- package/dist/core/sdk.d.ts.map +1 -1
- package/dist/core/sdk.js +7 -0
- package/dist/core/sdk.js.map +1 -1
- package/dist/core/settings-manager.d.ts +4 -0
- package/dist/core/settings-manager.d.ts.map +1 -1
- package/dist/core/settings-manager.js +36 -2
- package/dist/core/settings-manager.js.map +1 -1
- package/dist/core/socket-server/discovery.d.ts +19 -0
- package/dist/core/socket-server/discovery.d.ts.map +1 -0
- package/dist/core/socket-server/discovery.js +91 -0
- package/dist/core/socket-server/discovery.js.map +1 -0
- package/dist/core/socket-server/index.d.ts +13 -0
- package/dist/core/socket-server/index.d.ts.map +1 -0
- package/dist/core/socket-server/index.js +11 -0
- package/dist/core/socket-server/index.js.map +1 -0
- package/dist/core/socket-server/session-integration.d.ts +17 -0
- package/dist/core/socket-server/session-integration.d.ts.map +1 -0
- package/dist/core/socket-server/session-integration.js +77 -0
- package/dist/core/socket-server/session-integration.js.map +1 -0
- package/dist/core/socket-server/socket-client.d.ts +65 -0
- package/dist/core/socket-server/socket-client.d.ts.map +1 -0
- package/dist/core/socket-server/socket-client.js +197 -0
- package/dist/core/socket-server/socket-client.js.map +1 -0
- package/dist/core/socket-server/socket-server.d.ts +60 -0
- package/dist/core/socket-server/socket-server.d.ts.map +1 -0
- package/dist/core/socket-server/socket-server.js +273 -0
- package/dist/core/socket-server/socket-server.js.map +1 -0
- package/dist/core/socket-server/types.d.ts +81 -0
- package/dist/core/socket-server/types.d.ts.map +1 -0
- package/dist/core/socket-server/types.js +8 -0
- package/dist/core/socket-server/types.js.map +1 -0
- package/dist/gsd/domain.d.ts +5 -1
- package/dist/gsd/domain.d.ts.map +1 -1
- package/dist/gsd/domain.js +71 -1
- package/dist/gsd/domain.js.map +1 -1
- package/dist/gsd/git.d.ts.map +1 -1
- package/dist/gsd/git.js +18 -0
- package/dist/gsd/git.js.map +1 -1
- package/dist/gsd/index.d.ts +1 -0
- package/dist/gsd/index.d.ts.map +1 -1
- package/dist/gsd/index.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/main.d.ts.map +1 -1
- package/dist/main.js +76 -11
- package/dist/main.js.map +1 -1
- package/dist/modes/interactive/components/extension-editor.d.ts.map +1 -1
- package/dist/modes/interactive/components/extension-editor.js +1 -0
- package/dist/modes/interactive/components/extension-editor.js.map +1 -1
- package/dist/modes/interactive/components/footer.d.ts.map +1 -1
- package/dist/modes/interactive/components/footer.js +8 -23
- package/dist/modes/interactive/components/footer.js.map +1 -1
- package/dist/modes/interactive/components/settings-selector.d.ts +2 -0
- package/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/settings-selector.js +10 -0
- package/dist/modes/interactive/components/settings-selector.js.map +1 -1
- package/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
- package/dist/modes/interactive/components/tool-execution.js +14 -4
- package/dist/modes/interactive/components/tool-execution.js.map +1 -1
- package/dist/modes/interactive/components/tree-selector.d.ts +21 -2
- package/dist/modes/interactive/components/tree-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/tree-selector.js +115 -9
- package/dist/modes/interactive/components/tree-selector.js.map +1 -1
- package/dist/modes/interactive/interactive-mode.d.ts +1 -0
- package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-mode.js +66 -5
- package/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/dist/modes/rpc/jsonl.d.ts +17 -0
- package/dist/modes/rpc/jsonl.d.ts.map +1 -0
- package/dist/modes/rpc/jsonl.js +49 -0
- package/dist/modes/rpc/jsonl.js.map +1 -0
- package/dist/modes/rpc/rpc-client.d.ts +1 -1
- package/dist/modes/rpc/rpc-client.d.ts.map +1 -1
- package/dist/modes/rpc/rpc-client.js +7 -11
- package/dist/modes/rpc/rpc-client.js.map +1 -1
- package/dist/modes/rpc/rpc-mode.d.ts.map +1 -1
- package/dist/modes/rpc/rpc-mode.js +9 -11
- package/dist/modes/rpc/rpc-mode.js.map +1 -1
- package/dist/prompts/commands/execute-phase.md +2 -2
- package/dist/prompts/commands/fix.md +2 -2
- package/dist/prompts/commands/plan-phase.md +5 -1
- package/dist/prompts/commands/quick.md +5 -1
- package/dist/utils/changelog.d.ts +12 -0
- package/dist/utils/changelog.d.ts.map +1 -1
- package/dist/utils/changelog.js +25 -14
- package/dist/utils/changelog.js.map +1 -1
- package/dist/utils/notify.d.ts +12 -0
- package/dist/utils/notify.d.ts.map +1 -0
- package/dist/utils/notify.js +41 -0
- package/dist/utils/notify.js.map +1 -0
- package/docs/compaction.md +2 -0
- package/docs/custom-provider.md +11 -7
- package/docs/extensions.md +55 -3
- package/docs/keybindings.md +9 -1
- package/docs/models.md +5 -1
- package/docs/rpc.md +40 -3
- package/docs/session.md +2 -2
- package/docs/settings.md +1 -0
- package/docs/terminal-setup.md +28 -3
- package/docs/tmux.md +61 -0
- package/docs/tree.md +9 -0
- package/examples/extensions/antigravity-image-gen.ts +5 -4
- package/examples/extensions/custom-provider-gitlab-duo/test.ts +2 -2
- package/examples/extensions/notify.ts +9 -2
- package/examples/extensions/overlay-qa-tests.ts +468 -1
- package/examples/extensions/preset.ts +2 -3
- package/examples/extensions/provider-payload.ts +14 -0
- package/examples/extensions/sandbox/index.ts +2 -3
- package/examples/extensions/tool-override.ts +2 -3
- package/examples/extensions/with-deps/index.ts +1 -5
- package/package.json +7 -5
- package/prompts/commands/execute-phase.md +2 -2
- package/prompts/commands/fix.md +2 -2
- package/prompts/commands/plan-phase.md +5 -1
- package/prompts/commands/quick.md +5 -1
package/docs/extensions.md
CHANGED
|
@@ -225,8 +225,9 @@ Run `npm install` in the extension directory, then imports from `node_modules/`
|
|
|
225
225
|
### Lifecycle Overview
|
|
226
226
|
|
|
227
227
|
```
|
|
228
|
-
pi starts
|
|
228
|
+
pi starts (CLI only)
|
|
229
229
|
│
|
|
230
|
+
├─► session_directory (CLI startup only, no ctx)
|
|
230
231
|
└─► session_start
|
|
231
232
|
│
|
|
232
233
|
▼
|
|
@@ -243,6 +244,7 @@ user sends prompt ────────────────────
|
|
|
243
244
|
│ │ │ │
|
|
244
245
|
│ ├─► turn_start │ │
|
|
245
246
|
│ ├─► context (can modify messages) │ │
|
|
247
|
+
│ ├─► before_provider_request (can inspect or replace payload)
|
|
246
248
|
│ │ │ │
|
|
247
249
|
│ │ LLM responds, may call tools: │ │
|
|
248
250
|
│ │ ├─► tool_call (can block) │ │
|
|
@@ -284,6 +286,26 @@ exit (Ctrl+C, Ctrl+D)
|
|
|
284
286
|
|
|
285
287
|
See [session.md](session.md) for session storage internals and the SessionManager API.
|
|
286
288
|
|
|
289
|
+
#### session_directory
|
|
290
|
+
|
|
291
|
+
Fired by the `pi` CLI during startup session resolution, before the initial session manager is created.
|
|
292
|
+
|
|
293
|
+
This event is:
|
|
294
|
+
- CLI-only. It is not emitted in SDK mode.
|
|
295
|
+
- Startup-only. It is not emitted for later interactive `/new` or `/resume` actions.
|
|
296
|
+
- Bypassed when `--session-dir` is provided.
|
|
297
|
+
- Special-cased to receive no `ctx` argument.
|
|
298
|
+
|
|
299
|
+
If multiple extensions return `sessionDir`, the last one wins.
|
|
300
|
+
|
|
301
|
+
```typescript
|
|
302
|
+
pi.on("session_directory", async (event) => {
|
|
303
|
+
return {
|
|
304
|
+
sessionDir: `/tmp/pi-sessions/${encodeURIComponent(event.cwd)}`,
|
|
305
|
+
};
|
|
306
|
+
});
|
|
307
|
+
```
|
|
308
|
+
|
|
287
309
|
#### session_start
|
|
288
310
|
|
|
289
311
|
Fired on initial session load.
|
|
@@ -489,6 +511,21 @@ pi.on("context", async (event, ctx) => {
|
|
|
489
511
|
});
|
|
490
512
|
```
|
|
491
513
|
|
|
514
|
+
#### before_provider_request
|
|
515
|
+
|
|
516
|
+
Fired after the provider-specific payload is built, right before the request is sent. Handlers run in extension load order. Returning `undefined` keeps the payload unchanged. Returning any other value replaces the payload for later handlers and for the actual request.
|
|
517
|
+
|
|
518
|
+
```typescript
|
|
519
|
+
pi.on("before_provider_request", (event, ctx) => {
|
|
520
|
+
console.log(JSON.stringify(event.payload, null, 2));
|
|
521
|
+
|
|
522
|
+
// Optional: replace payload
|
|
523
|
+
// return { ...event.payload, temperature: 0 };
|
|
524
|
+
});
|
|
525
|
+
```
|
|
526
|
+
|
|
527
|
+
This is mainly useful for debugging provider serialization and cache behavior.
|
|
528
|
+
|
|
492
529
|
### Model Events
|
|
493
530
|
|
|
494
531
|
#### model_select
|
|
@@ -658,7 +695,9 @@ Transforms chain across handlers. See [input-transform.ts](../examples/extension
|
|
|
658
695
|
|
|
659
696
|
## ExtensionContext
|
|
660
697
|
|
|
661
|
-
|
|
698
|
+
All handlers except `session_directory` receive `ctx: ExtensionContext`.
|
|
699
|
+
|
|
700
|
+
`session_directory` is a CLI startup hook and receives only the event.
|
|
662
701
|
|
|
663
702
|
### ctx.ui
|
|
664
703
|
|
|
@@ -1340,6 +1379,18 @@ pi.registerTool({
|
|
|
1340
1379
|
});
|
|
1341
1380
|
```
|
|
1342
1381
|
|
|
1382
|
+
**Signaling errors:** To mark a tool execution as failed (sets `isError: true` on the result and reports it to the LLM), throw an error from `execute`. Returning a value never sets the error flag regardless of what properties you include in the return object.
|
|
1383
|
+
|
|
1384
|
+
```typescript
|
|
1385
|
+
// Correct: throw to signal an error
|
|
1386
|
+
async execute(toolCallId, params) {
|
|
1387
|
+
if (!isValid(params.input)) {
|
|
1388
|
+
throw new Error(`Invalid input: ${params.input}`);
|
|
1389
|
+
}
|
|
1390
|
+
return { content: [{ type: "text", text: "OK" }], details: {} };
|
|
1391
|
+
}
|
|
1392
|
+
```
|
|
1393
|
+
|
|
1343
1394
|
**Important:** Use `StringEnum` from `@draht/ai` for string enums. `Type.Union`/`Type.Literal` doesn't work with Google's API.
|
|
1344
1395
|
|
|
1345
1396
|
### Overriding Built-in Tools
|
|
@@ -1880,7 +1931,7 @@ const highlighted = highlightCode(code, lang, theme);
|
|
|
1880
1931
|
|
|
1881
1932
|
- Extension errors are logged, agent continues
|
|
1882
1933
|
- `tool_call` errors block the tool (fail-safe)
|
|
1883
|
-
- Tool `execute` errors
|
|
1934
|
+
- Tool `execute` errors must be signaled by throwing; the thrown error is caught, reported to the LLM with `isError: true`, and execution continues
|
|
1884
1935
|
|
|
1885
1936
|
## Mode Behavior
|
|
1886
1937
|
|
|
@@ -1922,6 +1973,7 @@ All examples in [examples/extensions/](../examples/extensions/).
|
|
|
1922
1973
|
| `dirty-repo-guard.ts` | Warn on dirty git repo | `on("session_before_*")`, `exec` |
|
|
1923
1974
|
| `input-transform.ts` | Transform user input | `on("input")` |
|
|
1924
1975
|
| `model-status.ts` | React to model changes | `on("model_select")`, `setStatus` |
|
|
1976
|
+
| `provider-payload.ts` | Inspect or patch provider payloads | `on("before_provider_request")` |
|
|
1925
1977
|
| `system-prompt-header.ts` | Display system prompt info | `on("agent_start")`, `getSystemPrompt` |
|
|
1926
1978
|
| `claude-rules.ts` | Load rules from files | `on("session_start")`, `on("before_agent_start")` |
|
|
1927
1979
|
| `file-trigger.ts` | File watcher triggers messages | `sendMessage` |
|
package/docs/keybindings.md
CHANGED
|
@@ -7,11 +7,12 @@ All keyboard shortcuts can be customized via `~/.pi/agent/keybindings.json`. Eac
|
|
|
7
7
|
`modifier+key` where modifiers are `ctrl`, `shift`, `alt` (combinable) and keys are:
|
|
8
8
|
|
|
9
9
|
- **Letters:** `a-z`
|
|
10
|
+
- **Digits:** `0-9`
|
|
10
11
|
- **Special:** `escape`, `esc`, `enter`, `return`, `tab`, `space`, `backspace`, `delete`, `insert`, `clear`, `home`, `end`, `pageUp`, `pageDown`, `up`, `down`, `left`, `right`
|
|
11
12
|
- **Function:** `f1`-`f12`
|
|
12
13
|
- **Symbols:** `` ` ``, `-`, `=`, `[`, `]`, `\`, `;`, `'`, `,`, `.`, `/`, `!`, `@`, `#`, `$`, `%`, `^`, `&`, `*`, `(`, `)`, `_`, `+`, `|`, `~`, `{`, `}`, `:`, `<`, `>`, `?`
|
|
13
14
|
|
|
14
|
-
Modifier combinations: `ctrl+shift+x`, `alt+ctrl+x`, `ctrl+shift+alt+x`, etc.
|
|
15
|
+
Modifier combinations: `ctrl+shift+x`, `alt+ctrl+x`, `ctrl+shift+alt+x`, `ctrl+1`, etc.
|
|
15
16
|
|
|
16
17
|
## All Actions
|
|
17
18
|
|
|
@@ -119,6 +120,13 @@ Modifier combinations: `ctrl+shift+x`, `alt+ctrl+x`, `ctrl+shift+alt+x`, etc.
|
|
|
119
120
|
| `selectConfirm` | `enter` | Confirm selection |
|
|
120
121
|
| `selectCancel` | `escape`, `ctrl+c` | Cancel selection |
|
|
121
122
|
|
|
123
|
+
### Tree Navigation
|
|
124
|
+
|
|
125
|
+
| Action | Default | Description |
|
|
126
|
+
|--------|---------|-------------|
|
|
127
|
+
| `treeFoldOrUp` | `ctrl+left`, `alt+left` | Fold current branch segment, or jump to the previous segment start |
|
|
128
|
+
| `treeUnfoldOrDown` | `ctrl+right`, `alt+right` | Unfold current branch segment, or jump to the next segment start or branch end |
|
|
129
|
+
|
|
122
130
|
### Session Picker
|
|
123
131
|
|
|
124
132
|
| Action | Default | Description |
|
package/docs/models.md
CHANGED
|
@@ -129,7 +129,7 @@ The `apiKey` and `headers` fields support three formats:
|
|
|
129
129
|
| Field | Required | Default | Description |
|
|
130
130
|
|-------|----------|---------|-------------|
|
|
131
131
|
| `id` | Yes | — | Model identifier (passed to the API) |
|
|
132
|
-
| `name` | No | `id` |
|
|
132
|
+
| `name` | No | `id` | Human-readable model label. Used for matching (`--model` patterns) and shown in model details/status text. |
|
|
133
133
|
| `api` | No | provider's `api` | Override provider's API for this model |
|
|
134
134
|
| `reasoning` | No | `false` | Supports extended thinking |
|
|
135
135
|
| `input` | No | `["text"]` | Input types: `["text"]` or `["text", "image"]` |
|
|
@@ -137,6 +137,10 @@ The `apiKey` and `headers` fields support three formats:
|
|
|
137
137
|
| `maxTokens` | No | `16384` | Maximum output tokens |
|
|
138
138
|
| `cost` | No | all zeros | `{"input": 0, "output": 0, "cacheRead": 0, "cacheWrite": 0}` (per million tokens) |
|
|
139
139
|
|
|
140
|
+
Current behavior:
|
|
141
|
+
- `/model` and `--list-models` list entries by model `id`.
|
|
142
|
+
- The configured `name` is used for model matching and detail/status text.
|
|
143
|
+
|
|
140
144
|
## Overriding Built-in Providers
|
|
141
145
|
|
|
142
146
|
Route a built-in provider through a proxy without redefining models:
|
package/docs/rpc.md
CHANGED
|
@@ -24,6 +24,17 @@ Common options:
|
|
|
24
24
|
|
|
25
25
|
All commands support an optional `id` field for request/response correlation. If provided, the corresponding response will include the same `id`.
|
|
26
26
|
|
|
27
|
+
### Framing
|
|
28
|
+
|
|
29
|
+
RPC mode uses strict JSONL semantics with LF (`\n`) as the only record delimiter.
|
|
30
|
+
|
|
31
|
+
This matters for clients:
|
|
32
|
+
- Split records on `\n` only
|
|
33
|
+
- Accept optional `\r\n` input by stripping a trailing `\r`
|
|
34
|
+
- Do not use generic line readers that treat Unicode separators as newlines
|
|
35
|
+
|
|
36
|
+
In particular, Node `readline` is not protocol-compliant for RPC mode because it also splits on `U+2028` and `U+2029`, which are valid inside JSON strings.
|
|
37
|
+
|
|
27
38
|
## Commands
|
|
28
39
|
|
|
29
40
|
### Prompting
|
|
@@ -1292,13 +1303,39 @@ For a complete example of handling the extension UI protocol, see [`examples/rpc
|
|
|
1292
1303
|
|
|
1293
1304
|
```javascript
|
|
1294
1305
|
const { spawn } = require("child_process");
|
|
1295
|
-
const
|
|
1306
|
+
const { StringDecoder } = require("string_decoder");
|
|
1296
1307
|
|
|
1297
1308
|
const agent = spawn("pi", ["--mode", "rpc", "--no-session"]);
|
|
1298
1309
|
|
|
1299
|
-
|
|
1310
|
+
function attachJsonlReader(stream, onLine) {
|
|
1311
|
+
const decoder = new StringDecoder("utf8");
|
|
1312
|
+
let buffer = "";
|
|
1313
|
+
|
|
1314
|
+
stream.on("data", (chunk) => {
|
|
1315
|
+
buffer += typeof chunk === "string" ? chunk : decoder.write(chunk);
|
|
1316
|
+
|
|
1317
|
+
while (true) {
|
|
1318
|
+
const newlineIndex = buffer.indexOf("\n");
|
|
1319
|
+
if (newlineIndex === -1) break;
|
|
1320
|
+
|
|
1321
|
+
let line = buffer.slice(0, newlineIndex);
|
|
1322
|
+
buffer = buffer.slice(newlineIndex + 1);
|
|
1323
|
+
if (line.endsWith("\r")) line = line.slice(0, -1);
|
|
1324
|
+
onLine(line);
|
|
1325
|
+
}
|
|
1326
|
+
});
|
|
1327
|
+
|
|
1328
|
+
stream.on("end", () => {
|
|
1329
|
+
buffer += decoder.end();
|
|
1330
|
+
if (buffer.length > 0) {
|
|
1331
|
+
onLine(buffer.endsWith("\r") ? buffer.slice(0, -1) : buffer);
|
|
1332
|
+
}
|
|
1333
|
+
});
|
|
1334
|
+
}
|
|
1335
|
+
|
|
1336
|
+
attachJsonlReader(agent.stdout, (line) => {
|
|
1300
1337
|
const event = JSON.parse(line);
|
|
1301
|
-
|
|
1338
|
+
|
|
1302
1339
|
if (event.type === "message_update") {
|
|
1303
1340
|
const { assistantMessageEvent } = event;
|
|
1304
1341
|
if (assistantMessageEvent.type === "text_delta") {
|
package/docs/session.md
CHANGED
|
@@ -5,14 +5,14 @@ Sessions are stored as JSONL (JSON Lines) files. Each line is a JSON object with
|
|
|
5
5
|
## File Location
|
|
6
6
|
|
|
7
7
|
```
|
|
8
|
-
~/.
|
|
8
|
+
~/.draht/agent/sessions/--<path>--/<timestamp>_<uuid>.jsonl
|
|
9
9
|
```
|
|
10
10
|
|
|
11
11
|
Where `<path>` is the working directory with `/` replaced by `-`.
|
|
12
12
|
|
|
13
13
|
## Deleting Sessions
|
|
14
14
|
|
|
15
|
-
Sessions can be removed by deleting their `.jsonl` files under `~/.
|
|
15
|
+
Sessions can be removed by deleting their `.jsonl` files under `~/.draht/agent/sessions/`.
|
|
16
16
|
|
|
17
17
|
Pi also supports deleting sessions interactively from `/resume` (select a session and press `Ctrl+D`, then confirm). When available, pi uses the `trash` CLI to avoid permanent deletion.
|
|
18
18
|
|
package/docs/settings.md
CHANGED
|
@@ -42,6 +42,7 @@ Edit directly or use `/settings` for common options.
|
|
|
42
42
|
| `quietStartup` | boolean | `false` | Hide startup header |
|
|
43
43
|
| `collapseChangelog` | boolean | `false` | Show condensed changelog after updates |
|
|
44
44
|
| `doubleEscapeAction` | string | `"tree"` | Action for double-escape: `"tree"`, `"fork"`, or `"none"` |
|
|
45
|
+
| `treeFilterMode` | string | `"default"` | Default filter for `/tree`: `"default"`, `"no-tools"`, `"user-only"`, `"labeled-only"`, `"all"` |
|
|
45
46
|
| `editorPaddingX` | number | `0` | Horizontal padding for input editor (0-3) |
|
|
46
47
|
| `autocompleteMaxVisible` | number | `5` | Max visible items in autocomplete dropdown (3-20) |
|
|
47
48
|
| `showHardwareCursor` | boolean | `false` | Show terminal cursor |
|
package/docs/terminal-setup.md
CHANGED
|
@@ -8,13 +8,30 @@ Work out of the box.
|
|
|
8
8
|
|
|
9
9
|
## Ghostty
|
|
10
10
|
|
|
11
|
-
Add to your Ghostty config (`~/.config/ghostty/config`):
|
|
11
|
+
Add to your Ghostty config (`~/Library/Application Support/com.mitchellh.ghostty/config` on macOS, `~/.config/ghostty/config` on Linux):
|
|
12
12
|
|
|
13
13
|
```
|
|
14
14
|
keybind = alt+backspace=text:\x1b\x7f
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
Older Claude Code versions may have added this Ghostty mapping:
|
|
18
|
+
|
|
19
|
+
```
|
|
15
20
|
keybind = shift+enter=text:\n
|
|
16
21
|
```
|
|
17
22
|
|
|
23
|
+
That mapping sends a raw linefeed byte. Inside pi, that is indistinguishable from `Ctrl+J`, so tmux and pi no longer see a real `shift+enter` key event.
|
|
24
|
+
|
|
25
|
+
If Claude Code 2.x or newer is the only reason you added that mapping, you can remove it, unless you want to use Claude Code in tmux, where it still requires that Ghostty mapping.
|
|
26
|
+
|
|
27
|
+
If you want `Shift+Enter` to keep working in tmux via that remap, add `ctrl+j` to your pi `newLine` keybinding in `~/.pi/agent/keybindings.json`:
|
|
28
|
+
|
|
29
|
+
```json
|
|
30
|
+
{
|
|
31
|
+
"newLine": ["shift+enter", "ctrl+j"]
|
|
32
|
+
}
|
|
33
|
+
```
|
|
34
|
+
|
|
18
35
|
## WezTerm
|
|
19
36
|
|
|
20
37
|
Create `~/.wezterm.lua`:
|
|
@@ -46,7 +63,7 @@ Add to `keybindings.json` to enable `Shift+Enter` for multi-line input:
|
|
|
46
63
|
|
|
47
64
|
## Windows Terminal
|
|
48
65
|
|
|
49
|
-
Add to `settings.json` (Ctrl+Shift+, or Settings → Open JSON file):
|
|
66
|
+
Add to `settings.json` (Ctrl+Shift+, or Settings → Open JSON file) to forward the modified Enter keys pi uses:
|
|
50
67
|
|
|
51
68
|
```json
|
|
52
69
|
{
|
|
@@ -54,12 +71,20 @@ Add to `settings.json` (Ctrl+Shift+, or Settings → Open JSON file):
|
|
|
54
71
|
{
|
|
55
72
|
"command": { "action": "sendInput", "input": "\u001b[13;2u" },
|
|
56
73
|
"keys": "shift+enter"
|
|
74
|
+
},
|
|
75
|
+
{
|
|
76
|
+
"command": { "action": "sendInput", "input": "\u001b[13;3u" },
|
|
77
|
+
"keys": "alt+enter"
|
|
57
78
|
}
|
|
58
79
|
]
|
|
59
80
|
}
|
|
60
81
|
```
|
|
61
82
|
|
|
62
|
-
|
|
83
|
+
- `Shift+Enter` inserts a new line.
|
|
84
|
+
- Windows Terminal binds `Alt+Enter` to fullscreen by default. That prevents pi from receiving `Alt+Enter` for follow-up queueing.
|
|
85
|
+
- Remapping `Alt+Enter` to `sendInput` forwards the real key chord to pi instead.
|
|
86
|
+
|
|
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.
|
|
63
88
|
|
|
64
89
|
## IntelliJ IDEA (Integrated Terminal)
|
|
65
90
|
|
package/docs/tmux.md
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
# tmux Setup
|
|
2
|
+
|
|
3
|
+
Pi works inside tmux, but tmux strips modifier information from certain keys by default. Without configuration, `Shift+Enter` and `Ctrl+Enter` are usually indistinguishable from plain `Enter`.
|
|
4
|
+
|
|
5
|
+
## Recommended Configuration
|
|
6
|
+
|
|
7
|
+
Add to `~/.tmux.conf`:
|
|
8
|
+
|
|
9
|
+
```tmux
|
|
10
|
+
set -g extended-keys on
|
|
11
|
+
set -g extended-keys-format csi-u
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
Then restart tmux fully:
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
tmux kill-server
|
|
18
|
+
tmux
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
Pi requests extended key reporting automatically when Kitty keyboard protocol is not available. With `extended-keys-format csi-u`, tmux forwards modified keys in CSI-u format, which is the most reliable configuration.
|
|
22
|
+
|
|
23
|
+
## Why `csi-u` Is Recommended
|
|
24
|
+
|
|
25
|
+
With only:
|
|
26
|
+
|
|
27
|
+
```tmux
|
|
28
|
+
set -g extended-keys on
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
tmux defaults to `extended-keys-format xterm`. When an application requests extended key reporting, modified keys are forwarded in xterm `modifyOtherKeys` format such as:
|
|
32
|
+
|
|
33
|
+
- `Ctrl+C` → `\x1b[27;5;99~`
|
|
34
|
+
- `Ctrl+D` → `\x1b[27;5;100~`
|
|
35
|
+
- `Ctrl+Enter` → `\x1b[27;5;13~`
|
|
36
|
+
|
|
37
|
+
With `extended-keys-format csi-u`, the same keys are forwarded as:
|
|
38
|
+
|
|
39
|
+
- `Ctrl+C` → `\x1b[99;5u`
|
|
40
|
+
- `Ctrl+D` → `\x1b[100;5u`
|
|
41
|
+
- `Ctrl+Enter` → `\x1b[13;5u`
|
|
42
|
+
|
|
43
|
+
Pi supports both formats, but `csi-u` is the recommended tmux setup.
|
|
44
|
+
|
|
45
|
+
## What This Fixes
|
|
46
|
+
|
|
47
|
+
Without tmux extended keys, modified Enter keys collapse to legacy sequences:
|
|
48
|
+
|
|
49
|
+
| Key | Without extkeys | With `csi-u` |
|
|
50
|
+
|-----|-----------------|--------------|
|
|
51
|
+
| Enter | `\r` | `\r` |
|
|
52
|
+
| Shift+Enter | `\r` | `\x1b[13;2u` |
|
|
53
|
+
| Ctrl+Enter | `\r` | `\x1b[13;5u` |
|
|
54
|
+
| Alt/Option+Enter | `\x1b\r` | `\x1b[13;3u` |
|
|
55
|
+
|
|
56
|
+
This affects the default keybindings (`Enter` to submit, `Shift+Enter` for newline) and any custom keybindings using modified Enter.
|
|
57
|
+
|
|
58
|
+
## Requirements
|
|
59
|
+
|
|
60
|
+
- tmux 3.2 or later (run `tmux -V` to check)
|
|
61
|
+
- A terminal emulator that supports extended keys (Ghostty, Kitty, iTerm2, WezTerm, Windows Terminal)
|
package/docs/tree.md
CHANGED
|
@@ -33,16 +33,25 @@ Sessions are stored as trees where each entry has an `id` and `parentId`. The "l
|
|
|
33
33
|
| Key | Action |
|
|
34
34
|
|-----|--------|
|
|
35
35
|
| ↑/↓ | Navigate (depth-first order) |
|
|
36
|
+
| ←/→ | Page up/down |
|
|
37
|
+
| Ctrl+←/Ctrl+→ or Alt+←/Alt+→ | Fold/unfold and jump between branch segments |
|
|
36
38
|
| Enter | Select node |
|
|
37
39
|
| Escape/Ctrl+C | Cancel |
|
|
38
40
|
| Ctrl+U | Toggle: user messages only |
|
|
39
41
|
| Ctrl+O | Toggle: show all (including custom/label entries) |
|
|
40
42
|
|
|
43
|
+
`Ctrl+←` or `Alt+←` folds the current node if it is foldable. Foldable nodes are roots and branch segment starts that have visible children. If the current node is not foldable, or is already folded, the selection jumps up to the previous visible branch segment start.
|
|
44
|
+
|
|
45
|
+
`Ctrl+→` or `Alt+→` unfolds the current node if it is folded. Otherwise, the selection jumps down to the next visible branch segment start, or to the branch end when there is no further branch point.
|
|
46
|
+
|
|
41
47
|
### Display
|
|
42
48
|
|
|
43
49
|
- Height: half terminal height
|
|
44
50
|
- Current leaf marked with `← active`
|
|
45
51
|
- Labels shown inline: `[label-name]`
|
|
52
|
+
- Foldable branch starts show `⊟` in the connector. Folded branches show `⊞`
|
|
53
|
+
- Active path marker `•` appears after the fold indicator when applicable
|
|
54
|
+
- Search and filter changes reset all folds
|
|
46
55
|
- Default filter hides `label` and `custom` entries (shown in Ctrl+O mode)
|
|
47
56
|
- Children sorted by timestamp (oldest first)
|
|
48
57
|
|
|
@@ -28,10 +28,9 @@
|
|
|
28
28
|
import { randomUUID } from "node:crypto";
|
|
29
29
|
import { existsSync, readFileSync } from "node:fs";
|
|
30
30
|
import { mkdir, writeFile } from "node:fs/promises";
|
|
31
|
-
import { homedir } from "node:os";
|
|
32
31
|
import { join } from "node:path";
|
|
33
32
|
import { StringEnum } from "@draht/ai";
|
|
34
|
-
import type
|
|
33
|
+
import { type ExtensionAPI, getAgentDir } from "@draht/coding-agent";
|
|
35
34
|
import { type Static, Type } from "@sinclair/typebox";
|
|
36
35
|
|
|
37
36
|
const PROVIDER = "google-antigravity";
|
|
@@ -184,7 +183,8 @@ function readConfigFile(path: string): ExtensionConfig {
|
|
|
184
183
|
}
|
|
185
184
|
|
|
186
185
|
function loadConfig(cwd: string): ExtensionConfig {
|
|
187
|
-
const
|
|
186
|
+
const globalPath = join(getAgentDir(), "extensions", "antigravity-image-gen.json");
|
|
187
|
+
const globalConfig = readConfigFile(globalPath);
|
|
188
188
|
const projectConfig = readConfigFile(join(cwd, ".pi", "extensions", "antigravity-image-gen.json"));
|
|
189
189
|
return { ...globalConfig, ...projectConfig };
|
|
190
190
|
}
|
|
@@ -204,7 +204,8 @@ function resolveSaveConfig(params: ToolParams, cwd: string): SaveConfig {
|
|
|
204
204
|
}
|
|
205
205
|
|
|
206
206
|
if (mode === "global") {
|
|
207
|
-
|
|
207
|
+
const outputDir = join(getAgentDir(), "generated-images");
|
|
208
|
+
return { mode, outputDir };
|
|
208
209
|
}
|
|
209
210
|
|
|
210
211
|
if (mode === "custom") {
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
|
|
11
11
|
import { type Api, type Context, type Model, registerApiProvider, streamSimple } from "@draht/ai";
|
|
12
12
|
import { readFileSync } from "fs";
|
|
13
|
-
import {
|
|
13
|
+
import { getAgentDir } from "packages/coding-agent/src/config.js";
|
|
14
14
|
import { join } from "path";
|
|
15
15
|
import { MODELS, streamGitLabDuo } from "./index.js";
|
|
16
16
|
|
|
@@ -28,7 +28,7 @@ async function main() {
|
|
|
28
28
|
}
|
|
29
29
|
|
|
30
30
|
// Read auth
|
|
31
|
-
const authPath = join(
|
|
31
|
+
const authPath = join(getAgentDir(), "extensions", "auth.json");
|
|
32
32
|
const authData = JSON.parse(readFileSync(authPath, "utf-8"));
|
|
33
33
|
const gitlabCred = authData["gitlab-duo"];
|
|
34
34
|
if (!gitlabCred?.access) {
|
|
@@ -3,12 +3,14 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Sends a native terminal notification when Pi agent is done and waiting for input.
|
|
5
5
|
* Supports multiple terminal protocols:
|
|
6
|
+
* - cmux: uses `cmux notify` CLI
|
|
6
7
|
* - OSC 777: Ghostty, iTerm2, WezTerm, rxvt-unicode
|
|
7
8
|
* - OSC 99: Kitty
|
|
8
9
|
* - Windows toast: Windows Terminal (WSL)
|
|
9
10
|
*/
|
|
10
11
|
|
|
11
12
|
import type { ExtensionAPI } from "@draht/coding-agent";
|
|
13
|
+
import { execFile } from "child_process";
|
|
12
14
|
|
|
13
15
|
function windowsToastScript(title: string, body: string): string {
|
|
14
16
|
const type = "Windows.UI.Notifications";
|
|
@@ -33,13 +35,18 @@ function notifyOSC99(title: string, body: string): void {
|
|
|
33
35
|
process.stdout.write(`\x1b]99;i=1:p=body;${body}\x1b\\`);
|
|
34
36
|
}
|
|
35
37
|
|
|
38
|
+
function notifyCmux(title: string, body: string): void {
|
|
39
|
+
execFile("cmux", ["notify", "--title", title, "--body", body]);
|
|
40
|
+
}
|
|
41
|
+
|
|
36
42
|
function notifyWindows(title: string, body: string): void {
|
|
37
|
-
const { execFile } = require("child_process");
|
|
38
43
|
execFile("powershell.exe", ["-NoProfile", "-Command", windowsToastScript(title, body)]);
|
|
39
44
|
}
|
|
40
45
|
|
|
41
46
|
function notify(title: string, body: string): void {
|
|
42
|
-
if (process.env.
|
|
47
|
+
if (process.env.CMUX_BUNDLE_ID) {
|
|
48
|
+
notifyCmux(title, body);
|
|
49
|
+
} else if (process.env.WT_SESSION) {
|
|
43
50
|
notifyWindows(title, body);
|
|
44
51
|
} else if (process.env.KITTY_WINDOW_ID) {
|
|
45
52
|
notifyOSC99(title, body);
|