pi-crew 0.1.44 → 0.1.45

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.
Files changed (142) hide show
  1. package/CHANGELOG.md +27 -0
  2. package/agents/analyst.md +11 -11
  3. package/agents/critic.md +11 -11
  4. package/agents/executor.md +11 -11
  5. package/agents/explorer.md +11 -11
  6. package/agents/planner.md +11 -11
  7. package/agents/reviewer.md +11 -11
  8. package/agents/security-reviewer.md +11 -11
  9. package/agents/test-engineer.md +11 -11
  10. package/agents/verifier.md +11 -11
  11. package/agents/writer.md +11 -11
  12. package/docs/refactor-tasks-phase3.md +394 -394
  13. package/docs/refactor-tasks-phase4.md +564 -564
  14. package/docs/refactor-tasks-phase5.md +402 -402
  15. package/docs/refactor-tasks-phase6.md +662 -662
  16. package/docs/research-extension-examples.md +297 -297
  17. package/docs/research-extension-system.md +324 -324
  18. package/docs/research-optimization-plan.md +548 -548
  19. package/docs/research-phase10-distillation.md +198 -198
  20. package/docs/research-phase11-distillation.md +201 -201
  21. package/docs/research-pi-coding-agent.md +357 -357
  22. package/docs/research-source-pi-crew-reference.md +174 -174
  23. package/docs/runtime-flow.md +148 -148
  24. package/docs/source-runtime-refactor-map.md +83 -83
  25. package/index.ts +6 -6
  26. package/package.json +1 -1
  27. package/src/agents/agent-serializer.ts +34 -34
  28. package/src/extension/cross-extension-rpc.ts +82 -82
  29. package/src/extension/register.ts +8 -1
  30. package/src/extension/registration/commands.ts +18 -2
  31. package/src/extension/registration/compaction-guard.ts +125 -125
  32. package/src/extension/registration/subagent-tools.ts +148 -148
  33. package/src/extension/registration/team-tool.ts +26 -8
  34. package/src/extension/run-bundle-schema.ts +89 -89
  35. package/src/extension/run-maintenance.ts +43 -43
  36. package/src/extension/team-tool/cancel.ts +105 -102
  37. package/src/extension/team-tool/context.ts +1 -0
  38. package/src/extension/team-tool/handle-settings.ts +188 -188
  39. package/src/extension/team-tool/inspect.ts +41 -41
  40. package/src/extension/team-tool/lifecycle-actions.ts +79 -79
  41. package/src/extension/team-tool/plan.ts +19 -19
  42. package/src/extension/team-tool/respond.ts +83 -66
  43. package/src/extension/team-tool/run.ts +1 -0
  44. package/src/i18n.ts +184 -184
  45. package/src/observability/exporters/otlp-exporter.ts +77 -77
  46. package/src/prompt/prompt-runtime.ts +72 -72
  47. package/src/runtime/agent-control.ts +63 -63
  48. package/src/runtime/agent-memory.ts +72 -72
  49. package/src/runtime/agent-observability.ts +114 -114
  50. package/src/runtime/async-marker.ts +26 -26
  51. package/src/runtime/attention-events.ts +28 -28
  52. package/src/runtime/background-runner.ts +53 -53
  53. package/src/runtime/child-pi.ts +444 -444
  54. package/src/runtime/completion-guard.ts +190 -190
  55. package/src/runtime/crew-agent-records.ts +8 -0
  56. package/src/runtime/delivery-coordinator.ts +153 -142
  57. package/src/runtime/direct-run.ts +35 -35
  58. package/src/runtime/foreground-control.ts +82 -82
  59. package/src/runtime/green-contract.ts +46 -46
  60. package/src/runtime/group-join.ts +106 -106
  61. package/src/runtime/heartbeat-gradient.ts +28 -28
  62. package/src/runtime/heartbeat-watcher.ts +124 -124
  63. package/src/runtime/live-agent-control.ts +87 -87
  64. package/src/runtime/live-agent-manager.ts +85 -85
  65. package/src/runtime/live-control-realtime.ts +36 -36
  66. package/src/runtime/live-session-runtime.ts +305 -305
  67. package/src/runtime/overflow-recovery.ts +175 -156
  68. package/src/runtime/parallel-research.ts +44 -44
  69. package/src/runtime/pi-json-output.ts +111 -111
  70. package/src/runtime/policy-engine.ts +79 -79
  71. package/src/runtime/progress-event-coalescer.ts +43 -43
  72. package/src/runtime/recovery-recipes.ts +74 -74
  73. package/src/runtime/retry-executor.ts +64 -64
  74. package/src/runtime/role-permission.ts +39 -39
  75. package/src/runtime/session-resources.ts +25 -25
  76. package/src/runtime/session-snapshot.ts +59 -59
  77. package/src/runtime/session-usage.ts +79 -79
  78. package/src/runtime/sidechain-output.ts +29 -29
  79. package/src/runtime/stale-reconciler.ts +199 -179
  80. package/src/runtime/supervisor-contact.ts +59 -59
  81. package/src/runtime/task-display.ts +38 -38
  82. package/src/runtime/task-output-context.ts +127 -127
  83. package/src/runtime/task-runner/live-executor.ts +101 -101
  84. package/src/runtime/task-runner/progress.ts +119 -119
  85. package/src/runtime/task-runner/result-utils.ts +14 -14
  86. package/src/runtime/task-runner/state-helpers.ts +22 -22
  87. package/src/runtime/team-runner.ts +13 -4
  88. package/src/runtime/worker-heartbeat.ts +21 -21
  89. package/src/runtime/worker-startup.ts +57 -57
  90. package/src/state/state-store.ts +43 -0
  91. package/src/state/task-claims.ts +44 -44
  92. package/src/state/types.ts +2 -0
  93. package/src/state/usage.ts +29 -29
  94. package/src/subagents/async-entry.ts +1 -1
  95. package/src/subagents/index.ts +3 -3
  96. package/src/subagents/live/control.ts +1 -1
  97. package/src/subagents/live/manager.ts +1 -1
  98. package/src/subagents/live/realtime.ts +1 -1
  99. package/src/subagents/live/session-runtime.ts +1 -1
  100. package/src/subagents/manager.ts +1 -1
  101. package/src/subagents/spawn.ts +1 -1
  102. package/src/teams/team-serializer.ts +38 -38
  103. package/src/types/diff.d.ts +18 -18
  104. package/src/ui/crew-footer.ts +101 -101
  105. package/src/ui/crew-select-list.ts +111 -111
  106. package/src/ui/crew-widget.ts +5 -1
  107. package/src/ui/dashboard-panes/mailbox-pane.ts +2 -1
  108. package/src/ui/dashboard-panes/metrics-pane.ts +34 -34
  109. package/src/ui/dynamic-border.ts +25 -25
  110. package/src/ui/layout-primitives.ts +106 -106
  111. package/src/ui/loaders.ts +158 -158
  112. package/src/ui/powerbar-publisher.ts +1 -1
  113. package/src/ui/render-diff.ts +119 -119
  114. package/src/ui/render-scheduler.ts +143 -143
  115. package/src/ui/run-snapshot-cache.ts +56 -37
  116. package/src/ui/snapshot-types.ts +5 -0
  117. package/src/ui/spinner.ts +17 -17
  118. package/src/ui/status-colors.ts +58 -58
  119. package/src/ui/syntax-highlight.ts +116 -116
  120. package/src/utils/atomic-write.ts +33 -33
  121. package/src/utils/completion-dedupe.ts +63 -63
  122. package/src/utils/frontmatter.ts +68 -68
  123. package/src/utils/git.ts +262 -262
  124. package/src/utils/ids.ts +12 -12
  125. package/src/utils/names.ts +27 -27
  126. package/src/utils/redaction.ts +44 -44
  127. package/src/utils/safe-paths.ts +47 -47
  128. package/src/utils/sleep.ts +32 -32
  129. package/src/workflows/validate-workflow.ts +40 -40
  130. package/src/worktree/branch-freshness.ts +45 -45
  131. package/teams/default.team.md +12 -12
  132. package/teams/fast-fix.team.md +11 -11
  133. package/teams/implementation.team.md +18 -18
  134. package/teams/parallel-research.team.md +14 -14
  135. package/teams/research.team.md +11 -11
  136. package/teams/review.team.md +12 -12
  137. package/workflows/default.workflow.md +29 -29
  138. package/workflows/fast-fix.workflow.md +22 -22
  139. package/workflows/implementation.workflow.md +38 -38
  140. package/workflows/parallel-research.workflow.md +46 -46
  141. package/workflows/research.workflow.md +22 -22
  142. package/workflows/review.workflow.md +30 -30
