@oh-my-pi/pi-coding-agent 10.6.2 → 11.0.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 +44 -0
- package/README.md +80 -79
- package/docs/compaction.md +182 -149
- package/docs/config-usage.md +141 -78
- package/docs/custom-tools.md +45 -16
- package/docs/extension-loading.md +56 -954
- package/docs/extensions.md +192 -51
- package/docs/hooks.md +109 -70
- package/docs/python-repl.md +52 -19
- package/docs/rpc.md +43 -19
- package/docs/sdk.md +270 -211
- package/docs/session-tree-plan.md +60 -417
- package/docs/session.md +104 -39
- package/docs/skills.md +59 -95
- package/docs/theme.md +139 -110
- package/docs/tree.md +42 -33
- package/docs/tui.md +226 -80
- package/package.json +8 -9
- package/src/capability/index.ts +3 -4
- package/src/cli/args.ts +4 -4
- package/src/cli/grep-cli.ts +1 -1
- package/src/commit/agentic/index.ts +4 -3
- package/src/commit/git/index.ts +2 -3
- package/src/commit/map-reduce/index.ts +2 -1
- package/src/config/prompt-templates.ts +2 -0
- package/src/config/settings-schema.ts +30 -7
- package/src/config/settings.ts +0 -14
- package/src/config.ts +2 -2
- package/src/discovery/agents.ts +36 -0
- package/src/discovery/index.ts +1 -0
- package/src/exa/mcp-client.ts +3 -3
- package/src/ipy/executor.ts +5 -7
- package/src/ipy/gateway-coordinator.ts +1 -1
- package/src/ipy/kernel.ts +20 -15
- package/src/ipy/prelude.py +1 -1
- package/src/ipy/runtime.ts +7 -6
- package/src/lsp/lspmux.ts +3 -3
- package/src/main.ts +6 -8
- package/src/mcp/tool-bridge.ts +19 -9
- package/src/modes/components/assistant-message.ts +2 -2
- package/src/modes/components/hook-editor.ts +4 -4
- package/src/modes/components/settings-defs.ts +37 -2
- package/src/modes/components/tool-execution.ts +7 -7
- package/src/modes/controllers/command-controller.ts +2 -2
- package/src/modes/controllers/event-controller.ts +4 -7
- package/src/modes/controllers/input-controller.ts +4 -4
- package/src/modes/controllers/selector-controller.ts +1 -0
- package/src/modes/interactive-mode.ts +3 -5
- package/src/modes/rpc/rpc-mode.ts +8 -9
- package/src/patch/index.ts +6 -6
- package/src/prompts/agents/explore.md +2 -2
- package/src/prompts/agents/frontmatter.md +5 -5
- package/src/prompts/agents/plan.md +3 -2
- package/src/prompts/agents/reviewer.md +1 -1
- package/src/prompts/system/system-prompt.md +1 -3
- package/src/sdk.ts +13 -9
- package/src/session/agent-session.ts +6 -4
- package/src/session/compaction/compaction.ts +3 -3
- package/src/session/session-manager.ts +8 -9
- package/src/ssh/connection-manager.ts +4 -4
- package/src/system-prompt.ts +2 -6
- package/src/task/agents.ts +1 -1
- package/src/task/executor.ts +31 -8
- package/src/task/index.ts +14 -35
- package/src/task/omp-command.ts +3 -1
- package/src/task/output-manager.ts +20 -6
- package/src/task/parallel.ts +3 -3
- package/src/task/render.ts +16 -2
- package/src/task/types.ts +13 -20
- package/src/task/worktree.ts +3 -3
- package/src/tools/ask.ts +3 -8
- package/src/tools/fetch.ts +2 -2
- package/src/tools/gemini-image.ts +5 -6
- package/src/tools/grep.ts +5 -5
- package/src/tools/index.ts +12 -5
- package/src/tools/read.ts +1 -1
- package/src/tools/todo-write.ts +2 -3
- package/src/utils/frontmatter.ts +1 -1
- package/src/utils/image-resize.ts +1 -1
- package/src/utils/timings.ts +3 -2
- package/src/web/scrapers/github.ts +2 -2
- package/src/web/scrapers/utils.ts +2 -3
- package/src/web/scrapers/youtube.ts +2 -3
- package/src/web/search/auth.ts +5 -6
- package/src/web/search/providers/anthropic.ts +3 -2
- package/src/utils/terminal-notify.ts +0 -37
package/docs/hooks.md
CHANGED
|
@@ -24,10 +24,10 @@ See [examples/hooks/](../examples/hooks/) for working implementations, including
|
|
|
24
24
|
|
|
25
25
|
## Quick Start
|
|
26
26
|
|
|
27
|
-
Create `~/.omp/agent/hooks/my-hook.ts
|
|
27
|
+
Create `~/.omp/agent/hooks/pre/my-hook.ts` (or project-local `.omp/hooks/pre/`):
|
|
28
28
|
|
|
29
29
|
```typescript
|
|
30
|
-
import type { HookAPI } from "@oh-my-pi/pi-coding-agent";
|
|
30
|
+
import type { HookAPI } from "@oh-my-pi/pi-coding-agent/hooks";
|
|
31
31
|
|
|
32
32
|
export default function (pi: HookAPI) {
|
|
33
33
|
pi.on("session_start", async (_event, ctx) => {
|
|
@@ -51,29 +51,30 @@ omp --hook ./my-hook.ts
|
|
|
51
51
|
|
|
52
52
|
## Hook Locations
|
|
53
53
|
|
|
54
|
-
Hooks are auto-discovered from
|
|
54
|
+
Hooks are auto-discovered from config directories under `hooks/`:
|
|
55
55
|
|
|
56
|
-
|
|
57
|
-
| ------------------------- | --------------------- |
|
|
58
|
-
| `~/.omp/agent/hooks/*.ts` | Global (all projects) |
|
|
59
|
-
| `.omp/hooks/*.ts` | Project-local |
|
|
56
|
+
Native (`.omp`, `.pi`) and Claude (`.claude`) use subdirectory structure:
|
|
60
57
|
|
|
61
|
-
|
|
58
|
+
- User-level:
|
|
59
|
+
- Native: `~/.omp/agent/hooks/{pre,post}/*.ts` (or `~/.pi/agent`)
|
|
60
|
+
- Claude: `~/.claude/hooks/{pre,post}/*.ts`
|
|
61
|
+
- Project-level: `.omp/hooks/{pre,post}/*.ts` (or `.pi`, `.claude`)
|
|
62
62
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
63
|
+
Codex (`.codex`) uses flat structure with filename prefixes (`pre-*.ts`, `post-*.ts`):
|
|
64
|
+
|
|
65
|
+
- User-level: `~/.codex/hooks/*.ts`
|
|
66
|
+
- Project-level: `.codex/hooks/*.ts`
|
|
67
|
+
|
|
68
|
+
Hooks can also be loaded from plugin manifests or explicitly via `--hook`.
|
|
68
69
|
|
|
69
70
|
## Available Imports
|
|
70
71
|
|
|
71
|
-
| Package | Purpose
|
|
72
|
-
| --------------------------------- |
|
|
73
|
-
| `@oh-my-pi/pi-coding-agent/hooks` | Hook types (`HookAPI`, `HookContext`, events)
|
|
74
|
-
| `@oh-my-pi/pi-coding-agent` |
|
|
75
|
-
| `@oh-my-pi/pi-ai` | AI utilities
|
|
76
|
-
| `@oh-my-pi/pi-tui` | TUI components
|
|
72
|
+
| Package | Purpose |
|
|
73
|
+
| --------------------------------- | ---------------------------------------------------- |
|
|
74
|
+
| `@oh-my-pi/pi-coding-agent/hooks` | Hook types (`HookAPI`, `HookContext`, events) |
|
|
75
|
+
| `@oh-my-pi/pi-coding-agent` | Components (`BorderedLoader`), utilities, type re-exports |
|
|
76
|
+
| `@oh-my-pi/pi-ai` | AI utilities (`complete`, message types) |
|
|
77
|
+
| `@oh-my-pi/pi-tui` | TUI components (`CancellableLoader`, etc.) |
|
|
77
78
|
|
|
78
79
|
Node.js built-ins (`node:fs`, `node:path`, etc.) are also available.
|
|
79
80
|
|
|
@@ -82,7 +83,7 @@ Node.js built-ins (`node:fs`, `node:path`, etc.) are also available.
|
|
|
82
83
|
A hook exports a default function that receives `HookAPI`:
|
|
83
84
|
|
|
84
85
|
```typescript
|
|
85
|
-
import type { HookAPI } from "@oh-my-pi/pi-coding-agent";
|
|
86
|
+
import type { HookAPI } from "@oh-my-pi/pi-coding-agent/hooks";
|
|
86
87
|
|
|
87
88
|
export default function (pi: HookAPI) {
|
|
88
89
|
// Subscribe to events
|
|
@@ -92,7 +93,7 @@ export default function (pi: HookAPI) {
|
|
|
92
93
|
}
|
|
93
94
|
```
|
|
94
95
|
|
|
95
|
-
Hooks are loaded via
|
|
96
|
+
Hooks are loaded via native Bun import, so TypeScript works without compilation.
|
|
96
97
|
|
|
97
98
|
## Events
|
|
98
99
|
|
|
@@ -125,9 +126,9 @@ user sends prompt ────────────────────
|
|
|
125
126
|
│
|
|
126
127
|
user sends another prompt ◄────────────────────────────────┘
|
|
127
128
|
|
|
128
|
-
/new
|
|
129
|
-
├─► session_before_switch (can cancel, has reason: "new" | "resume")
|
|
130
|
-
└─► session_switch (has reason: "new" | "resume")
|
|
129
|
+
/new, /resume, or /fork
|
|
130
|
+
├─► session_before_switch (can cancel, has reason: "new" | "resume" | "fork")
|
|
131
|
+
└─► session_switch (has reason: "new" | "resume" | "fork")
|
|
131
132
|
|
|
132
133
|
/branch
|
|
133
134
|
├─► session_before_branch (can cancel)
|
|
@@ -135,6 +136,7 @@ user sends another prompt ◄─────────────────
|
|
|
135
136
|
|
|
136
137
|
/compact or auto-compaction
|
|
137
138
|
├─► session_before_compact (can cancel or customize)
|
|
139
|
+
├─► session.compacting (customize prompt/context)
|
|
138
140
|
└─► session_compact
|
|
139
141
|
|
|
140
142
|
/tree navigation
|
|
@@ -159,11 +161,11 @@ pi.on("session_start", async (_event, ctx) => {
|
|
|
159
161
|
|
|
160
162
|
#### session_before_switch / session_switch
|
|
161
163
|
|
|
162
|
-
Fired when starting a new session (`/new`) or
|
|
164
|
+
Fired when starting a new session (`/new`), resuming (`/resume`), or forking (`/fork`).
|
|
163
165
|
|
|
164
166
|
```typescript
|
|
165
167
|
pi.on("session_before_switch", async (event, ctx) => {
|
|
166
|
-
// event.reason - "new" (starting fresh)
|
|
168
|
+
// event.reason - "new" (starting fresh), "resume" (switching to existing), or "fork" (branch switch)
|
|
167
169
|
// event.targetSessionFile - session we're switching to (only for "resume")
|
|
168
170
|
|
|
169
171
|
if (event.reason === "new") {
|
|
@@ -175,7 +177,7 @@ pi.on("session_before_switch", async (event, ctx) => {
|
|
|
175
177
|
});
|
|
176
178
|
|
|
177
179
|
pi.on("session_switch", async (event, ctx) => {
|
|
178
|
-
// event.reason - "new" or "
|
|
180
|
+
// event.reason - "new", "resume", or "fork"
|
|
179
181
|
// event.previousSessionFile - session we came from
|
|
180
182
|
});
|
|
181
183
|
```
|
|
@@ -200,7 +202,7 @@ pi.on("session_branch", async (event, ctx) => {
|
|
|
200
202
|
|
|
201
203
|
The `skipConversationRestore` option is useful for checkpoint hooks that restore code state separately.
|
|
202
204
|
|
|
203
|
-
#### session_before_compact / session_compact
|
|
205
|
+
#### session_before_compact / session.compacting / session_compact
|
|
204
206
|
|
|
205
207
|
Fired on compaction. See [compaction.md](compaction.md) for details.
|
|
206
208
|
|
|
@@ -221,9 +223,30 @@ pi.on("session_before_compact", async (event, ctx) => {
|
|
|
221
223
|
};
|
|
222
224
|
});
|
|
223
225
|
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
#### session.compacting
|
|
229
|
+
|
|
230
|
+
Fired after preparation but before the default summarizer runs. Use it to customize the prompt or add context
|
|
231
|
+
when you are not returning a full compaction result from `session_before_compact`.
|
|
232
|
+
|
|
233
|
+
```typescript
|
|
234
|
+
pi.on("session.compacting", async (event, ctx) => {
|
|
235
|
+
// event.sessionId
|
|
236
|
+
// event.messages - messages about to be summarized
|
|
237
|
+
|
|
238
|
+
return {
|
|
239
|
+
context: ["Additional context line"],
|
|
240
|
+
prompt: "Custom compaction prompt...",
|
|
241
|
+
preserveData: { source: "my-hook" },
|
|
242
|
+
};
|
|
243
|
+
});
|
|
244
|
+
```
|
|
245
|
+
|
|
246
|
+
```typescript
|
|
224
247
|
pi.on("session_compact", async (event, ctx) => {
|
|
225
248
|
// event.compactionEntry - the saved compaction
|
|
226
|
-
// event.
|
|
249
|
+
// event.fromExtension - whether hook provided it
|
|
227
250
|
});
|
|
228
251
|
```
|
|
229
252
|
|
|
@@ -243,7 +266,7 @@ pi.on("session_before_tree", async (event, ctx) => {
|
|
|
243
266
|
});
|
|
244
267
|
|
|
245
268
|
pi.on("session_tree", async (event, ctx) => {
|
|
246
|
-
// event.newLeafId, oldLeafId, summaryEntry,
|
|
269
|
+
// event.newLeafId, oldLeafId, summaryEntry, fromExtension
|
|
247
270
|
});
|
|
248
271
|
```
|
|
249
272
|
|
|
@@ -340,15 +363,21 @@ pi.on("tool_call", async (event, ctx) => {
|
|
|
340
363
|
});
|
|
341
364
|
```
|
|
342
365
|
|
|
343
|
-
Tool inputs:
|
|
366
|
+
Tool inputs (common built-ins):
|
|
344
367
|
|
|
345
|
-
- `bash`: `{ command, timeout? }`
|
|
346
|
-
- `read`: `{ path, offset?, limit? }`
|
|
368
|
+
- `bash`: `{ command, timeout?, cwd?, head?, tail? }`
|
|
369
|
+
- `read`: `{ path, offset?, limit?, lines? }`
|
|
347
370
|
- `write`: `{ path, content }`
|
|
348
|
-
- `edit
|
|
349
|
-
- `
|
|
350
|
-
- `find`: `{ pattern,
|
|
351
|
-
- `grep`: `{ pattern, path?, glob?,
|
|
371
|
+
- `edit` (replace mode): `{ path, old_text, new_text, all? }`
|
|
372
|
+
- `edit` (patch mode): `{ path, op?, rename?, diff? }`
|
|
373
|
+
- `find`: `{ pattern, hidden?, limit? }`
|
|
374
|
+
- `grep`: `{ pattern, path?, glob?, type?, i?, pre?, post?, multiline?, limit?, offset? }`
|
|
375
|
+
|
|
376
|
+
The edit input shape depends on the current edit variant (replace vs patch). Inspect `event.input` to
|
|
377
|
+
see which schema is active.
|
|
378
|
+
|
|
379
|
+
Other tools (ask, browser, task, todo_write, fetch, web_search, python, notebook, lsp, ssh, calc) use
|
|
380
|
+
their own schemas; inspect the tool prompt or `src/tools/*.ts` for details.
|
|
352
381
|
|
|
353
382
|
#### tool_result
|
|
354
383
|
|
|
@@ -372,23 +401,20 @@ pi.on("tool_result", async (event, ctx) => {
|
|
|
372
401
|
});
|
|
373
402
|
```
|
|
374
403
|
|
|
375
|
-
Use
|
|
404
|
+
Use `event.toolName` to narrow tool-specific details:
|
|
376
405
|
|
|
377
406
|
```typescript
|
|
378
|
-
import { isBashToolResult } from "@oh-my-pi/pi-coding-agent";
|
|
379
|
-
|
|
380
407
|
pi.on("tool_result", async (event, ctx) => {
|
|
381
|
-
if (
|
|
408
|
+
if (event.toolName === "bash") {
|
|
382
409
|
// event.details is BashToolDetails | undefined
|
|
383
|
-
|
|
384
|
-
|
|
410
|
+
const artifactId = event.details?.meta?.truncation?.artifactId;
|
|
411
|
+
if (artifactId) {
|
|
412
|
+
// Full output is stored under the artifact ID
|
|
385
413
|
}
|
|
386
414
|
}
|
|
387
415
|
});
|
|
388
416
|
```
|
|
389
417
|
|
|
390
|
-
Available guards: `isBashToolResult`, `isReadToolResult`, `isEditToolResult`, `isWriteToolResult`, `isGrepToolResult`, `isFindToolResult`, `isLsToolResult`.
|
|
391
|
-
|
|
392
418
|
## HookContext
|
|
393
419
|
|
|
394
420
|
Every handler receives `ctx: HookContext`:
|
|
@@ -488,7 +514,8 @@ See [examples/hooks/qna.ts](../examples/hooks/qna.ts) for a loader pattern and [
|
|
|
488
514
|
|
|
489
515
|
### ctx.hasUI
|
|
490
516
|
|
|
491
|
-
`false` in print mode (`-p`)
|
|
517
|
+
`false` in print mode (`-p`) and JSON print mode. RPC mode provides UI via the host, so `ctx.hasUI` is true.
|
|
518
|
+
Always check before using `ctx.ui`:
|
|
492
519
|
|
|
493
520
|
```typescript
|
|
494
521
|
if (ctx.hasUI) {
|
|
@@ -504,7 +531,7 @@ Current working directory.
|
|
|
504
531
|
|
|
505
532
|
### ctx.sessionManager
|
|
506
533
|
|
|
507
|
-
Read-only access to session state. See `ReadonlySessionManager` in [`src/
|
|
534
|
+
Read-only access to session state. See `ReadonlySessionManager` in [`src/session/session-manager.ts`](../src/session/session-manager.ts).
|
|
508
535
|
|
|
509
536
|
```typescript
|
|
510
537
|
// Session info
|
|
@@ -538,7 +565,7 @@ Access to models and API keys:
|
|
|
538
565
|
const apiKey = await ctx.modelRegistry.getApiKey(model);
|
|
539
566
|
|
|
540
567
|
// Get available models
|
|
541
|
-
const models = ctx.modelRegistry.
|
|
568
|
+
const models = ctx.modelRegistry.getAvailable();
|
|
542
569
|
```
|
|
543
570
|
|
|
544
571
|
### ctx.model
|
|
@@ -567,7 +594,7 @@ if (ctx.isIdle()) {
|
|
|
567
594
|
Abort the current agent operation (fire-and-forget, does not wait):
|
|
568
595
|
|
|
569
596
|
```typescript
|
|
570
|
-
|
|
597
|
+
ctx.abort();
|
|
571
598
|
```
|
|
572
599
|
|
|
573
600
|
### ctx.hasQueuedMessages()
|
|
@@ -643,24 +670,28 @@ const result = await ctx.navigateTree("entry-id-456", {
|
|
|
643
670
|
|
|
644
671
|
Subscribe to events. See [Events](#events) for all event types.
|
|
645
672
|
|
|
646
|
-
### pi.sendMessage(message,
|
|
673
|
+
### pi.sendMessage(message, options?)
|
|
647
674
|
|
|
648
675
|
Inject a message into the session. Creates a `CustomMessageEntry` that participates in the LLM context.
|
|
649
676
|
|
|
650
677
|
```typescript
|
|
651
|
-
pi.sendMessage(
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
},
|
|
678
|
+
pi.sendMessage(
|
|
679
|
+
{
|
|
680
|
+
customType: "my-hook", // Your hook's identifier
|
|
681
|
+
content: "Message text", // string or (TextContent | ImageContent)[]
|
|
682
|
+
display: true, // Show in TUI
|
|
683
|
+
details: { ... }, // Optional metadata (not sent to LLM)
|
|
684
|
+
},
|
|
685
|
+
{ triggerTurn: true }, // Trigger a new LLM response if idle
|
|
686
|
+
);
|
|
657
687
|
```
|
|
658
688
|
|
|
659
689
|
**Storage and timing:**
|
|
660
690
|
|
|
661
691
|
- The message is appended to the session file immediately as a `CustomMessageEntry`
|
|
662
692
|
- If the agent is currently streaming, the message is queued and appended after the current turn
|
|
663
|
-
- If `triggerTurn` is true and the agent is idle, a new agent loop starts
|
|
693
|
+
- If `options.triggerTurn` is true and the agent is idle, a new agent loop starts
|
|
694
|
+
- `options.deliverAs` chooses how to enqueue the message (`"steer"` or `"followUp"`)
|
|
664
695
|
|
|
665
696
|
**LLM context:**
|
|
666
697
|
|
|
@@ -708,7 +739,7 @@ pi.registerCommand("stats", {
|
|
|
708
739
|
|
|
709
740
|
For long-running commands (e.g., LLM calls), use `ctx.ui.custom()` with a loader. See [examples/hooks/qna.ts](../examples/hooks/qna.ts).
|
|
710
741
|
|
|
711
|
-
To trigger LLM after command, call `pi.sendMessage(..., true)`.
|
|
742
|
+
To trigger the LLM after a command, call `pi.sendMessage(..., { triggerTurn: true })`.
|
|
712
743
|
|
|
713
744
|
### pi.registerMessageRenderer(customType, renderer)
|
|
714
745
|
|
|
@@ -736,13 +767,13 @@ pi.registerMessageRenderer("my-hook", (message, options, theme) => {
|
|
|
736
767
|
|
|
737
768
|
```typescript
|
|
738
769
|
type HookMessageRenderer = (
|
|
739
|
-
message:
|
|
770
|
+
message: HookMessage,
|
|
740
771
|
options: { expanded: boolean },
|
|
741
772
|
theme: Theme
|
|
742
|
-
) => Component |
|
|
773
|
+
) => Component | undefined;
|
|
743
774
|
```
|
|
744
775
|
|
|
745
|
-
Return `
|
|
776
|
+
Return `undefined` to use default rendering. The returned component is wrapped in a styled Box by the TUI. See [tui.md](tui.md) for component details.
|
|
746
777
|
|
|
747
778
|
### pi.exec(command, args, options?)
|
|
748
779
|
|
|
@@ -757,12 +788,18 @@ const result = await pi.exec("git", ["status"], {
|
|
|
757
788
|
// result.stdout, result.stderr, result.code, result.killed
|
|
758
789
|
```
|
|
759
790
|
|
|
791
|
+
### pi.logger / pi.typebox / pi.pi
|
|
792
|
+
|
|
793
|
+
- `pi.logger` is the shared logger (avoid `console.*` to keep the TUI clean)
|
|
794
|
+
- `pi.typebox` exposes `@sinclair/typebox` for schema definitions
|
|
795
|
+
- `pi.pi` exposes `@oh-my-pi/pi-coding-agent` exports (components, helpers)
|
|
796
|
+
|
|
760
797
|
## Examples
|
|
761
798
|
|
|
762
799
|
### Permission Gate
|
|
763
800
|
|
|
764
801
|
```typescript
|
|
765
|
-
import type { HookAPI } from "@oh-my-pi/pi-coding-agent";
|
|
802
|
+
import type { HookAPI } from "@oh-my-pi/pi-coding-agent/hooks";
|
|
766
803
|
|
|
767
804
|
export default function (pi: HookAPI) {
|
|
768
805
|
const dangerous = [/\brm\s+(-rf?|--recursive)/i, /\bsudo\b/i];
|
|
@@ -785,7 +822,7 @@ export default function (pi: HookAPI) {
|
|
|
785
822
|
### Protected Paths
|
|
786
823
|
|
|
787
824
|
```typescript
|
|
788
|
-
import type { HookAPI } from "@oh-my-pi/pi-coding-agent";
|
|
825
|
+
import type { HookAPI } from "@oh-my-pi/pi-coding-agent/hooks";
|
|
789
826
|
|
|
790
827
|
export default function (pi: HookAPI) {
|
|
791
828
|
const protectedPaths = [".env", ".git/", "node_modules/"];
|
|
@@ -805,7 +842,7 @@ export default function (pi: HookAPI) {
|
|
|
805
842
|
### Git Checkpoint
|
|
806
843
|
|
|
807
844
|
```typescript
|
|
808
|
-
import type { HookAPI } from "@oh-my-pi/pi-coding-agent";
|
|
845
|
+
import type { HookAPI } from "@oh-my-pi/pi-coding-agent/hooks";
|
|
809
846
|
|
|
810
847
|
export default function (pi: HookAPI) {
|
|
811
848
|
const checkpoints = new Map<string, string>();
|
|
@@ -844,13 +881,15 @@ See [examples/hooks/snake.ts](../examples/hooks/snake.ts) for a complete example
|
|
|
844
881
|
|
|
845
882
|
## Mode Behavior
|
|
846
883
|
|
|
847
|
-
| Mode
|
|
848
|
-
|
|
|
849
|
-
| Interactive
|
|
850
|
-
| RPC
|
|
851
|
-
| Print (`-p`)
|
|
884
|
+
| Mode | UI Methods | Notes |
|
|
885
|
+
| --------------- | -------------------------- | ------------------------------------------ |
|
|
886
|
+
| Interactive | Full TUI | Normal operation |
|
|
887
|
+
| RPC | UI via RPC | Host handles UI, `ctx.hasUI` is true |
|
|
888
|
+
| Print (`-p`) | No-op (returns undefined/false) | Hooks run but can't prompt (`ctx.hasUI`=false) |
|
|
852
889
|
|
|
853
|
-
In print mode, `select()` returns `undefined`, `confirm()` returns `false`, `input()` returns
|
|
890
|
+
In print mode (including JSON output), `select()` returns `undefined`, `confirm()` returns `false`, `input()` returns
|
|
891
|
+
`undefined`, `getEditorText()` returns `""`, and `setEditorText()`/`setStatus()` are no-ops. Design hooks to handle this
|
|
892
|
+
by checking `ctx.hasUI`.
|
|
854
893
|
|
|
855
894
|
## Error Handling
|
|
856
895
|
|
package/docs/python-repl.md
CHANGED
|
@@ -6,20 +6,24 @@
|
|
|
6
6
|
- `jupyter-kernel-gateway` (`kernel_gateway` module) and `ipykernel` installed in the selected Python environment
|
|
7
7
|
|
|
8
8
|
Install:
|
|
9
|
+
|
|
9
10
|
```bash
|
|
10
11
|
python -m pip install jupyter_kernel_gateway ipykernel
|
|
11
12
|
```
|
|
12
13
|
|
|
13
14
|
## How It Works
|
|
14
15
|
|
|
15
|
-
The Python tool
|
|
16
|
+
The Python tool uses a Jupyter Kernel Gateway and talks to it over REST and WebSocket APIs.
|
|
17
|
+
By default it uses a shared local gateway so multiple pi instances reuse the same gateway process.
|
|
18
|
+
|
|
19
|
+
Shared-gateway startup flow:
|
|
16
20
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
21
|
+
1. Filter the environment and resolve the Python runtime (including venv detection)
|
|
22
|
+
2. Acquire the shared gateway (reuse a healthy gateway or spawn `python -m kernel_gateway` on 127.0.0.1:PORT)
|
|
23
|
+
3. Wait for gateway readiness (`GET /api/kernelspecs`)
|
|
24
|
+
4. Create a kernel (`POST /api/kernels`)
|
|
25
|
+
5. Connect WebSocket for execution messages
|
|
26
|
+
6. Initialize kernel environment, run prelude helpers, and load extension modules
|
|
23
27
|
|
|
24
28
|
## External Gateway Support
|
|
25
29
|
|
|
@@ -27,19 +31,21 @@ Instead of spawning a local gateway, you can connect to an already-running Jupyt
|
|
|
27
31
|
|
|
28
32
|
```bash
|
|
29
33
|
# Connect to external gateway
|
|
30
|
-
export
|
|
34
|
+
export PI_PYTHON_GATEWAY_URL="http://127.0.0.1:8888"
|
|
31
35
|
|
|
32
36
|
# Optional: auth token if gateway requires it (KG_AUTH_TOKEN)
|
|
33
|
-
export
|
|
37
|
+
export PI_PYTHON_GATEWAY_TOKEN="your-token-here"
|
|
34
38
|
```
|
|
35
39
|
|
|
36
|
-
When `
|
|
40
|
+
When `PI_PYTHON_GATEWAY_URL` is set:
|
|
41
|
+
|
|
37
42
|
- No local gateway process is spawned
|
|
38
43
|
- Kernels are created on the external gateway
|
|
39
44
|
- The gateway process is not killed on shutdown
|
|
40
45
|
- Availability check uses `/api/kernelspecs` endpoint instead of local module check
|
|
41
46
|
|
|
42
47
|
This is useful for:
|
|
48
|
+
|
|
43
49
|
- Remote kernel execution
|
|
44
50
|
- Shared kernel environments
|
|
45
51
|
- Pre-configured gateway setups
|
|
@@ -47,31 +53,58 @@ This is useful for:
|
|
|
47
53
|
## Environment Propagation
|
|
48
54
|
|
|
49
55
|
- The kernel inherits a filtered environment (explicit allowlist + denylist)
|
|
50
|
-
-
|
|
56
|
+
- Allowlisted prefixes include `LC_`, `XDG_`, and `PI_`; known API-key vars are removed
|
|
57
|
+
- `PYTHONPATH` is passed through if present
|
|
51
58
|
- Virtual environments are detected via `VIRTUAL_ENV`, `.venv/`, or `venv/` and preferred when present
|
|
52
59
|
|
|
60
|
+
## Prelude Extensions
|
|
61
|
+
|
|
62
|
+
Optional `.py` modules are loaded after the prelude from:
|
|
63
|
+
|
|
64
|
+
- `~/.omp/agent/modules` and `~/.pi/agent/modules`
|
|
65
|
+
- `<project>/.omp/modules` and `<project>/.pi/modules`
|
|
66
|
+
|
|
67
|
+
Project modules override user modules with the same filename.
|
|
68
|
+
|
|
53
69
|
## Kernel Modes
|
|
54
70
|
|
|
55
71
|
Settings under `python` control exposure and reuse:
|
|
56
|
-
- `toolMode`: `ipy-only` (default), `bash-only`, `both`
|
|
57
|
-
- `kernelMode`: `session` (default, queued), `per-call`
|
|
58
72
|
|
|
59
|
-
|
|
73
|
+
- `toolMode`: `both` (default), `ipy-only`, `bash-only`
|
|
74
|
+
- `kernelMode`: `session` (default) or `per-call`
|
|
75
|
+
- `sharedGateway`: `true` (default). Setting to `false` throws an error because local (per-process) gateways are not supported; the shared gateway is required.
|
|
76
|
+
|
|
77
|
+
Mode behavior:
|
|
78
|
+
|
|
79
|
+
- `session`: reuse kernels per session id, serialize execution, evict after 5 minutes of idle time (max 4 sessions)
|
|
80
|
+
- `per-call`: create a fresh kernel per tool call and shut it down afterward
|
|
81
|
+
|
|
82
|
+
Environment override:
|
|
83
|
+
|
|
84
|
+
- `PI_PY=0|bash` → `bash-only`
|
|
85
|
+
- `PI_PY=1|py` → `ipy-only`
|
|
86
|
+
- `PI_PY=mix|both` → `both`
|
|
87
|
+
|
|
88
|
+
## Shell Helper
|
|
60
89
|
|
|
61
|
-
The Python prelude exposes `
|
|
62
|
-
|
|
63
|
-
- Runs via `bash -lc` when available, with OS fallbacks
|
|
90
|
+
The Python prelude exposes `run()` which executes a shell command via `bash -c` (or `sh -c` fallback)
|
|
91
|
+
and returns a `ShellResult` with `stdout`, `stderr`, and `code`.
|
|
64
92
|
|
|
65
93
|
## Output Handling
|
|
66
94
|
|
|
67
95
|
- Streams `stdout`/`stderr` as text
|
|
96
|
+
- `application/x-omp-status` emits structured status events for the TUI
|
|
68
97
|
- `image/png` display data renders inline in TUI
|
|
69
98
|
- `application/json` display data renders as a collapsible tree
|
|
99
|
+
- `text/markdown` is rendered as-is, `text/plain` is used as a fallback
|
|
70
100
|
- `text/html` display data is converted to basic markdown
|
|
71
101
|
|
|
72
102
|
## Troubleshooting
|
|
73
103
|
|
|
74
104
|
- **Kernel unavailable**: Ensure `python` + `jupyter-kernel-gateway` + `ipykernel` are installed; the session will fall back to bash-only.
|
|
75
|
-
- **
|
|
76
|
-
- **
|
|
105
|
+
- **Python mode override**: Check `python.toolMode` or `PI_PY` if the Python tool is missing.
|
|
106
|
+
- **Shared gateway disabled**: `python.sharedGateway=false` causes the Python tool to error because local (per-process) gateways are not supported.
|
|
107
|
+
- **Skip preflight checks**: Set `PI_PYTHON_SKIP_CHECK=1` to bypass kernel availability checks.
|
|
108
|
+
- **External gateway unreachable**: Check the URL is correct and the gateway is running. If auth is required, set `PI_PYTHON_GATEWAY_TOKEN`.
|
|
109
|
+
- **IPC tracing**: Set `PI_PYTHON_IPC_TRACE=1` to log kernel message flow.
|
|
77
110
|
- **Stdin requests**: Interactive input is not supported; refactor code to avoid `input()` or provide data programmatically.
|