@aliou/pi-dev-kit 0.6.5 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -2
- package/package.json +11 -10
- package/src/commands/index.ts +5 -1
- package/src/commands/update.ts +139 -91
- package/src/skills/pi-extension/SKILL.md +108 -137
- package/src/skills/pi-extension/references/additional-apis.md +252 -208
- package/src/skills/pi-extension/references/commands.md +113 -33
- package/src/skills/pi-extension/references/components.md +267 -102
- package/src/skills/pi-extension/references/hooks.md +229 -156
- package/src/skills/pi-extension/references/messages.md +94 -106
- package/src/skills/pi-extension/references/modes.md +80 -90
- package/src/skills/pi-extension/references/providers.md +255 -96
- package/src/skills/pi-extension/references/publish.md +76 -62
- package/src/skills/pi-extension/references/state.md +80 -33
- package/src/skills/pi-extension/references/structure.md +126 -269
- package/src/skills/pi-extension/references/testing.md +1 -1
- package/src/skills/pi-extension/references/tools.md +198 -823
- package/src/tools/changelog-tool.ts +15 -3
- package/src/tools/docs-tool.ts +3 -3
- package/src/tools/index.ts +5 -1
- package/src/tools/package-manager-tool.ts +8 -4
- package/src/tools/utils.ts +33 -23
- package/src/tools/version-tool.ts +8 -4
- package/src/index.ts +0 -8
|
@@ -1,345 +1,389 @@
|
|
|
1
1
|
# Additional APIs
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
When you implement something using one of these APIs, update this skill reference with a fuller example based on your actual usage.
|
|
3
|
+
This reference covers less common `ExtensionAPI`, `ExtensionContext`, and `ExtensionCommandContext` APIs.
|
|
6
4
|
|
|
7
5
|
## Shortcuts
|
|
8
6
|
|
|
9
|
-
Register
|
|
7
|
+
Register keyboard shortcuts for interactive mode.
|
|
10
8
|
|
|
11
9
|
```typescript
|
|
12
10
|
pi.registerShortcut("ctrl+shift+p", {
|
|
13
11
|
description: "Toggle plan mode",
|
|
14
12
|
handler: async (ctx) => {
|
|
15
13
|
planModeEnabled = !planModeEnabled;
|
|
16
|
-
ctx.ui.setStatus("plan", planModeEnabled ? "
|
|
14
|
+
ctx.ui.setStatus("plan-mode", planModeEnabled ? ctx.ui.theme.fg("accent", "Plan") : undefined);
|
|
17
15
|
},
|
|
18
16
|
});
|
|
19
17
|
```
|
|
20
18
|
|
|
21
|
-
Shortcuts
|
|
19
|
+
Shortcuts are TUI-only.
|
|
22
20
|
|
|
23
21
|
## Flags
|
|
24
22
|
|
|
25
|
-
Register
|
|
23
|
+
Register CLI flags and read them in any handler.
|
|
26
24
|
|
|
27
25
|
```typescript
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
26
|
+
pi.registerFlag("plan", {
|
|
27
|
+
description: "Start in plan mode",
|
|
28
|
+
type: "boolean",
|
|
31
29
|
default: false,
|
|
32
30
|
});
|
|
33
31
|
|
|
34
|
-
|
|
35
|
-
const autoCommit = pi.getFlag("auto-commit");
|
|
32
|
+
const planEnabled = pi.getFlag("plan") === true;
|
|
36
33
|
```
|
|
37
34
|
|
|
38
|
-
|
|
35
|
+
## Commands and Sessions
|
|
39
36
|
|
|
40
|
-
|
|
37
|
+
Command handlers receive `ExtensionCommandContext`, which adds session-control methods. These methods are command-only because they can deadlock from event handlers.
|
|
41
38
|
|
|
42
|
-
|
|
39
|
+
### Wait for idle
|
|
43
40
|
|
|
44
41
|
```typescript
|
|
45
|
-
pi.
|
|
42
|
+
pi.registerCommand("safe-command", {
|
|
43
|
+
handler: async (_args, ctx) => {
|
|
44
|
+
await ctx.waitForIdle();
|
|
45
|
+
// Safe to inspect or replace session state.
|
|
46
|
+
},
|
|
47
|
+
});
|
|
46
48
|
```
|
|
47
49
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
## Session Name
|
|
50
|
+
### New, fork, switch
|
|
51
51
|
|
|
52
|
-
|
|
52
|
+
Use `withSession` for post-replacement work. Captured old `pi`, old command `ctx`, and old `ctx.sessionManager` are stale after replacement.
|
|
53
53
|
|
|
54
54
|
```typescript
|
|
55
|
-
|
|
56
|
-
|
|
55
|
+
await ctx.newSession({
|
|
56
|
+
setup: async (sm) => {
|
|
57
|
+
sm.appendMessage({
|
|
58
|
+
role: "user",
|
|
59
|
+
content: [{ type: "text", text: "Seed context" }],
|
|
60
|
+
timestamp: Date.now(),
|
|
61
|
+
});
|
|
62
|
+
},
|
|
63
|
+
withSession: async (ctx) => {
|
|
64
|
+
await ctx.sendUserMessage("Continue from the new session");
|
|
65
|
+
},
|
|
66
|
+
});
|
|
57
67
|
```
|
|
58
68
|
|
|
59
|
-
|
|
69
|
+
```typescript
|
|
70
|
+
await ctx.fork(entryId, {
|
|
71
|
+
position: "at",
|
|
72
|
+
withSession: async (ctx) => ctx.ui.notify("Forked", "info"),
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
await ctx.switchSession(sessionPath, {
|
|
76
|
+
withSession: async (ctx) => {
|
|
77
|
+
await ctx.sendUserMessage("Resume this work here");
|
|
78
|
+
},
|
|
79
|
+
});
|
|
80
|
+
```
|
|
60
81
|
|
|
61
|
-
|
|
82
|
+
### Tree navigation
|
|
62
83
|
|
|
63
84
|
```typescript
|
|
64
|
-
|
|
85
|
+
await ctx.navigateTree(targetId, {
|
|
86
|
+
summarize: true,
|
|
87
|
+
customInstructions: "Focus on implementation decisions",
|
|
88
|
+
replaceInstructions: false,
|
|
89
|
+
label: "review-checkpoint",
|
|
90
|
+
});
|
|
65
91
|
```
|
|
66
92
|
|
|
67
|
-
##
|
|
93
|
+
## Reload
|
|
68
94
|
|
|
69
|
-
|
|
95
|
+
Use `ctx.reload()` in command handlers. Treat it as terminal for predictable behavior.
|
|
70
96
|
|
|
71
97
|
```typescript
|
|
72
|
-
|
|
73
|
-
|
|
98
|
+
pi.registerCommand("reload-runtime", {
|
|
99
|
+
description: "Reload extensions, skills, prompts, and themes",
|
|
100
|
+
handler: async (_args, ctx) => {
|
|
101
|
+
await ctx.reload();
|
|
102
|
+
return;
|
|
103
|
+
},
|
|
104
|
+
});
|
|
74
105
|
```
|
|
75
106
|
|
|
76
|
-
|
|
107
|
+
Code after `await ctx.reload()` still runs in the old call frame. Avoid post-reload work in that handler.
|
|
77
108
|
|
|
78
|
-
|
|
109
|
+
Tools cannot call `ctx.reload()`. If the LLM needs a reload tool, create a tool that queues a reload command as a follow-up user message.
|
|
79
110
|
|
|
80
|
-
|
|
111
|
+
```typescript
|
|
112
|
+
async execute() {
|
|
113
|
+
pi.sendUserMessage("/reload-runtime", { deliverAs: "followUp" });
|
|
114
|
+
return { content: [{ type: "text", text: "Queued /reload-runtime." }] };
|
|
115
|
+
}
|
|
116
|
+
```
|
|
81
117
|
|
|
82
|
-
##
|
|
118
|
+
## Sending Messages
|
|
119
|
+
|
|
120
|
+
### `pi.sendUserMessage(content, options?)`
|
|
83
121
|
|
|
84
|
-
|
|
122
|
+
Sends an actual user message and triggers a turn.
|
|
85
123
|
|
|
86
124
|
```typescript
|
|
87
|
-
|
|
88
|
-
pi.
|
|
125
|
+
pi.sendUserMessage("Summarize the current state.");
|
|
126
|
+
pi.sendUserMessage("Focus on tests next.", { deliverAs: "steer" });
|
|
127
|
+
pi.sendUserMessage("After that, summarize.", { deliverAs: "followUp" });
|
|
89
128
|
```
|
|
90
129
|
|
|
91
|
-
|
|
130
|
+
When the agent is streaming, specify `deliverAs: "steer"` or `"followUp"`.
|
|
92
131
|
|
|
93
|
-
|
|
132
|
+
### `pi.sendMessage(message, options?)`
|
|
133
|
+
|
|
134
|
+
Sends a custom message. Use `registerMessageRenderer` for custom display.
|
|
94
135
|
|
|
95
136
|
```typescript
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
}
|
|
137
|
+
pi.sendMessage(
|
|
138
|
+
{
|
|
139
|
+
customType: "my-extension-status",
|
|
140
|
+
content: "Status update",
|
|
141
|
+
display: true,
|
|
142
|
+
details: { status: "ok" },
|
|
143
|
+
},
|
|
144
|
+
{ deliverAs: "nextTurn" },
|
|
145
|
+
);
|
|
146
|
+
```
|
|
102
147
|
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
148
|
+
Delivery modes:
|
|
149
|
+
|
|
150
|
+
- `steer`: queue while streaming and deliver before next LLM call.
|
|
151
|
+
- `followUp`: wait until the agent finishes.
|
|
152
|
+
- `nextTurn`: save for the next user prompt.
|
|
153
|
+
|
|
154
|
+
## State and Session Metadata
|
|
155
|
+
|
|
156
|
+
```typescript
|
|
157
|
+
pi.appendEntry("my-extension-state", { enabled: true });
|
|
158
|
+
pi.setSessionName("Feature: auth refactor");
|
|
159
|
+
const name = pi.getSessionName();
|
|
160
|
+
pi.setLabel(entryId, "checkpoint-before-refactor");
|
|
161
|
+
pi.setLabel(entryId, undefined); // clear
|
|
106
162
|
```
|
|
107
163
|
|
|
108
|
-
|
|
164
|
+
Use labels for `/tree` bookmarks and session names for the session selector.
|
|
165
|
+
|
|
166
|
+
## Shell Execution
|
|
109
167
|
|
|
110
|
-
|
|
168
|
+
Use `pi.exec(command, args, options?)` for shell commands.
|
|
111
169
|
|
|
112
170
|
```typescript
|
|
113
|
-
pi.
|
|
114
|
-
|
|
115
|
-
|
|
171
|
+
const result = await pi.exec("git", ["status", "--porcelain"], {
|
|
172
|
+
cwd: ctx.cwd,
|
|
173
|
+
signal,
|
|
174
|
+
timeout: 5_000,
|
|
116
175
|
});
|
|
176
|
+
|
|
177
|
+
// result.stdout, result.stderr, result.code, result.killed
|
|
117
178
|
```
|
|
118
179
|
|
|
119
|
-
|
|
180
|
+
Do not use Node `child_process` APIs for normal command execution. The only exception is a documented long-lived streaming process with direct stdin/stdout needs that `pi.exec()` cannot support.
|
|
181
|
+
|
|
182
|
+
## Active Tools
|
|
183
|
+
|
|
184
|
+
```typescript
|
|
185
|
+
const active = pi.getActiveTools();
|
|
186
|
+
const all = pi.getAllTools();
|
|
187
|
+
const builtin = all.filter((tool) => tool.sourceInfo.source === "builtin");
|
|
120
188
|
|
|
121
|
-
|
|
189
|
+
pi.setActiveTools(["read", "grep", "find"]);
|
|
190
|
+
```
|
|
122
191
|
|
|
123
|
-
|
|
192
|
+
`pi.getAllTools()` includes built-in tools, SDK tools, and extension tools with `sourceInfo` provenance.
|
|
124
193
|
|
|
125
|
-
|
|
126
|
-
- Your extension adds a tool that competes with a natural bash fallback (e.g. a process manager, a CI watcher, a search tool)
|
|
127
|
-
- Correct usage depends on subtle conditions (alert flags, when-not-to-use, alert vs. poll)
|
|
128
|
-
- You have observed agents ignoring the tool or reaching for `bash` instead
|
|
194
|
+
## Model and Thinking Control
|
|
129
195
|
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
196
|
+
```typescript
|
|
197
|
+
const model = ctx.modelRegistry.find("anthropic", "claude-sonnet-4-5");
|
|
198
|
+
if (model) {
|
|
199
|
+
const success = await pi.setModel(model);
|
|
200
|
+
if (!success) ctx.ui.notify("No API key for this model", "error");
|
|
201
|
+
}
|
|
133
202
|
|
|
134
|
-
|
|
203
|
+
const level = pi.getThinkingLevel();
|
|
204
|
+
pi.setThinkingLevel("high");
|
|
205
|
+
```
|
|
135
206
|
|
|
136
|
-
|
|
207
|
+
Thinking levels are `"off"`, `"minimal"`, `"low"`, `"medium"`, `"high"`, and `"xhigh"`. Pi clamps unsupported levels to model capabilities.
|
|
137
208
|
|
|
138
|
-
|
|
209
|
+
## System Prompt Guidance
|
|
139
210
|
|
|
140
|
-
|
|
211
|
+
Prefer tool-level `promptSnippet` and `promptGuidelines` for simple guidance. Use `before_agent_start` only for dynamic or cross-tool guidance.
|
|
141
212
|
|
|
142
|
-
-
|
|
143
|
-
- **`promptGuidelines`** — Appended verbatim to the global "Guidelines" section. Use for a short list of usage rules that still make sense without extra tool-local context.
|
|
213
|
+
### Per-tool metadata
|
|
144
214
|
|
|
145
215
|
```typescript
|
|
146
|
-
const myTool = {
|
|
216
|
+
const myTool = defineTool({
|
|
147
217
|
name: "my_tool",
|
|
148
218
|
label: "My Tool",
|
|
149
219
|
description: "...",
|
|
150
|
-
promptSnippet: "Manage background
|
|
220
|
+
promptSnippet: "Manage background work without blocking the conversation.",
|
|
151
221
|
promptGuidelines: [
|
|
152
|
-
"Use my_tool for long-running commands instead of
|
|
153
|
-
"After starting my_tool, continue
|
|
222
|
+
"Use my_tool for long-running commands instead of shell backgrounding.",
|
|
223
|
+
"After starting my_tool, continue useful work instead of polling my_tool immediately.",
|
|
154
224
|
],
|
|
155
|
-
parameters
|
|
156
|
-
execute
|
|
157
|
-
|
|
225
|
+
parameters,
|
|
226
|
+
async execute() {
|
|
227
|
+
// ...
|
|
228
|
+
},
|
|
229
|
+
});
|
|
158
230
|
```
|
|
159
231
|
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
Because these bullets are merged into the shared global `Guidelines` section, avoid vague phrasing like `Use this tool...`. Name the exact tool (`my_tool`, `process`, `linkup_web_search`) so the bullet remains clear after injection.
|
|
163
|
-
|
|
164
|
-
#### Tier 2: System Prompt Hook (For Complex Cross-Tool Orchestration)
|
|
232
|
+
Every `promptGuidelines` bullet must name the exact tool because Pi injects bullets flat into the global Guidelines section.
|
|
165
233
|
|
|
166
|
-
|
|
167
|
-
- Guidance involves **cross-tool workflow instructions** (e.g. "use tool A, then tool B, then tool C")
|
|
168
|
-
- You need **dynamic context from config** (e.g. workspace names, team keys, feature flags)
|
|
169
|
-
- The per-tool metadata fields aren't expressive enough
|
|
170
|
-
|
|
171
|
-
**Structure: three files**
|
|
172
|
-
|
|
173
|
-
`src/guidance.ts` — the guidance text as a named export:
|
|
234
|
+
### System prompt hook
|
|
174
235
|
|
|
175
236
|
```typescript
|
|
176
237
|
export const MY_EXTENSION_GUIDANCE = `
|
|
177
238
|
## My Extension
|
|
178
239
|
|
|
179
|
-
Use
|
|
180
|
-
|
|
181
|
-
**Use \`my_tool\` when:**
|
|
182
|
-
- Situation A
|
|
183
|
-
- Situation B
|
|
184
|
-
|
|
185
|
-
**Use \`bash\` when:**
|
|
186
|
-
- You need the result immediately to proceed (quick commands that finish in seconds)
|
|
187
|
-
|
|
188
|
-
**Never do this:**
|
|
189
|
-
\`\`\`bash
|
|
190
|
-
workaround_command # loses observability
|
|
191
|
-
\`\`\`
|
|
192
|
-
|
|
193
|
-
**Do this instead:**
|
|
194
|
-
\`\`\`
|
|
195
|
-
my_tool({ action: "start", ... })
|
|
196
|
-
\`\`\`
|
|
240
|
+
Use \`my_tool\` when ...
|
|
241
|
+
Do not use bash workaround ...
|
|
197
242
|
`;
|
|
243
|
+
|
|
244
|
+
pi.on("before_agent_start", async (event) => {
|
|
245
|
+
if (!configLoader.getConfig().systemPromptGuidance) return;
|
|
246
|
+
return {
|
|
247
|
+
systemPrompt: `${event.systemPrompt}\n\n${MY_EXTENSION_GUIDANCE}`,
|
|
248
|
+
};
|
|
249
|
+
});
|
|
198
250
|
```
|
|
199
251
|
|
|
200
|
-
`
|
|
252
|
+
Use `event.systemPromptOptions` when you need structured prompt inputs such as selected tools, loaded skills, context files, and accumulated prompt guidelines.
|
|
201
253
|
|
|
202
|
-
|
|
203
|
-
import type { ExtensionAPI } from "@mariozechner/pi-coding-agent";
|
|
204
|
-
import { configLoader } from "../config";
|
|
205
|
-
import { MY_EXTENSION_GUIDANCE } from "../guidance";
|
|
254
|
+
## Compaction and Shutdown
|
|
206
255
|
|
|
207
|
-
|
|
208
|
-
pi.on("before_agent_start", async (event) => {
|
|
209
|
-
const config = configLoader.getConfig();
|
|
210
|
-
if (!config.systemPromptGuidance) return;
|
|
256
|
+
Use `ctx.compact()` to trigger compaction without awaiting the full operation.
|
|
211
257
|
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
}
|
|
258
|
+
```typescript
|
|
259
|
+
ctx.compact({
|
|
260
|
+
customInstructions: "Focus on recent code changes",
|
|
261
|
+
onComplete: (result) => ctx.ui.notify("Compaction complete", "info"),
|
|
262
|
+
onError: (error) => ctx.ui.notify(`Compaction failed: ${error.message}`, "error"),
|
|
263
|
+
});
|
|
217
264
|
```
|
|
218
265
|
|
|
219
|
-
`
|
|
266
|
+
Use `ctx.shutdown()` to request graceful shutdown.
|
|
220
267
|
|
|
221
268
|
```typescript
|
|
222
|
-
|
|
223
|
-
// ...
|
|
224
|
-
/** Inject tool guidance into the system prompt each turn. Default: true. */
|
|
225
|
-
systemPromptGuidance?: boolean;
|
|
226
|
-
}
|
|
269
|
+
ctx.shutdown();
|
|
227
270
|
```
|
|
228
271
|
|
|
229
|
-
|
|
272
|
+
In interactive and RPC modes, shutdown is deferred until Pi becomes idle. In print mode it is a no-op.
|
|
230
273
|
|
|
231
|
-
|
|
274
|
+
## Event Bus
|
|
232
275
|
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
- Lead with the decision rule: **when to use AND when not to use**. The when-not-to-use is as important — it gives the agent permission to keep using `bash` for quick tasks and prevents overcorrection.
|
|
236
|
-
- Name anti-patterns explicitly by their exact form (`cmd &`, `nohup`, `sleep 30 &&`). Abstract descriptions ("don't use bash workarounds") are ignored.
|
|
237
|
-
- Use 2–3 tight code examples. More than that dilutes attention; fewer leave the pattern underspecified.
|
|
238
|
-
- Keep the guidance section header (`## My Extension`) so it reads as a named capability, not a restriction.
|
|
239
|
-
- Avoid stacking emphasis markers (`NEVER`, `ALWAYS`, `IMPORTANT`). One or two land; more are ignored.
|
|
240
|
-
|
|
241
|
-
**Reference implementations:**
|
|
242
|
-
- `pi-linkup` — Uses per-tool `promptSnippet`/`promptGuidelines` (simple tools, no hook needed).
|
|
243
|
-
- `pi-linear` — Uses `guidance.ts` + `before_agent_start` hook (cross-tool workflow instructions + dynamic workspace context).
|
|
244
|
-
- `pi-processes` — Uses both: `promptSnippet`/`promptGuidelines` on tools for basic guidance, plus system prompt hook for complex multi-tool orchestration patterns.
|
|
245
|
-
|
|
246
|
-
## Session Replacement
|
|
247
|
-
|
|
248
|
-
`ctx.newSession()`, `ctx.fork()`, and `ctx.switchSession()` invalidate captured pre-replacement session-bound objects after the replacement. Use `withSession` for post-switch work and only use the fresh callback context there.
|
|
276
|
+
Use the shared event bus only when extensions need to coordinate.
|
|
249
277
|
|
|
250
278
|
```typescript
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
},
|
|
255
|
-
withSession: async (ctx) => {
|
|
256
|
-
await ctx.sendUserMessage("Continue from the new session");
|
|
257
|
-
},
|
|
279
|
+
pi.events.emit("my-extension:data-ready", { items });
|
|
280
|
+
pi.events.on("my-extension:data-ready", (data) => {
|
|
281
|
+
console.log(data.items.length);
|
|
258
282
|
});
|
|
259
283
|
```
|
|
260
284
|
|
|
261
|
-
|
|
285
|
+
Namespace event names with your extension name.
|
|
262
286
|
|
|
263
|
-
##
|
|
287
|
+
## UI Customization
|
|
264
288
|
|
|
265
|
-
|
|
289
|
+
### Working indicator and message
|
|
266
290
|
|
|
267
291
|
```typescript
|
|
268
|
-
|
|
269
|
-
|
|
292
|
+
ctx.ui.setWorkingMessage("Thinking through plan...");
|
|
293
|
+
ctx.ui.setWorkingMessage(); // restore default
|
|
270
294
|
|
|
271
|
-
|
|
295
|
+
ctx.ui.setWorkingVisible(false);
|
|
296
|
+
ctx.ui.setWorkingVisible(true);
|
|
272
297
|
|
|
273
|
-
|
|
298
|
+
ctx.ui.setWorkingIndicator({ frames: [ctx.ui.theme.fg("accent", "●")] });
|
|
299
|
+
ctx.ui.setWorkingIndicator({ frames: [] }); // hide indicator
|
|
300
|
+
ctx.ui.setWorkingIndicator(); // restore default
|
|
301
|
+
```
|
|
302
|
+
|
|
303
|
+
### Widgets, title, editor text
|
|
274
304
|
|
|
275
305
|
```typescript
|
|
276
|
-
|
|
306
|
+
ctx.ui.setWidget("my-widget", ["Line 1", "Line 2"]);
|
|
307
|
+
ctx.ui.setWidget("my-widget", ["Below"], { placement: "belowEditor" });
|
|
308
|
+
ctx.ui.setWidget("my-widget", undefined);
|
|
309
|
+
|
|
310
|
+
ctx.ui.setTitle("pi - my project");
|
|
311
|
+
ctx.ui.setEditorText("Prefilled prompt");
|
|
312
|
+
const editorText = ctx.ui.getEditorText();
|
|
313
|
+
ctx.ui.pasteToEditor("Pasted content");
|
|
277
314
|
```
|
|
278
315
|
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
Inter-extension communication via a shared event bus:
|
|
316
|
+
### Footer
|
|
282
317
|
|
|
283
318
|
```typescript
|
|
284
|
-
|
|
285
|
-
|
|
319
|
+
ctx.ui.setFooter((tui, theme, footerData) => ({
|
|
320
|
+
invalidate() {},
|
|
321
|
+
render(width) {
|
|
322
|
+
return [theme.fg("dim", footerData.getGitBranch() ?? "no git")];
|
|
323
|
+
},
|
|
324
|
+
dispose: footerData.onBranchChange(() => tui.requestRender()),
|
|
325
|
+
}));
|
|
286
326
|
|
|
287
|
-
|
|
288
|
-
pi.events.on("my-extension:data-ready", (data) => {
|
|
289
|
-
console.log("Received:", data.items.length, "items");
|
|
290
|
-
});
|
|
327
|
+
ctx.ui.setFooter(undefined);
|
|
291
328
|
```
|
|
292
329
|
|
|
293
|
-
|
|
330
|
+
### Autocomplete providers
|
|
294
331
|
|
|
295
|
-
|
|
332
|
+
Stack on top of the current provider and delegate when your syntax does not match.
|
|
296
333
|
|
|
297
334
|
```typescript
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
const
|
|
335
|
+
ctx.ui.addAutocompleteProvider((current) => ({
|
|
336
|
+
async getSuggestions(lines, cursorLine, cursorCol, options) {
|
|
337
|
+
const beforeCursor = (lines[cursorLine] ?? "").slice(0, cursorCol);
|
|
338
|
+
const match = beforeCursor.match(/(?:^|[ \t])#([^\s#]*)$/);
|
|
339
|
+
if (!match) return current.getSuggestions(lines, cursorLine, cursorCol, options);
|
|
301
340
|
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
341
|
+
return {
|
|
342
|
+
prefix: `#${match[1] ?? ""}`,
|
|
343
|
+
items: [{ value: "#123", label: "#123", description: "Issue title" }],
|
|
344
|
+
};
|
|
345
|
+
},
|
|
346
|
+
applyCompletion(lines, cursorLine, cursorCol, item, prefix) {
|
|
347
|
+
return current.applyCompletion(lines, cursorLine, cursorCol, item, prefix);
|
|
348
|
+
},
|
|
349
|
+
shouldTriggerFileCompletion(lines, cursorLine, cursorCol) {
|
|
350
|
+
return current.shouldTriggerFileCompletion?.(lines, cursorLine, cursorCol) ?? true;
|
|
351
|
+
},
|
|
352
|
+
}));
|
|
305
353
|
```
|
|
306
354
|
|
|
307
|
-
|
|
355
|
+
### Theme control
|
|
308
356
|
|
|
309
357
|
```typescript
|
|
310
|
-
|
|
311
|
-
ctx.ui.
|
|
312
|
-
|
|
313
|
-
|
|
358
|
+
const themes = ctx.ui.getAllThemes();
|
|
359
|
+
const light = ctx.ui.getTheme("light");
|
|
360
|
+
const result = ctx.ui.setTheme("light");
|
|
361
|
+
if (!result.success) ctx.ui.notify(result.error, "error");
|
|
362
|
+
```
|
|
314
363
|
|
|
315
|
-
|
|
316
|
-
ctx.ui.setHeader((maxWidth, theme) => {
|
|
317
|
-
return theme.fg("accent", "My Custom Header");
|
|
318
|
-
});
|
|
364
|
+
## Pi Paths
|
|
319
365
|
|
|
320
|
-
|
|
321
|
-
ctx.ui.setEditorComponent((tui, theme, kb) => {
|
|
322
|
-
return new CustomEditor(tui, theme, kb);
|
|
323
|
-
});
|
|
366
|
+
Use SDK helpers for Pi paths instead of `homedir()` when helpers exist. They respect `PI_CODING_AGENT_DIR` and test/custom setups.
|
|
324
367
|
|
|
325
|
-
|
|
326
|
-
ctx.ui.setEditorText("Prefilled content");
|
|
368
|
+
Common helpers exported from the main package include:
|
|
327
369
|
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
370
|
+
- `getAgentDir()`
|
|
371
|
+
- `getSettingsPath()`
|
|
372
|
+
- `getSessionsDir()`
|
|
373
|
+
- `getPromptsDir()`
|
|
374
|
+
- `getToolsDir()`
|
|
375
|
+
- `getCustomThemesDir()`
|
|
376
|
+
- `getModelsPath()`
|
|
377
|
+
- `getAuthPath()`
|
|
378
|
+
- `getBinDir()`
|
|
379
|
+
- `getDebugLogPath()`
|
|
332
380
|
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
return current.shouldTriggerFileCompletion?.(input) ?? false;
|
|
343
|
-
},
|
|
344
|
-
}));
|
|
345
|
-
```
|
|
381
|
+
## Checklist
|
|
382
|
+
|
|
383
|
+
- [ ] Session replacement code uses `withSession` for post-switch work.
|
|
384
|
+
- [ ] Reload handlers return immediately after `await ctx.reload()`.
|
|
385
|
+
- [ ] `pi.exec()` is used instead of `child_process`.
|
|
386
|
+
- [ ] System prompt changes return `{ systemPrompt }` from `before_agent_start`.
|
|
387
|
+
- [ ] `promptGuidelines` bullets name exact tools.
|
|
388
|
+
- [ ] UI customizations account for RPC/print degradation.
|
|
389
|
+
- [ ] Pi path helpers are used instead of `homedir()`.
|