@@ -1,324 +1,324 @@
1
- # Research: Pi Extension System Deep Dive
2
-
3
- > Ngày: 2026-04-29 | Read-only research | Source: `source/pi-mono/packages/coding-agent/src/core/extensions/`
4
-
5
- ## 1. Extension System Architecture
6
-
7
- Pi extension system là plugin framework cho coding agent. Extensions được viết bằng TypeScript,
8
- load qua jiti (JIT compiler), và có thể hook vào mọi phase của agent lifecycle.
9
-
10
- ```
11
- ┌─────────────────────────────────────────────────────────────┐
12
- │ ExtensionAPI ("pi.*") │
13
- │ Event sub: pi.on(event, handler) │
14
- │ Tools: pi.registerTool(def) │
15
- │ Commands: pi.registerCommand(name, opts) │
16
- │ Shortcuts: pi.registerShortcut(key, opts) │
17
- │ Flags: pi.registerFlag(name, opts) │
18
- │ Messages: pi.sendMessage() / pi.sendUserMessage() │
19
- │ State: pi.appendEntry(customType, data) │
20
- │ Provider: pi.registerProvider(name, config) │
21
- │ Event bus: pi.events.emit/on() │
22
- │ Model: pi.setModel() / getThinkingLevel() │
23
- │ Tools mgmt: pi.getActiveTools() / setActiveTools() │
24
- ├─────────────────────────────────────────────────────────────┤
25
- │ ExtensionFactory │
26
- │ (pi: ExtensionAPI) => void | Promise<void> │
27
- ├─────────────────────────────────────────────────────────────┤
28
- │ loader.ts ──► jiti → TypeScript module loading │
29
- │ runner.ts ──► ExtensionRunner → lifecycle + event emit │
30
- │ types.ts ───► 1545 dòng type definitions │
31
- └─────────────────────────────────────────────────────────────┘
32
- ```
33
-
34
- ## 2. Extension Loading Flow
35
-
36
- ```
37
- discoverAndLoadExtensions(cwd, agentDir, extensionPaths)
38
- ├── Scan directories:
39
- │ ├── ~/.pi/agent/extensions/**/index.ts (user-global)
40
- │ ├── .pi/extensions/**/index.ts (project-local)
41
- │ └── CLI --extension paths (explicit)
42
- ├── Create ExtensionRuntime (shared state + action stubs)
43
- ├── For each extension file:
44
- │ ├── jiti.import(path) # Load TS module
45
- │ ├── Call default export: factory(pi) # Register handlers/tools/commands
46
- │ └── Collect into Extension object
47
- └── Return LoadExtensionsResult
48
-
49
- ExtensionRunner.initialize(session, context, actions)
50
- ├── Bind real action implementations to runtime
51
- ├── Process queued provider registrations
52
- └── Emit session_start event
53
- ```
54
-
55
- ### 2.1 Discovery priority
56
-
57
- Project-local > user-global. Extensions cùng tên: project override user.
58
-
59
- ### 2.2 Runtime replacement (reload)
60
-
61
- Khi `/reload` hoặc session switch:
62
- 1. `emitSessionShutdownEvent("reload")`
63
- 2. Invalidate old ExtensionRuntime (throws if stale extension tries to act)
64
- 3. Re-discover + re-load tất cả extensions
65
- 4. Re-initialize ExtensionRunner
66
-
67
- ## 3. Full Event Lifecycle
68
-
69
- ### 3.1 Event model (23 event types)
70
-
71
- **Session events** — session-level lifecycle:
72
- ```
73
- session_start ← Khi session được tạo/load/reload
74
- resources_discover ← Extension có thể inject thêm paths
75
- session_before_switch ← Trước khi switch session (có thể cancel)
76
- session_before_fork ← Trước khi fork session (có thể cancel)
77
- session_before_compact ← Trước khi compaction (có thể cancel hoặc custom)
78
- session_compact ← Sau khi compaction hoàn tất
79
- session_before_tree ← Trước khi navigate tree (có thể cancel)
80
- session_tree ← Sau khi navigate tree
81
- session_shutdown ← Khi session bị hủy (quit/reload/new/resume/fork)
82
- ```
83
-
84
- **Agent events** — per-prompt:
85
- ```
86
- input ← Khi user input received (có thể transform/block)
87
- before_agent_start ← Trước khi agent loop chạy (inject custom message / swap system prompt)
88
- context ← Transform messages trước khi gửi LLM
89
- before_provider_request ← Thay đổi payload trước khi gửi provider
90
- after_provider_response ← Quan sát response status/headers
91
- agent_start ← Agent loop bắt đầu
92
- agent_end ← Agent loop kết thúc
93
- ```
94
-
95
- **Turn events** — per-turn:
96
- ```
97
- turn_start ← Bắt đầu turn mới
98
- turn_end ← Kết thúc turn (có message + tool results)
99
- ```
100
-
101
- **Message events** — per-message:
102
- ```
103
- message_start ← Message bắt đầu (user/assistant/toolResult)
104
- message_update ← Streaming token-by-token update
105
- message_end ← Message hoàn tất
106
- ```
107
-
108
- **Tool events** — per-tool:
109
- ```
110
- tool_call ← Trước khi tool execute (có thể block/mutate args)
111
- tool_execution_start ← Tool bắt đầu chạy
112
- tool_execution_update ← Partial/streaming result
113
- tool_execution_end ← Tool hoàn tất
114
- tool_result ← Sau khi tool execute (có thể modify result)
115
- ```
116
-
117
- **Other:**
118
- ```
119
- model_select ← Khi model được chọn/thay đổi
120
- user_bash ← Khi user dùng ! prefix cho bash
121
- ```
122
-
123
- ### 3.2 Event result contracts
124
-
125
- Mỗi event có thể return result để ảnh hưởng đến behavior:
126
-
127
- | Event | Result type | Effect |
128
- |---|---|---|
129
- | `input` | `{ action: "continue" \| "transform" \| "handled" }` | Transform/block input |
130
- | `before_agent_start` | `{ message?, systemPrompt? }` | Inject custom message, swap system prompt |
131
- | `context` | `{ messages? }` | Replace context messages |
132
- | `before_provider_request` | `any` | Replace payload |
133
- | `tool_call` | `{ block?, reason? }` | Block tool execution |
134
- | `tool_result` | `{ content?, details?, isError? }` | Modify result |
135
- | `user_bash` | `{ operations?, result? }` | Custom bash execution |
136
- | `session_before_*` | `{ cancel? }` | Cancel session operation |
137
- | `session_before_compact` | `{ cancel?, compaction? }` | Cancel or custom compact |
138
- | `session_before_tree` | `{ cancel?, summary?, customInstructions? }` | Cancel or custom summary |
139
- | `resources_discover` | `{ skillPaths?, promptPaths?, themePaths? }` | Inject resource paths |
140
-
141
- ## 4. Context Objects Available to Extensions
142
-
143
- ### 4.1 ExtensionContext (`ctx.*`) — có sẵn trong mọi event handler
144
-
145
- ```typescript
146
- interface ExtensionContext {
147
- ui: ExtensionUIContext; // UI methods (select, confirm, notify, widgets...)
148
- hasUI: boolean; // false in print/RPC mode
149
- cwd: string; // Current working directory
150
- sessionManager: ReadonlySessionManager; // Session access (read-only)
151
- modelRegistry: ModelRegistry; // Auth + model discovery
152
- model: Model<any> | undefined; // Current model
153
- isIdle(): boolean; // Check if agent is streaming
154
- signal: AbortSignal | undefined;// Current abort signal
155
- abort(): void; // Abort current operation
156
- hasPendingMessages(): boolean; // Check message queue
157
- shutdown(): void; // Graceful shutdown
158
- getContextUsage(): ContextUsage | undefined; // Token usage
159
- compact(options?): void; // Trigger compaction
160
- getSystemPrompt(): string; // Current system prompt
161
- }
162
- ```
163
-
164
- ### 4.2 ExtensionCommandContext — extends Context, chỉ trong command handler
165
-
166
- ```typescript
167
- interface ExtensionCommandContext extends ExtensionContext {
168
- waitForIdle(): Promise<void>; // Wait for agent to finish
169
- newSession(options?): Promise<{cancelled}>;
170
- fork(entryId, options?): Promise<{cancelled}>;
171
- navigateTree(targetId, options?): Promise<{cancelled}>;
172
- switchSession(sessionPath, options?): Promise<{cancelled}>;
173
- reload(): Promise<void>;
174
- }
175
- ```
176
-
177
- ### 4.3 ReplacedSessionContext — sau khi switch/new session
178
-
179
- ```typescript
180
- interface ReplacedSessionContext extends ExtensionCommandContext {
181
- sendMessage(message, options?): Promise<void>;
182
- sendUserMessage(content, options?): Promise<void>;
183
- }
184
- ```
185
-
186
- ### 4.4 ExtensionUIContext (`ctx.ui.*`) — chỉ khi `hasUI=true`
187
-
188
- ```typescript
189
- interface ExtensionUIContext {
190
- select(title, options, opts?): Promise<string | undefined>;
191
- confirm(title, message, opts?): Promise<boolean>;
192
- input(title, placeholder?, opts?): Promise<string | undefined>;
193
- notify(message, type?): void;
194
- custom<T>(factory, options?): Promise<T>; // Custom overlay component
195
- setWidget(key, content, options?): void; // Widget above/below editor
196
- setFooter(factory): void; // Custom footer
197
- setHeader(factory): void; // Custom header
198
- setEditorComponent(factory): void; // Custom editor
199
- setStatus(key, text): void; // Status bar
200
- setTitle(title): void; // Terminal title
201
- setWorkingMessage(message?): void; // Working loader text
202
- setWorkingVisible(visible): void; // Show/hide loader
203
- setWorkingIndicator(options?): void; // Custom loader animation
204
- setHiddenThinkingLabel(label?): void; // Thinking block label
205
- onTerminalInput(handler): () => void; // Raw terminal input
206
- getToolsExpanded(): boolean;
207
- setToolsExpanded(expanded): void;
208
- theme: Theme;
209
- getAllThemes(): {name, path}[];
210
- getTheme(name): Theme | undefined;
211
- setTheme(theme): {success, error?};
212
- }
213
- ```
214
-
215
- ## 5. ToolDefinition Contract
216
-
217
- ```typescript
218
- interface ToolDefinition<TParams extends TSchema, TDetails = unknown, TState = any> {
219
- name: string; // Unique tool name
220
- label: string; // Human-readable for UI
221
- description: string; // For LLM
222
- parameters: TParams; // TypeBox schema
223
- promptSnippet?: string; // 1-line for system prompt "Available tools"
224
- promptGuidelines?: string[]; // Bullets for system prompt "Guidelines"
225
- renderShell?: "default" | "self"; // Who renders the outer frame
226
- executionMode?: "sequential" | "parallel"; // Concurrency control
227
- prepareArguments?: (args: unknown) => Static<TParams>;
228
-
229
- // Core execution
230
- execute(
231
- toolCallId: string,
232
- params: Static<TParams>,
233
- signal: AbortSignal | undefined,
234
- onUpdate: AgentToolUpdateCallback<TDetails> | undefined,
235
- ctx: ExtensionContext,
236
- ): Promise<AgentToolResult<TDetails>>;
237
-
238
- // Rendering (optional)
239
- renderCall?(args, theme, context): Component; // Custom call display
240
- renderResult?(result, options, theme, context): Component; // Custom result display
241
- }
242
- ```
243
-
244
- ### 5.1 `terminate: true` pattern
245
-
246
- Tool có thể set `terminate: true` trong result để kết thúc turn ngay sau tool call,
247
- tiết kiệm 1 follow-up LLM turn:
248
-
249
- ```typescript
250
- return {
251
- content: [{ type: "text", text: "Done" }],
252
- details: { ... },
253
- terminate: true, // ← Kết thúc turn, không cần LLM follow-up
254
- };
255
- ```
256
-
257
- ## 6. Provider Registration
258
-
259
- Extension có thể đăng ký provider tùy chỉnh:
260
-
261
- ```typescript
262
- pi.registerProvider("my-provider", {
263
- baseUrl: "https://api.example.com",
264
- apiKey: "PROVIDER_API_KEY",
265
- api: "anthropic-messages",
266
- models: [{
267
- id: "my-model",
268
- name: "My Model",
269
- reasoning: false,
270
- input: ["text", "image"],
271
- cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
272
- contextWindow: 200000,
273
- maxTokens: 16384,
274
- }],
275
- // Optional OAuth:
276
- oauth: {
277
- name: "My Provider (SSO)",
278
- async login(callbacks) { ... },
279
- async refreshToken(credentials) { ... },
280
- getApiKey(credentials) { return credentials.access; },
281
- },
282
- });
283
- ```
284
-
285
- Hiệu lực ngay lập tức sau `session_start` (không cần `/reload`).
286
-
287
- ## 7. API Comparison: ExtensionAPI vs ExtensionContext
288
-
289
- | Capability | `pi.*` (ExtensionAPI) | `ctx.*` (ExtensionContext) |
290
- |---|---|---|
291
- | Subscribe events | ✅ `pi.on(...)` | ❌ |
292
- | Register tools | ✅ `pi.registerTool()` | ❌ |
293
- | Register commands | ✅ `pi.registerCommand()` | ❌ |
294
- | Register shortcuts | ✅ `pi.registerShortcut()` | ❌ |
295
- | Register flags | ✅ `pi.registerFlag()` | ❌ |
296
- | Register providers | ✅ `pi.registerProvider()` | ❌ |
297
- | Send messages | ✅ `pi.sendMessage()` | ❌ |
298
- | Send user messages | ✅ `pi.sendUserMessage()` | ❌ |
299
- | Append entries | ✅ `pi.appendEntry()` | ❌ |
300
- | Session name | ✅ `pi.setSessionName()` / `getSessionName()` | ❌ |
301
- | Event bus | ✅ `pi.events` | ❌ |
302
- | Get/set active tools | ✅ `pi.getActiveTools()` / `setActiveTools()` | ❌ |
303
- | Get model | ❌ (register-time only) | ✅ `ctx.model` |
304
- | Check idle | ❌ | ✅ `ctx.isIdle()` |
305
- | Abort | ❌ | ✅ `ctx.abort()` |
306
- | Trigger compaction | ❌ | ✅ `ctx.compact()` |
307
- | Context usage | ❌ | ✅ `ctx.getContextUsage()` |
308
- | System prompt | ❌ | ✅ `ctx.getSystemPrompt()` |
309
- | Session manager | ❌ | ✅ `ctx.sessionManager` |
310
- | UI interaction | ❌ | ✅ `ctx.ui` |
311
- | Session control | ❌ | ✅ `ctx.newSession()` / `fork()` (command ctx) |
312
-
313
- **Rule of thumb:**
314
- - `pi.*`: Registration-time API (trong factory function, `session_start`)
315
- - `ctx.*`: Runtime API (trong event handlers, command handlers)
316
-
317
- ## 8. Key Design Decisions
318
-
319
- 1. **No sandbox** — Extensions run in same Node.js process, full system access
320
- 2. **jiti loader** — TypeScript extensions compiled JIT, no build step
321
- 3. **Virtual modules** — For Bun compiled binary, built-in dependencies bundled
322
- 4. **Throwing stubs** — Runtime actions start as stubs, real implementations bound by runner
323
- 5. **Stale detection** — After reload, old extension instances throw on any API call
324
- 6. **Event bus** — Separate from extension events, for cross-extension communication
1
+ # Research: Pi Extension System Deep Dive
2
+
3
+ > Ngày: 2026-04-29 | Read-only research | Source: `source/pi-mono/packages/coding-agent/src/core/extensions/`
4
+
5
+ ## 1. Extension System Architecture
6
+
7
+ Pi extension system là plugin framework cho coding agent. Extensions được viết bằng TypeScript,
8
+ load qua jiti (JIT compiler), và có thể hook vào mọi phase của agent lifecycle.
9
+
10
+ ```
11
+ ┌─────────────────────────────────────────────────────────────┐
12
+ │ ExtensionAPI ("pi.*") │
13
+ │ Event sub: pi.on(event, handler) │
14
+ │ Tools: pi.registerTool(def) │
15
+ │ Commands: pi.registerCommand(name, opts) │
16
+ │ Shortcuts: pi.registerShortcut(key, opts) │
17
+ │ Flags: pi.registerFlag(name, opts) │
18
+ │ Messages: pi.sendMessage() / pi.sendUserMessage() │
19
+ │ State: pi.appendEntry(customType, data) │
20
+ │ Provider: pi.registerProvider(name, config) │
21
+ │ Event bus: pi.events.emit/on() │
22
+ │ Model: pi.setModel() / getThinkingLevel() │
23
+ │ Tools mgmt: pi.getActiveTools() / setActiveTools() │
24
+ ├─────────────────────────────────────────────────────────────┤
25
+ │ ExtensionFactory │
26
+ │ (pi: ExtensionAPI) => void | Promise<void> │
27
+ ├─────────────────────────────────────────────────────────────┤
28
+ │ loader.ts ──► jiti → TypeScript module loading │
29
+ │ runner.ts ──► ExtensionRunner → lifecycle + event emit │
30
+ │ types.ts ───► 1545 dòng type definitions │
31
+ └─────────────────────────────────────────────────────────────┘
32
+ ```
33
+
34
+ ## 2. Extension Loading Flow
35
+
36
+ ```
37
+ discoverAndLoadExtensions(cwd, agentDir, extensionPaths)
38
+ ├── Scan directories:
39
+ │ ├── ~/.pi/agent/extensions/**/index.ts (user-global)
40
+ │ ├── .pi/extensions/**/index.ts (project-local)
41
+ │ └── CLI --extension paths (explicit)
42
+ ├── Create ExtensionRuntime (shared state + action stubs)
43
+ ├── For each extension file:
44
+ │ ├── jiti.import(path) # Load TS module
45
+ │ ├── Call default export: factory(pi) # Register handlers/tools/commands
46
+ │ └── Collect into Extension object
47
+ └── Return LoadExtensionsResult
48
+
49
+ ExtensionRunner.initialize(session, context, actions)
50
+ ├── Bind real action implementations to runtime
51
+ ├── Process queued provider registrations
52
+ └── Emit session_start event
53
+ ```
54
+
55
+ ### 2.1 Discovery priority
56
+
57
+ Project-local > user-global. Extensions cùng tên: project override user.
58
+
59
+ ### 2.2 Runtime replacement (reload)
60
+
61
+ Khi `/reload` hoặc session switch:
62
+ 1. `emitSessionShutdownEvent("reload")`
63
+ 2. Invalidate old ExtensionRuntime (throws if stale extension tries to act)
64
+ 3. Re-discover + re-load tất cả extensions
65
+ 4. Re-initialize ExtensionRunner
66
+
67
+ ## 3. Full Event Lifecycle
68
+
69
+ ### 3.1 Event model (23 event types)
70
+
71
+ **Session events** — session-level lifecycle:
72
+ ```
73
+ session_start ← Khi session được tạo/load/reload
74
+ resources_discover ← Extension có thể inject thêm paths
75
+ session_before_switch ← Trước khi switch session (có thể cancel)
76
+ session_before_fork ← Trước khi fork session (có thể cancel)
77
+ session_before_compact ← Trước khi compaction (có thể cancel hoặc custom)
78
+ session_compact ← Sau khi compaction hoàn tất
79
+ session_before_tree ← Trước khi navigate tree (có thể cancel)
80
+ session_tree ← Sau khi navigate tree
81
+ session_shutdown ← Khi session bị hủy (quit/reload/new/resume/fork)
82
+ ```
83
+
84
+ **Agent events** — per-prompt:
85
+ ```
86
+ input ← Khi user input received (có thể transform/block)
87
+ before_agent_start ← Trước khi agent loop chạy (inject custom message / swap system prompt)
88
+ context ← Transform messages trước khi gửi LLM
89
+ before_provider_request ← Thay đổi payload trước khi gửi provider
90
+ after_provider_response ← Quan sát response status/headers
91
+ agent_start ← Agent loop bắt đầu
92
+ agent_end ← Agent loop kết thúc
93
+ ```
94
+
95
+ **Turn events** — per-turn:
96
+ ```
97
+ turn_start ← Bắt đầu turn mới
98
+ turn_end ← Kết thúc turn (có message + tool results)
99
+ ```
100
+
101
+ **Message events** — per-message:
102
+ ```
103
+ message_start ← Message bắt đầu (user/assistant/toolResult)
104
+ message_update ← Streaming token-by-token update
105
+ message_end ← Message hoàn tất
106
+ ```
107
+
108
+ **Tool events** — per-tool:
109
+ ```
110
+ tool_call ← Trước khi tool execute (có thể block/mutate args)
111
+ tool_execution_start ← Tool bắt đầu chạy
112
+ tool_execution_update ← Partial/streaming result
113
+ tool_execution_end ← Tool hoàn tất
114
+ tool_result ← Sau khi tool execute (có thể modify result)
115
+ ```
116
+
117
+ **Other:**
118
+ ```
119
+ model_select ← Khi model được chọn/thay đổi
120
+ user_bash ← Khi user dùng ! prefix cho bash
121
+ ```
122
+
123
+ ### 3.2 Event result contracts
124
+
125
+ Mỗi event có thể return result để ảnh hưởng đến behavior:
126
+
127
+ | Event | Result type | Effect |
128
+ |---|---|---|
129
+ | `input` | `{ action: "continue" \| "transform" \| "handled" }` | Transform/block input |
130
+ | `before_agent_start` | `{ message?, systemPrompt? }` | Inject custom message, swap system prompt |
131
+ | `context` | `{ messages? }` | Replace context messages |
132
+ | `before_provider_request` | `any` | Replace payload |
133
+ | `tool_call` | `{ block?, reason? }` | Block tool execution |
134
+ | `tool_result` | `{ content?, details?, isError? }` | Modify result |
135
+ | `user_bash` | `{ operations?, result? }` | Custom bash execution |
136
+ | `session_before_*` | `{ cancel? }` | Cancel session operation |
137
+ | `session_before_compact` | `{ cancel?, compaction? }` | Cancel or custom compact |
138
+ | `session_before_tree` | `{ cancel?, summary?, customInstructions? }` | Cancel or custom summary |
139
+ | `resources_discover` | `{ skillPaths?, promptPaths?, themePaths? }` | Inject resource paths |
140
+
141
+ ## 4. Context Objects Available to Extensions
142
+
143
+ ### 4.1 ExtensionContext (`ctx.*`) — có sẵn trong mọi event handler
144
+
145
+ ```typescript
146
+ interface ExtensionContext {
147
+ ui: ExtensionUIContext; // UI methods (select, confirm, notify, widgets...)
148
+ hasUI: boolean; // false in print/RPC mode
149
+ cwd: string; // Current working directory
150
+ sessionManager: ReadonlySessionManager; // Session access (read-only)
151
+ modelRegistry: ModelRegistry; // Auth + model discovery
152
+ model: Model<any> | undefined; // Current model
153
+ isIdle(): boolean; // Check if agent is streaming
154
+ signal: AbortSignal | undefined;// Current abort signal
155
+ abort(): void; // Abort current operation
156
+ hasPendingMessages(): boolean; // Check message queue
157
+ shutdown(): void; // Graceful shutdown
158
+ getContextUsage(): ContextUsage | undefined; // Token usage
159
+ compact(options?): void; // Trigger compaction
160
+ getSystemPrompt(): string; // Current system prompt
161
+ }
162
+ ```
163
+
164
+ ### 4.2 ExtensionCommandContext — extends Context, chỉ trong command handler
165
+
166
+ ```typescript
167
+ interface ExtensionCommandContext extends ExtensionContext {
168
+ waitForIdle(): Promise<void>; // Wait for agent to finish
169
+ newSession(options?): Promise<{cancelled}>;
170
+ fork(entryId, options?): Promise<{cancelled}>;
171
+ navigateTree(targetId, options?): Promise<{cancelled}>;
172
+ switchSession(sessionPath, options?): Promise<{cancelled}>;
173
+ reload(): Promise<void>;
174
+ }
175
+ ```
176
+
177
+ ### 4.3 ReplacedSessionContext — sau khi switch/new session
178
+
179
+ ```typescript
180
+ interface ReplacedSessionContext extends ExtensionCommandContext {
181
+ sendMessage(message, options?): Promise<void>;
182
+ sendUserMessage(content, options?): Promise<void>;
183
+ }
184
+ ```
185
+
186
+ ### 4.4 ExtensionUIContext (`ctx.ui.*`) — chỉ khi `hasUI=true`
187
+
188
+ ```typescript
189
+ interface ExtensionUIContext {
190
+ select(title, options, opts?): Promise<string | undefined>;
191
+ confirm(title, message, opts?): Promise<boolean>;
192
+ input(title, placeholder?, opts?): Promise<string | undefined>;
193
+ notify(message, type?): void;
194
+ custom<T>(factory, options?): Promise<T>; // Custom overlay component
195
+ setWidget(key, content, options?): void; // Widget above/below editor
196
+ setFooter(factory): void; // Custom footer
197
+ setHeader(factory): void; // Custom header
198
+ setEditorComponent(factory): void; // Custom editor
199
+ setStatus(key, text): void; // Status bar
200
+ setTitle(title): void; // Terminal title
201
+ setWorkingMessage(message?): void; // Working loader text
202
+ setWorkingVisible(visible): void; // Show/hide loader
203
+ setWorkingIndicator(options?): void; // Custom loader animation
204
+ setHiddenThinkingLabel(label?): void; // Thinking block label
205
+ onTerminalInput(handler): () => void; // Raw terminal input
206
+ getToolsExpanded(): boolean;
207
+ setToolsExpanded(expanded): void;
208
+ theme: Theme;
209
+ getAllThemes(): {name, path}[];
210
+ getTheme(name): Theme | undefined;
211
+ setTheme(theme): {success, error?};
212
+ }
213
+ ```
214
+
215
+ ## 5. ToolDefinition Contract
216
+
217
+ ```typescript
218
+ interface ToolDefinition<TParams extends TSchema, TDetails = unknown, TState = any> {
219
+ name: string; // Unique tool name
220
+ label: string; // Human-readable for UI
221
+ description: string; // For LLM
222
+ parameters: TParams; // TypeBox schema
223
+ promptSnippet?: string; // 1-line for system prompt "Available tools"
224
+ promptGuidelines?: string[]; // Bullets for system prompt "Guidelines"
225
+ renderShell?: "default" | "self"; // Who renders the outer frame
226
+ executionMode?: "sequential" | "parallel"; // Concurrency control
227
+ prepareArguments?: (args: unknown) => Static<TParams>;
228
+
229
+ // Core execution
230
+ execute(
231
+ toolCallId: string,
232
+ params: Static<TParams>,
233
+ signal: AbortSignal | undefined,
234
+ onUpdate: AgentToolUpdateCallback<TDetails> | undefined,
235
+ ctx: ExtensionContext,
236
+ ): Promise<AgentToolResult<TDetails>>;
237
+
238
+ // Rendering (optional)
239
+ renderCall?(args, theme, context): Component; // Custom call display
240
+ renderResult?(result, options, theme, context): Component; // Custom result display
241
+ }
242
+ ```
243
+
244
+ ### 5.1 `terminate: true` pattern
245
+
246
+ Tool có thể set `terminate: true` trong result để kết thúc turn ngay sau tool call,
247
+ tiết kiệm 1 follow-up LLM turn:
248
+
249
+ ```typescript
250
+ return {
251
+ content: [{ type: "text", text: "Done" }],
252
+ details: { ... },
253
+ terminate: true, // ← Kết thúc turn, không cần LLM follow-up
254
+ };
255
+ ```
256
+
257
+ ## 6. Provider Registration
258
+
259
+ Extension có thể đăng ký provider tùy chỉnh:
260
+
261
+ ```typescript
262
+ pi.registerProvider("my-provider", {
263
+ baseUrl: "https://api.example.com",
264
+ apiKey: "PROVIDER_API_KEY",
265
+ api: "anthropic-messages",
266
+ models: [{
267
+ id: "my-model",
268
+ name: "My Model",
269
+ reasoning: false,
270
+ input: ["text", "image"],
271
+ cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
272
+ contextWindow: 200000,
273
+ maxTokens: 16384,
274
+ }],
275
+ // Optional OAuth:
276
+ oauth: {
277
+ name: "My Provider (SSO)",
278
+ async login(callbacks) { ... },
279
+ async refreshToken(credentials) { ... },
280
+ getApiKey(credentials) { return credentials.access; },
281
+ },
282
+ });
283
+ ```
284
+
285
+ Hiệu lực ngay lập tức sau `session_start` (không cần `/reload`).
286
+
287
+ ## 7. API Comparison: ExtensionAPI vs ExtensionContext
288
+
289
+ | Capability | `pi.*` (ExtensionAPI) | `ctx.*` (ExtensionContext) |
290
+ |---|---|---|
291
+ | Subscribe events | ✅ `pi.on(...)` | ❌ |
292
+ | Register tools | ✅ `pi.registerTool()` | ❌ |
293
+ | Register commands | ✅ `pi.registerCommand()` | ❌ |
294
+ | Register shortcuts | ✅ `pi.registerShortcut()` | ❌ |
295
+ | Register flags | ✅ `pi.registerFlag()` | ❌ |
296
+ | Register providers | ✅ `pi.registerProvider()` | ❌ |
297
+ | Send messages | ✅ `pi.sendMessage()` | ❌ |
298
+ | Send user messages | ✅ `pi.sendUserMessage()` | ❌ |
299
+ | Append entries | ✅ `pi.appendEntry()` | ❌ |
300
+ | Session name | ✅ `pi.setSessionName()` / `getSessionName()` | ❌ |
301
+ | Event bus | ✅ `pi.events` | ❌ |
302
+ | Get/set active tools | ✅ `pi.getActiveTools()` / `setActiveTools()` | ❌ |
303
+ | Get model | ❌ (register-time only) | ✅ `ctx.model` |
304
+ | Check idle | ❌ | ✅ `ctx.isIdle()` |
305
+ | Abort | ❌ | ✅ `ctx.abort()` |
306
+ | Trigger compaction | ❌ | ✅ `ctx.compact()` |
307
+ | Context usage | ❌ | ✅ `ctx.getContextUsage()` |
308
+ | System prompt | ❌ | ✅ `ctx.getSystemPrompt()` |
309
+ | Session manager | ❌ | ✅ `ctx.sessionManager` |
310
+ | UI interaction | ❌ | ✅ `ctx.ui` |
311
+ | Session control | ❌ | ✅ `ctx.newSession()` / `fork()` (command ctx) |
312
+
313
+ **Rule of thumb:**
314
+ - `pi.*`: Registration-time API (trong factory function, `session_start`)
315
+ - `ctx.*`: Runtime API (trong event handlers, command handlers)
316
+
317
+ ## 8. Key Design Decisions
318
+
319
+ 1. **No sandbox** — Extensions run in same Node.js process, full system access
320
+ 2. **jiti loader** — TypeScript extensions compiled JIT, no build step
321
+ 3. **Virtual modules** — For Bun compiled binary, built-in dependencies bundled
322
+ 4. **Throwing stubs** — Runtime actions start as stubs, real implementations bound by runner
323
+ 5. **Stale detection** — After reload, old extension instances throw on any API call
324
+ 6. **Event bus** — Separate from extension events, for cross-extension communication