gsd-pi 2.28.0-dev.e19bf89 → 2.29.0-dev.2ccf3fb
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 +24 -17
- package/dist/cli.js +15 -9
- package/dist/resource-loader.js +80 -8
- package/dist/resources/extensions/bg-shell/process-manager.ts +13 -0
- package/dist/resources/extensions/gsd/auto-dashboard.ts +186 -65
- package/dist/resources/extensions/gsd/auto-post-unit.ts +14 -6
- package/dist/resources/extensions/gsd/auto-recovery.ts +33 -23
- package/dist/resources/extensions/gsd/auto-start.ts +25 -10
- package/dist/resources/extensions/gsd/auto-verification.ts +41 -7
- package/dist/resources/extensions/gsd/auto-worktree-sync.ts +21 -6
- package/dist/resources/extensions/gsd/auto.ts +67 -22
- package/dist/resources/extensions/gsd/commands-handlers.ts +3 -11
- package/dist/resources/extensions/gsd/commands-logs.ts +536 -0
- package/dist/resources/extensions/gsd/commands-prefs-wizard.ts +90 -47
- package/dist/resources/extensions/gsd/commands-workflow-templates.ts +544 -0
- package/dist/resources/extensions/gsd/commands.ts +75 -29
- package/dist/resources/extensions/gsd/dashboard-overlay.ts +2 -1
- package/dist/resources/extensions/gsd/doctor-types.ts +13 -0
- package/dist/resources/extensions/gsd/doctor.ts +2 -6
- package/dist/resources/extensions/gsd/export.ts +28 -2
- package/dist/resources/extensions/gsd/gsd-db.ts +19 -0
- package/dist/resources/extensions/gsd/index.ts +2 -1
- package/dist/resources/extensions/gsd/json-persistence.ts +67 -0
- package/dist/resources/extensions/gsd/metrics.ts +17 -31
- package/dist/resources/extensions/gsd/paths.ts +0 -8
- package/dist/resources/extensions/gsd/prompts/guided-discuss-milestone.md +1 -1
- package/dist/resources/extensions/gsd/prompts/workflow-start.md +28 -0
- package/dist/resources/extensions/gsd/queue-order.ts +10 -11
- package/dist/resources/extensions/gsd/routing-history.ts +13 -17
- package/dist/resources/extensions/gsd/session-lock.ts +284 -0
- package/dist/resources/extensions/gsd/session-status-io.ts +23 -41
- package/dist/resources/extensions/gsd/tests/auto-budget-alerts.test.ts +1 -1
- package/dist/resources/extensions/gsd/tests/auto-skip-loop.test.ts +1 -1
- package/dist/resources/extensions/gsd/tests/commands-logs.test.ts +241 -0
- package/dist/resources/extensions/gsd/tests/extension-selector-separator.test.ts +60 -38
- package/dist/resources/extensions/gsd/tests/gsd-inspect.test.ts +1 -1
- package/dist/resources/extensions/gsd/tests/parallel-workers-multi-milestone-e2e.test.ts +1 -1
- package/dist/resources/extensions/gsd/tests/session-lock.test.ts +315 -0
- package/dist/resources/extensions/gsd/tests/validate-milestone.test.ts +55 -0
- package/dist/resources/extensions/gsd/tests/verification-evidence.test.ts +26 -24
- package/dist/resources/extensions/gsd/tests/verification-gate.test.ts +136 -7
- package/dist/resources/extensions/gsd/tests/workflow-templates.test.ts +173 -0
- package/dist/resources/extensions/gsd/types.ts +1 -0
- package/dist/resources/extensions/gsd/unit-runtime.ts +16 -13
- package/dist/resources/extensions/gsd/verification-evidence.ts +2 -0
- package/dist/resources/extensions/gsd/verification-gate.ts +13 -2
- package/dist/resources/extensions/gsd/workflow-templates/bugfix.md +87 -0
- package/dist/resources/extensions/gsd/workflow-templates/dep-upgrade.md +74 -0
- package/dist/resources/extensions/gsd/workflow-templates/full-project.md +41 -0
- package/dist/resources/extensions/gsd/workflow-templates/hotfix.md +45 -0
- package/dist/resources/extensions/gsd/workflow-templates/refactor.md +83 -0
- package/dist/resources/extensions/gsd/workflow-templates/registry.json +85 -0
- package/dist/resources/extensions/gsd/workflow-templates/security-audit.md +73 -0
- package/dist/resources/extensions/gsd/workflow-templates/small-feature.md +81 -0
- package/dist/resources/extensions/gsd/workflow-templates/spike.md +69 -0
- package/dist/resources/extensions/gsd/workflow-templates.ts +241 -0
- package/dist/resources/extensions/mcp-client/index.ts +459 -0
- package/dist/resources/extensions/remote-questions/discord-adapter.ts +9 -20
- package/dist/resources/extensions/remote-questions/http-client.ts +76 -0
- package/dist/resources/extensions/remote-questions/notify.ts +1 -2
- package/dist/resources/extensions/remote-questions/slack-adapter.ts +11 -18
- package/dist/resources/extensions/remote-questions/telegram-adapter.ts +8 -20
- package/dist/resources/extensions/remote-questions/types.ts +3 -0
- package/dist/resources/extensions/shared/mod.ts +3 -0
- package/dist/resources/skills/create-gsd-extension/SKILL.md +87 -0
- package/dist/resources/skills/create-gsd-extension/references/compaction-session-control.md +77 -0
- package/dist/resources/skills/create-gsd-extension/references/custom-commands.md +139 -0
- package/dist/resources/skills/create-gsd-extension/references/custom-rendering.md +108 -0
- package/dist/resources/skills/create-gsd-extension/references/custom-tools.md +183 -0
- package/dist/resources/skills/create-gsd-extension/references/custom-ui.md +490 -0
- package/dist/resources/skills/create-gsd-extension/references/events-reference.md +126 -0
- package/dist/resources/skills/create-gsd-extension/references/extension-lifecycle.md +64 -0
- package/dist/resources/skills/create-gsd-extension/references/extensionapi-reference.md +75 -0
- package/dist/resources/skills/create-gsd-extension/references/extensioncontext-reference.md +53 -0
- package/dist/resources/skills/create-gsd-extension/references/key-rules-gotchas.md +36 -0
- package/dist/resources/skills/create-gsd-extension/references/mode-behavior.md +32 -0
- package/dist/resources/skills/create-gsd-extension/references/model-provider-management.md +89 -0
- package/dist/resources/skills/create-gsd-extension/references/packaging-distribution.md +55 -0
- package/dist/resources/skills/create-gsd-extension/references/remote-execution-overrides.md +90 -0
- package/dist/resources/skills/create-gsd-extension/references/state-management.md +70 -0
- package/dist/resources/skills/create-gsd-extension/references/system-prompt-modification.md +52 -0
- package/dist/resources/skills/create-gsd-extension/templates/extension-skeleton.ts +51 -0
- package/dist/resources/skills/create-gsd-extension/templates/stateful-tool-skeleton.ts +143 -0
- package/dist/resources/skills/create-gsd-extension/workflows/add-capability.md +57 -0
- package/dist/resources/skills/create-gsd-extension/workflows/create-extension.md +156 -0
- package/dist/resources/skills/create-gsd-extension/workflows/debug-extension.md +74 -0
- package/dist/resources/skills/create-skill/SKILL.md +184 -0
- package/dist/resources/skills/create-skill/references/api-security.md +226 -0
- package/dist/resources/skills/create-skill/references/be-clear-and-direct.md +531 -0
- package/dist/resources/skills/create-skill/references/common-patterns.md +595 -0
- package/dist/resources/skills/create-skill/references/core-principles.md +437 -0
- package/dist/resources/skills/create-skill/references/executable-code.md +175 -0
- package/dist/resources/skills/create-skill/references/gsd-skill-ecosystem.md +68 -0
- package/dist/resources/skills/create-skill/references/iteration-and-testing.md +474 -0
- package/dist/resources/skills/create-skill/references/recommended-structure.md +168 -0
- package/dist/resources/skills/create-skill/references/skill-structure.md +372 -0
- package/dist/resources/skills/create-skill/references/use-xml-tags.md +466 -0
- package/dist/resources/skills/create-skill/references/using-scripts.md +113 -0
- package/dist/resources/skills/create-skill/references/using-templates.md +112 -0
- package/dist/resources/skills/create-skill/references/workflows-and-validation.md +510 -0
- package/dist/resources/skills/create-skill/templates/router-skill.md +73 -0
- package/dist/resources/skills/create-skill/templates/simple-skill.md +33 -0
- package/dist/resources/skills/create-skill/workflows/add-reference.md +96 -0
- package/dist/resources/skills/create-skill/workflows/add-script.md +93 -0
- package/dist/resources/skills/create-skill/workflows/add-template.md +74 -0
- package/dist/resources/skills/create-skill/workflows/add-workflow.md +120 -0
- package/dist/resources/skills/create-skill/workflows/audit-skill.md +148 -0
- package/dist/resources/skills/create-skill/workflows/create-new-skill.md +196 -0
- package/dist/resources/skills/create-skill/workflows/get-guidance.md +121 -0
- package/dist/resources/skills/create-skill/workflows/upgrade-to-router.md +161 -0
- package/dist/resources/skills/create-skill/workflows/verify-skill.md +204 -0
- package/package.json +6 -3
- package/packages/native/dist/native.d.ts +2 -0
- package/packages/native/dist/native.js +19 -5
- package/packages/native/src/native.ts +23 -9
- package/packages/pi-coding-agent/dist/core/extensions/loader.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/extensions/loader.js +13 -0
- package/packages/pi-coding-agent/dist/core/extensions/loader.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/settings-manager.d.ts +3 -0
- package/packages/pi-coding-agent/dist/core/settings-manager.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/settings-manager.js +8 -0
- package/packages/pi-coding-agent/dist/core/settings-manager.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/system-prompt.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/system-prompt.js +10 -0
- package/packages/pi-coding-agent/dist/core/system-prompt.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js +4 -1
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/packages/pi-coding-agent/package.json +1 -1
- package/packages/pi-coding-agent/scripts/copy-assets.cjs +39 -8
- package/packages/pi-coding-agent/src/core/extensions/loader.ts +13 -0
- package/packages/pi-coding-agent/src/core/settings-manager.ts +11 -0
- package/packages/pi-coding-agent/src/core/system-prompt.ts +11 -0
- package/packages/pi-coding-agent/src/modes/interactive/interactive-mode.ts +4 -1
- package/packages/pi-tui/dist/autocomplete.d.ts +3 -0
- package/packages/pi-tui/dist/autocomplete.d.ts.map +1 -1
- package/packages/pi-tui/dist/autocomplete.js +14 -0
- package/packages/pi-tui/dist/autocomplete.js.map +1 -1
- package/packages/pi-tui/src/autocomplete.ts +19 -1
- package/pkg/package.json +1 -1
- package/src/resources/extensions/bg-shell/process-manager.ts +13 -0
- package/src/resources/extensions/gsd/auto-dashboard.ts +186 -65
- package/src/resources/extensions/gsd/auto-post-unit.ts +14 -6
- package/src/resources/extensions/gsd/auto-recovery.ts +33 -23
- package/src/resources/extensions/gsd/auto-start.ts +25 -10
- package/src/resources/extensions/gsd/auto-verification.ts +41 -7
- package/src/resources/extensions/gsd/auto-worktree-sync.ts +21 -6
- package/src/resources/extensions/gsd/auto.ts +67 -22
- package/src/resources/extensions/gsd/commands-handlers.ts +3 -11
- package/src/resources/extensions/gsd/commands-logs.ts +536 -0
- package/src/resources/extensions/gsd/commands-prefs-wizard.ts +90 -47
- package/src/resources/extensions/gsd/commands-workflow-templates.ts +544 -0
- package/src/resources/extensions/gsd/commands.ts +75 -29
- package/src/resources/extensions/gsd/dashboard-overlay.ts +2 -1
- package/src/resources/extensions/gsd/doctor-types.ts +13 -0
- package/src/resources/extensions/gsd/doctor.ts +2 -6
- package/src/resources/extensions/gsd/export.ts +28 -2
- package/src/resources/extensions/gsd/gsd-db.ts +19 -0
- package/src/resources/extensions/gsd/index.ts +2 -1
- package/src/resources/extensions/gsd/json-persistence.ts +67 -0
- package/src/resources/extensions/gsd/metrics.ts +17 -31
- package/src/resources/extensions/gsd/paths.ts +0 -8
- package/src/resources/extensions/gsd/prompts/guided-discuss-milestone.md +1 -1
- package/src/resources/extensions/gsd/prompts/workflow-start.md +28 -0
- package/src/resources/extensions/gsd/queue-order.ts +10 -11
- package/src/resources/extensions/gsd/routing-history.ts +13 -17
- package/src/resources/extensions/gsd/session-lock.ts +284 -0
- package/src/resources/extensions/gsd/session-status-io.ts +23 -41
- package/src/resources/extensions/gsd/tests/auto-budget-alerts.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/auto-skip-loop.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/commands-logs.test.ts +241 -0
- package/src/resources/extensions/gsd/tests/extension-selector-separator.test.ts +60 -38
- package/src/resources/extensions/gsd/tests/gsd-inspect.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/parallel-workers-multi-milestone-e2e.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/session-lock.test.ts +315 -0
- package/src/resources/extensions/gsd/tests/validate-milestone.test.ts +55 -0
- package/src/resources/extensions/gsd/tests/verification-evidence.test.ts +26 -24
- package/src/resources/extensions/gsd/tests/verification-gate.test.ts +136 -7
- package/src/resources/extensions/gsd/tests/workflow-templates.test.ts +173 -0
- package/src/resources/extensions/gsd/types.ts +1 -0
- package/src/resources/extensions/gsd/unit-runtime.ts +16 -13
- package/src/resources/extensions/gsd/verification-evidence.ts +2 -0
- package/src/resources/extensions/gsd/verification-gate.ts +13 -2
- package/src/resources/extensions/gsd/workflow-templates/bugfix.md +87 -0
- package/src/resources/extensions/gsd/workflow-templates/dep-upgrade.md +74 -0
- package/src/resources/extensions/gsd/workflow-templates/full-project.md +41 -0
- package/src/resources/extensions/gsd/workflow-templates/hotfix.md +45 -0
- package/src/resources/extensions/gsd/workflow-templates/refactor.md +83 -0
- package/src/resources/extensions/gsd/workflow-templates/registry.json +85 -0
- package/src/resources/extensions/gsd/workflow-templates/security-audit.md +73 -0
- package/src/resources/extensions/gsd/workflow-templates/small-feature.md +81 -0
- package/src/resources/extensions/gsd/workflow-templates/spike.md +69 -0
- package/src/resources/extensions/gsd/workflow-templates.ts +241 -0
- package/src/resources/extensions/mcp-client/index.ts +459 -0
- package/src/resources/extensions/remote-questions/discord-adapter.ts +9 -20
- package/src/resources/extensions/remote-questions/http-client.ts +76 -0
- package/src/resources/extensions/remote-questions/notify.ts +1 -2
- package/src/resources/extensions/remote-questions/slack-adapter.ts +11 -18
- package/src/resources/extensions/remote-questions/telegram-adapter.ts +8 -20
- package/src/resources/extensions/remote-questions/types.ts +3 -0
- package/src/resources/extensions/shared/mod.ts +3 -0
- package/src/resources/skills/create-gsd-extension/SKILL.md +87 -0
- package/src/resources/skills/create-gsd-extension/references/compaction-session-control.md +77 -0
- package/src/resources/skills/create-gsd-extension/references/custom-commands.md +139 -0
- package/src/resources/skills/create-gsd-extension/references/custom-rendering.md +108 -0
- package/src/resources/skills/create-gsd-extension/references/custom-tools.md +183 -0
- package/src/resources/skills/create-gsd-extension/references/custom-ui.md +490 -0
- package/src/resources/skills/create-gsd-extension/references/events-reference.md +126 -0
- package/src/resources/skills/create-gsd-extension/references/extension-lifecycle.md +64 -0
- package/src/resources/skills/create-gsd-extension/references/extensionapi-reference.md +75 -0
- package/src/resources/skills/create-gsd-extension/references/extensioncontext-reference.md +53 -0
- package/src/resources/skills/create-gsd-extension/references/key-rules-gotchas.md +36 -0
- package/src/resources/skills/create-gsd-extension/references/mode-behavior.md +32 -0
- package/src/resources/skills/create-gsd-extension/references/model-provider-management.md +89 -0
- package/src/resources/skills/create-gsd-extension/references/packaging-distribution.md +55 -0
- package/src/resources/skills/create-gsd-extension/references/remote-execution-overrides.md +90 -0
- package/src/resources/skills/create-gsd-extension/references/state-management.md +70 -0
- package/src/resources/skills/create-gsd-extension/references/system-prompt-modification.md +52 -0
- package/src/resources/skills/create-gsd-extension/templates/extension-skeleton.ts +51 -0
- package/src/resources/skills/create-gsd-extension/templates/stateful-tool-skeleton.ts +143 -0
- package/src/resources/skills/create-gsd-extension/workflows/add-capability.md +57 -0
- package/src/resources/skills/create-gsd-extension/workflows/create-extension.md +156 -0
- package/src/resources/skills/create-gsd-extension/workflows/debug-extension.md +74 -0
- package/src/resources/skills/create-skill/SKILL.md +184 -0
- package/src/resources/skills/create-skill/references/api-security.md +226 -0
- package/src/resources/skills/create-skill/references/be-clear-and-direct.md +531 -0
- package/src/resources/skills/create-skill/references/common-patterns.md +595 -0
- package/src/resources/skills/create-skill/references/core-principles.md +437 -0
- package/src/resources/skills/create-skill/references/executable-code.md +175 -0
- package/src/resources/skills/create-skill/references/gsd-skill-ecosystem.md +68 -0
- package/src/resources/skills/create-skill/references/iteration-and-testing.md +474 -0
- package/src/resources/skills/create-skill/references/recommended-structure.md +168 -0
- package/src/resources/skills/create-skill/references/skill-structure.md +372 -0
- package/src/resources/skills/create-skill/references/use-xml-tags.md +466 -0
- package/src/resources/skills/create-skill/references/using-scripts.md +113 -0
- package/src/resources/skills/create-skill/references/using-templates.md +112 -0
- package/src/resources/skills/create-skill/references/workflows-and-validation.md +510 -0
- package/src/resources/skills/create-skill/templates/router-skill.md +73 -0
- package/src/resources/skills/create-skill/templates/simple-skill.md +33 -0
- package/src/resources/skills/create-skill/workflows/add-reference.md +96 -0
- package/src/resources/skills/create-skill/workflows/add-script.md +93 -0
- package/src/resources/skills/create-skill/workflows/add-template.md +74 -0
- package/src/resources/skills/create-skill/workflows/add-workflow.md +120 -0
- package/src/resources/skills/create-skill/workflows/audit-skill.md +148 -0
- package/src/resources/skills/create-skill/workflows/create-new-skill.md +196 -0
- package/src/resources/skills/create-skill/workflows/get-guidance.md +121 -0
- package/src/resources/skills/create-skill/workflows/upgrade-to-router.md +161 -0
- package/src/resources/skills/create-skill/workflows/verify-skill.md +204 -0
- package/dist/resources/extensions/gsd/preferences-hooks.ts +0 -10
- package/dist/resources/extensions/mcporter/index.ts +0 -525
- package/dist/resources/extensions/shared/progress-widget.ts +0 -282
- package/dist/resources/extensions/shared/thinking-widget.ts +0 -107
- package/src/resources/extensions/gsd/preferences-hooks.ts +0 -10
- package/src/resources/extensions/mcporter/index.ts +0 -525
- package/src/resources/extensions/shared/progress-widget.ts +0 -282
- package/src/resources/extensions/shared/thinking-widget.ts +0 -107
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
<overview>
|
|
2
|
+
State management patterns for extensions — tool result details (branch-safe) and appendEntry (private).
|
|
3
|
+
</overview>
|
|
4
|
+
|
|
5
|
+
<tool_result_details>
|
|
6
|
+
**Recommended for stateful tools.** State in `details` works correctly with branching/forking.
|
|
7
|
+
|
|
8
|
+
```typescript
|
|
9
|
+
export default function (pi: ExtensionAPI) {
|
|
10
|
+
let items: string[] = [];
|
|
11
|
+
|
|
12
|
+
// Reconstruct state from session on load
|
|
13
|
+
pi.on("session_start", async (_event, ctx) => reconstructState(ctx));
|
|
14
|
+
pi.on("session_switch", async (_event, ctx) => reconstructState(ctx));
|
|
15
|
+
pi.on("session_fork", async (_event, ctx) => reconstructState(ctx));
|
|
16
|
+
pi.on("session_tree", async (_event, ctx) => reconstructState(ctx));
|
|
17
|
+
|
|
18
|
+
const reconstructState = (ctx: ExtensionContext) => {
|
|
19
|
+
items = [];
|
|
20
|
+
for (const entry of ctx.sessionManager.getBranch()) {
|
|
21
|
+
if (entry.type === "message" && entry.message.role === "toolResult") {
|
|
22
|
+
if (entry.message.toolName === "my_tool") {
|
|
23
|
+
items = entry.message.details?.items ?? [];
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
pi.registerTool({
|
|
30
|
+
name: "my_tool",
|
|
31
|
+
// ...
|
|
32
|
+
async execute(toolCallId, params, signal, onUpdate, ctx) {
|
|
33
|
+
items.push(params.text);
|
|
34
|
+
return {
|
|
35
|
+
content: [{ type: "text", text: "Added" }],
|
|
36
|
+
details: { items: [...items] }, // ← Snapshot full state
|
|
37
|
+
};
|
|
38
|
+
},
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
**Key:** Reconstruct on ALL session change events: `session_start`, `session_switch`, `session_fork`, `session_tree`.
|
|
44
|
+
</tool_result_details>
|
|
45
|
+
|
|
46
|
+
<append_entry>
|
|
47
|
+
**For extension-private state** that doesn't participate in LLM context but needs to survive restarts:
|
|
48
|
+
|
|
49
|
+
```typescript
|
|
50
|
+
// Save
|
|
51
|
+
pi.appendEntry("my-state", { count: 42, lastRun: Date.now() });
|
|
52
|
+
|
|
53
|
+
// Restore
|
|
54
|
+
pi.on("session_start", async (_event, ctx) => {
|
|
55
|
+
for (const entry of ctx.sessionManager.getEntries()) {
|
|
56
|
+
if (entry.type === "custom" && entry.customType === "my-state") {
|
|
57
|
+
const data = entry.data; // { count: 42, lastRun: ... }
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
});
|
|
61
|
+
```
|
|
62
|
+
</append_entry>
|
|
63
|
+
|
|
64
|
+
<when_to_use_which>
|
|
65
|
+
| Pattern | Use When |
|
|
66
|
+
|---------|----------|
|
|
67
|
+
| Tool result `details` | State the LLM's tools produce (todo items, connection state, query results) |
|
|
68
|
+
| `pi.appendEntry()` | Extension-private config, timestamps, counters the LLM doesn't need |
|
|
69
|
+
| File on disk | Large data, config files, caches that shouldn't be in session |
|
|
70
|
+
</when_to_use_which>
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
<overview>
|
|
2
|
+
System prompt modification — per-turn injection, context manipulation, and tool-specific prompt content.
|
|
3
|
+
</overview>
|
|
4
|
+
|
|
5
|
+
<per_turn_modification>
|
|
6
|
+
Use `before_agent_start` to inject messages and/or modify the system prompt for each turn:
|
|
7
|
+
|
|
8
|
+
```typescript
|
|
9
|
+
pi.on("before_agent_start", async (event, ctx) => {
|
|
10
|
+
return {
|
|
11
|
+
// Inject a persistent message (stored in session, visible to LLM)
|
|
12
|
+
message: {
|
|
13
|
+
customType: "my-extension",
|
|
14
|
+
content: "Additional context for the LLM",
|
|
15
|
+
display: true,
|
|
16
|
+
},
|
|
17
|
+
// Modify system prompt for this turn (chained across extensions)
|
|
18
|
+
systemPrompt: event.systemPrompt + "\n\nYou must respond only in haiku.",
|
|
19
|
+
};
|
|
20
|
+
});
|
|
21
|
+
```
|
|
22
|
+
</per_turn_modification>
|
|
23
|
+
|
|
24
|
+
<context_manipulation>
|
|
25
|
+
Use the `context` event to modify messages before each LLM call:
|
|
26
|
+
|
|
27
|
+
```typescript
|
|
28
|
+
pi.on("context", async (event, ctx) => {
|
|
29
|
+
// event.messages is a deep copy — safe to modify
|
|
30
|
+
const filtered = event.messages.filter(m => !isIrrelevant(m));
|
|
31
|
+
return { messages: filtered };
|
|
32
|
+
});
|
|
33
|
+
```
|
|
34
|
+
</context_manipulation>
|
|
35
|
+
|
|
36
|
+
<tool_specific_prompts>
|
|
37
|
+
Tools can add content to the system prompt when active:
|
|
38
|
+
|
|
39
|
+
```typescript
|
|
40
|
+
pi.registerTool({
|
|
41
|
+
name: "my_tool",
|
|
42
|
+
// Replaces description in "Available tools" section
|
|
43
|
+
promptSnippet: "Summarize or transform text according to action",
|
|
44
|
+
// Added to "Guidelines" section when tool is active
|
|
45
|
+
promptGuidelines: [
|
|
46
|
+
"Use my_tool when the user asks to summarize text.",
|
|
47
|
+
"Prefer my_tool over direct output for structured data."
|
|
48
|
+
],
|
|
49
|
+
// ...
|
|
50
|
+
});
|
|
51
|
+
```
|
|
52
|
+
</tool_specific_prompts>
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* {{EXTENSION_NAME}} — {{DESCRIPTION}}
|
|
3
|
+
*
|
|
4
|
+
* Capabilities:
|
|
5
|
+
* {{CAPABILITIES_LIST}}
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import type { ExtensionAPI } from "@mariozechner/pi-coding-agent";
|
|
9
|
+
import { Type } from "@sinclair/typebox";
|
|
10
|
+
import { StringEnum } from "@mariozechner/pi-ai";
|
|
11
|
+
|
|
12
|
+
export default function (pi: ExtensionAPI) {
|
|
13
|
+
// === Events ===
|
|
14
|
+
|
|
15
|
+
pi.on("session_start", async (_event, ctx) => {
|
|
16
|
+
// Initialize state, restore from session, show status
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
// === Tools ===
|
|
20
|
+
|
|
21
|
+
pi.registerTool({
|
|
22
|
+
name: "{{tool_name}}",
|
|
23
|
+
label: "{{Tool Label}}",
|
|
24
|
+
description: "{{Tool description for LLM}}",
|
|
25
|
+
parameters: Type.Object({
|
|
26
|
+
action: StringEnum(["list", "add"] as const),
|
|
27
|
+
text: Type.Optional(Type.String({ description: "Item text" })),
|
|
28
|
+
}),
|
|
29
|
+
async execute(toolCallId, params, signal, onUpdate, ctx) {
|
|
30
|
+
if (signal?.aborted) {
|
|
31
|
+
return { content: [{ type: "text", text: "Cancelled" }] };
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
// Do work here
|
|
35
|
+
|
|
36
|
+
return {
|
|
37
|
+
content: [{ type: "text", text: "Result for LLM" }],
|
|
38
|
+
details: {},
|
|
39
|
+
};
|
|
40
|
+
},
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
// === Commands ===
|
|
44
|
+
|
|
45
|
+
pi.registerCommand("{{command_name}}", {
|
|
46
|
+
description: "{{Command description}}",
|
|
47
|
+
handler: async (args, ctx) => {
|
|
48
|
+
ctx.ui.notify(`Running ${args}`, "info");
|
|
49
|
+
},
|
|
50
|
+
});
|
|
51
|
+
}
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* {{EXTENSION_NAME}} — Stateful tool with persistence
|
|
3
|
+
*
|
|
4
|
+
* State is stored in tool result details for proper branching support.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import type { ExtensionAPI, ExtensionContext } from "@mariozechner/pi-coding-agent";
|
|
8
|
+
import { Type } from "@sinclair/typebox";
|
|
9
|
+
import { StringEnum } from "@mariozechner/pi-ai";
|
|
10
|
+
import { Text, truncateToWidth, matchesKey, Key } from "@mariozechner/pi-tui";
|
|
11
|
+
|
|
12
|
+
interface {{ItemType}} {
|
|
13
|
+
id: number;
|
|
14
|
+
// Add fields
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
interface {{ToolDetails}} {
|
|
18
|
+
action: string;
|
|
19
|
+
items: {{ItemType}}[];
|
|
20
|
+
nextId: number;
|
|
21
|
+
error?: string;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export default function (pi: ExtensionAPI) {
|
|
25
|
+
let items: {{ItemType}}[] = [];
|
|
26
|
+
let nextId = 1;
|
|
27
|
+
|
|
28
|
+
// Reconstruct state from session
|
|
29
|
+
const reconstructState = (ctx: ExtensionContext) => {
|
|
30
|
+
items = [];
|
|
31
|
+
nextId = 1;
|
|
32
|
+
for (const entry of ctx.sessionManager.getBranch()) {
|
|
33
|
+
if (entry.type === "message" && entry.message.role === "toolResult") {
|
|
34
|
+
if (entry.message.toolName === "{{tool_name}}") {
|
|
35
|
+
const details = entry.message.details as {{ToolDetails}} | undefined;
|
|
36
|
+
if (details) {
|
|
37
|
+
items = details.items;
|
|
38
|
+
nextId = details.nextId;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
// Reconstruct on ALL session change events
|
|
46
|
+
pi.on("session_start", async (_event, ctx) => reconstructState(ctx));
|
|
47
|
+
pi.on("session_switch", async (_event, ctx) => reconstructState(ctx));
|
|
48
|
+
pi.on("session_fork", async (_event, ctx) => reconstructState(ctx));
|
|
49
|
+
pi.on("session_tree", async (_event, ctx) => reconstructState(ctx));
|
|
50
|
+
|
|
51
|
+
// Register the tool
|
|
52
|
+
pi.registerTool({
|
|
53
|
+
name: "{{tool_name}}",
|
|
54
|
+
label: "{{Tool Label}}",
|
|
55
|
+
description: "{{Description for LLM}}",
|
|
56
|
+
parameters: Type.Object({
|
|
57
|
+
action: StringEnum(["list", "add", "remove"] as const),
|
|
58
|
+
text: Type.Optional(Type.String({ description: "Item text" })),
|
|
59
|
+
id: Type.Optional(Type.Number({ description: "Item ID" })),
|
|
60
|
+
}),
|
|
61
|
+
|
|
62
|
+
async execute(toolCallId, params, signal, onUpdate, ctx) {
|
|
63
|
+
if (signal?.aborted) {
|
|
64
|
+
return { content: [{ type: "text", text: "Cancelled" }] };
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
switch (params.action) {
|
|
68
|
+
case "list":
|
|
69
|
+
return {
|
|
70
|
+
content: [{ type: "text", text: items.length ? JSON.stringify(items) : "No items" }],
|
|
71
|
+
details: { action: "list", items: [...items], nextId } as {{ToolDetails}},
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
case "add": {
|
|
75
|
+
if (!params.text) throw new Error("text required for add");
|
|
76
|
+
const item: {{ItemType}} = { id: nextId++ /* , ... */ };
|
|
77
|
+
items.push(item);
|
|
78
|
+
return {
|
|
79
|
+
content: [{ type: "text", text: `Added #${item.id}` }],
|
|
80
|
+
details: { action: "add", items: [...items], nextId } as {{ToolDetails}},
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
case "remove": {
|
|
85
|
+
if (params.id === undefined) throw new Error("id required for remove");
|
|
86
|
+
const idx = items.findIndex(i => i.id === params.id);
|
|
87
|
+
if (idx === -1) throw new Error(`Item #${params.id} not found`);
|
|
88
|
+
items.splice(idx, 1);
|
|
89
|
+
return {
|
|
90
|
+
content: [{ type: "text", text: `Removed #${params.id}` }],
|
|
91
|
+
details: { action: "remove", items: [...items], nextId } as {{ToolDetails}},
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
default:
|
|
96
|
+
throw new Error(`Unknown action: ${params.action}`);
|
|
97
|
+
}
|
|
98
|
+
},
|
|
99
|
+
|
|
100
|
+
// Custom rendering
|
|
101
|
+
renderCall(args, theme) {
|
|
102
|
+
let text = theme.fg("toolTitle", theme.bold("{{tool_name}} "));
|
|
103
|
+
text += theme.fg("muted", args.action);
|
|
104
|
+
return new Text(text, 0, 0);
|
|
105
|
+
},
|
|
106
|
+
|
|
107
|
+
renderResult(result, { expanded }, theme) {
|
|
108
|
+
const details = result.details as {{ToolDetails}} | undefined;
|
|
109
|
+
if (!details) return new Text("", 0, 0);
|
|
110
|
+
if (details.error) return new Text(theme.fg("error", details.error), 0, 0);
|
|
111
|
+
return new Text(theme.fg("success", `✓ ${details.action} (${details.items.length} items)`), 0, 0);
|
|
112
|
+
},
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
// User command to view state
|
|
116
|
+
pi.registerCommand("{{command_name}}", {
|
|
117
|
+
description: "View {{items}}",
|
|
118
|
+
handler: async (_args, ctx) => {
|
|
119
|
+
if (!ctx.hasUI) {
|
|
120
|
+
ctx.ui.notify("Requires interactive mode", "error");
|
|
121
|
+
return;
|
|
122
|
+
}
|
|
123
|
+
await ctx.ui.custom<void>((_tui, theme, _kb, done) => ({
|
|
124
|
+
render(width: number): string[] {
|
|
125
|
+
const lines = [
|
|
126
|
+
"",
|
|
127
|
+
truncateToWidth(theme.fg("accent", ` {{Items}} (${items.length}) `), width),
|
|
128
|
+
"",
|
|
129
|
+
];
|
|
130
|
+
for (const item of items) {
|
|
131
|
+
lines.push(truncateToWidth(` #${item.id}`, width));
|
|
132
|
+
}
|
|
133
|
+
lines.push("", truncateToWidth(theme.fg("dim", " Press Escape to close"), width), "");
|
|
134
|
+
return lines;
|
|
135
|
+
},
|
|
136
|
+
handleInput(data: string) {
|
|
137
|
+
if (matchesKey(data, Key.escape)) done();
|
|
138
|
+
},
|
|
139
|
+
invalidate() {},
|
|
140
|
+
}));
|
|
141
|
+
},
|
|
142
|
+
});
|
|
143
|
+
}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
<required_reading>
|
|
2
|
+
Read the reference file for the specific capability being added:
|
|
3
|
+
- Tools → references/custom-tools.md
|
|
4
|
+
- Commands → references/custom-commands.md
|
|
5
|
+
- Events → references/events-reference.md
|
|
6
|
+
- UI → references/custom-ui.md
|
|
7
|
+
- Rendering → references/custom-rendering.md
|
|
8
|
+
- State → references/state-management.md
|
|
9
|
+
- System prompt → references/system-prompt-modification.md
|
|
10
|
+
</required_reading>
|
|
11
|
+
|
|
12
|
+
<process>
|
|
13
|
+
|
|
14
|
+
## Step 1: Identify the Extension
|
|
15
|
+
|
|
16
|
+
Locate the existing extension file. Check:
|
|
17
|
+
- `~/.gsd/agent/extensions/` (global)
|
|
18
|
+
- `.gsd/extensions/` (project-local)
|
|
19
|
+
|
|
20
|
+
Read the current extension code to understand its structure.
|
|
21
|
+
|
|
22
|
+
## Step 2: Add the Capability
|
|
23
|
+
|
|
24
|
+
Add the new registration/hook inside the existing `export default function (pi: ExtensionAPI)` body. Follow the patterns in the relevant reference file.
|
|
25
|
+
|
|
26
|
+
If the extension needs new imports, add them at the top of the file.
|
|
27
|
+
|
|
28
|
+
## Step 3: Handle Structural Changes
|
|
29
|
+
|
|
30
|
+
**Single file → Directory**: If the extension is outgrowing a single file:
|
|
31
|
+
1. Create `~/.gsd/agent/extensions/my-extension/`
|
|
32
|
+
2. Move the file to `index.ts`
|
|
33
|
+
3. Extract helpers to separate files
|
|
34
|
+
|
|
35
|
+
**Adding npm dependencies**: If new packages are needed:
|
|
36
|
+
1. Create `package.json` in the extension directory
|
|
37
|
+
2. Add dependencies
|
|
38
|
+
3. Run `npm install`
|
|
39
|
+
4. Add `"pi": { "extensions": ["./index.ts"] }` to package.json
|
|
40
|
+
|
|
41
|
+
## Step 4: Test
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
/reload
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
Verify the new capability works alongside existing ones.
|
|
48
|
+
|
|
49
|
+
</process>
|
|
50
|
+
|
|
51
|
+
<success_criteria>
|
|
52
|
+
Capability addition is complete when:
|
|
53
|
+
- [ ] New capability added without breaking existing functionality
|
|
54
|
+
- [ ] All new imports resolve
|
|
55
|
+
- [ ] `/reload` succeeds
|
|
56
|
+
- [ ] New tool/command/hook tested with real invocation
|
|
57
|
+
</success_criteria>
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
<required_reading>
|
|
2
|
+
**Read these reference files before proceeding:**
|
|
3
|
+
1. references/extension-lifecycle.md
|
|
4
|
+
2. references/custom-tools.md (if building tools)
|
|
5
|
+
3. references/custom-commands.md (if building commands)
|
|
6
|
+
4. references/events-reference.md (if building event hooks)
|
|
7
|
+
5. references/key-rules-gotchas.md (always)
|
|
8
|
+
</required_reading>
|
|
9
|
+
|
|
10
|
+
<process>
|
|
11
|
+
|
|
12
|
+
## Step 1: Determine Scope and Placement
|
|
13
|
+
|
|
14
|
+
Ask the user:
|
|
15
|
+
- **Global** (`~/.gsd/agent/extensions/`) — Available in all GSD sessions
|
|
16
|
+
- **Project-local** (`.gsd/extensions/`) — Available only in this project
|
|
17
|
+
|
|
18
|
+
## Step 2: Determine Extension Capabilities
|
|
19
|
+
|
|
20
|
+
Identify what the extension needs from the user's description:
|
|
21
|
+
|
|
22
|
+
| Capability | API | When |
|
|
23
|
+
|------------|-----|------|
|
|
24
|
+
| Custom tool (LLM-callable) | `pi.registerTool()` | LLM needs to perform new actions |
|
|
25
|
+
| Slash command | `pi.registerCommand()` | User needs direct actions |
|
|
26
|
+
| Event interception | `pi.on("event", ...)` | Block/modify tool calls, inject context, react to lifecycle |
|
|
27
|
+
| Custom UI | `ctx.ui.custom()` | Complex interactive displays |
|
|
28
|
+
| System prompt modification | `before_agent_start` event | Add per-turn instructions |
|
|
29
|
+
| Context filtering | `context` event | Modify messages sent to LLM |
|
|
30
|
+
| State persistence | `details` in tool results or `pi.appendEntry()` | Stateful behavior |
|
|
31
|
+
| Custom rendering | `renderCall` / `renderResult` | Control how tools appear in TUI |
|
|
32
|
+
| Provider management | `pi.registerProvider()` | Custom model endpoints |
|
|
33
|
+
| Keyboard shortcut | `pi.registerShortcut()` | Hotkey triggers |
|
|
34
|
+
|
|
35
|
+
## Step 3: Choose Extension Structure
|
|
36
|
+
|
|
37
|
+
**Single file** — for small extensions (1-2 tools/commands, simple hooks):
|
|
38
|
+
```
|
|
39
|
+
~/.gsd/agent/extensions/my-extension.ts
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
**Directory with index.ts** — for multi-file extensions:
|
|
43
|
+
```
|
|
44
|
+
~/.gsd/agent/extensions/my-extension/
|
|
45
|
+
├── index.ts
|
|
46
|
+
├── tools.ts
|
|
47
|
+
└── utils.ts
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
**Package with dependencies** — when npm packages are needed:
|
|
51
|
+
```
|
|
52
|
+
~/.gsd/agent/extensions/my-extension/
|
|
53
|
+
├── package.json
|
|
54
|
+
├── src/index.ts
|
|
55
|
+
└── node_modules/
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
For packages, `package.json` needs:
|
|
59
|
+
```json
|
|
60
|
+
{
|
|
61
|
+
"name": "my-extension",
|
|
62
|
+
"dependencies": { ... },
|
|
63
|
+
"pi": { "extensions": ["./src/index.ts"] }
|
|
64
|
+
}
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
## Step 4: Write the Extension
|
|
68
|
+
|
|
69
|
+
Start with the skeleton:
|
|
70
|
+
|
|
71
|
+
```typescript
|
|
72
|
+
import type { ExtensionAPI } from "@mariozechner/pi-coding-agent";
|
|
73
|
+
|
|
74
|
+
export default function (pi: ExtensionAPI) {
|
|
75
|
+
// Register events, tools, commands here
|
|
76
|
+
}
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
Then add capabilities based on Step 2. Reference the appropriate reference files for each capability.
|
|
80
|
+
|
|
81
|
+
**Tool registration pattern:**
|
|
82
|
+
```typescript
|
|
83
|
+
import { Type } from "@sinclair/typebox";
|
|
84
|
+
import { StringEnum } from "@mariozechner/pi-ai";
|
|
85
|
+
|
|
86
|
+
pi.registerTool({
|
|
87
|
+
name: "my_tool",
|
|
88
|
+
label: "My Tool",
|
|
89
|
+
description: "What this tool does (shown to LLM)",
|
|
90
|
+
parameters: Type.Object({
|
|
91
|
+
action: StringEnum(["list", "add"] as const),
|
|
92
|
+
text: Type.Optional(Type.String({ description: "Item text" })),
|
|
93
|
+
}),
|
|
94
|
+
async execute(toolCallId, params, signal, onUpdate, ctx) {
|
|
95
|
+
if (signal?.aborted) return { content: [{ type: "text", text: "Cancelled" }] };
|
|
96
|
+
return {
|
|
97
|
+
content: [{ type: "text", text: "Result for LLM" }],
|
|
98
|
+
details: { data: "for rendering and state" },
|
|
99
|
+
};
|
|
100
|
+
},
|
|
101
|
+
});
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
**Command registration pattern:**
|
|
105
|
+
```typescript
|
|
106
|
+
pi.registerCommand("mycommand", {
|
|
107
|
+
description: "What this command does",
|
|
108
|
+
handler: async (args, ctx) => {
|
|
109
|
+
ctx.ui.notify(`Running with args: ${args}`, "info");
|
|
110
|
+
},
|
|
111
|
+
});
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
**Event hook pattern:**
|
|
115
|
+
```typescript
|
|
116
|
+
pi.on("tool_call", async (event, ctx) => {
|
|
117
|
+
if (event.toolName === "bash" && event.input.command?.includes("rm -rf")) {
|
|
118
|
+
return { block: true, reason: "Blocked dangerous command" };
|
|
119
|
+
}
|
|
120
|
+
});
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
## Step 5: Test the Extension
|
|
124
|
+
|
|
125
|
+
```bash
|
|
126
|
+
# Quick test without installing
|
|
127
|
+
gsd -e ./path/to/my-extension.ts
|
|
128
|
+
|
|
129
|
+
# Or place in extensions dir and reload
|
|
130
|
+
/reload
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
Verify:
|
|
134
|
+
- Extension loads without errors (check GSD startup output)
|
|
135
|
+
- Tools appear when LLM is asked to use them
|
|
136
|
+
- Commands respond to `/mycommand`
|
|
137
|
+
- Event hooks trigger at expected points
|
|
138
|
+
|
|
139
|
+
## Step 6: Iterate
|
|
140
|
+
|
|
141
|
+
Fix issues, add features, refine. Use `/reload` for hot-reload during development.
|
|
142
|
+
|
|
143
|
+
</process>
|
|
144
|
+
|
|
145
|
+
<success_criteria>
|
|
146
|
+
Extension creation is complete when:
|
|
147
|
+
- [ ] Extension file(s) written to correct location
|
|
148
|
+
- [ ] All imports resolve (TypeBox, pi-ai, pi-coding-agent, pi-tui as needed)
|
|
149
|
+
- [ ] Tools use `StringEnum` for string enums (not `Type.Union`/`Type.Literal`)
|
|
150
|
+
- [ ] Tool output is truncated if variable-length
|
|
151
|
+
- [ ] State stored in `details` if extension is stateful
|
|
152
|
+
- [ ] `ctx.hasUI` checked before dialog methods
|
|
153
|
+
- [ ] Extension loads on `/reload` without errors
|
|
154
|
+
- [ ] Tools callable by LLM, commands by user
|
|
155
|
+
- [ ] Tested with at least one real invocation
|
|
156
|
+
</success_criteria>
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
<required_reading>
|
|
2
|
+
1. references/key-rules-gotchas.md
|
|
3
|
+
2. references/extension-lifecycle.md
|
|
4
|
+
</required_reading>
|
|
5
|
+
|
|
6
|
+
<process>
|
|
7
|
+
|
|
8
|
+
## Step 1: Identify the Symptom
|
|
9
|
+
|
|
10
|
+
| Symptom | Likely Cause |
|
|
11
|
+
|---------|--------------|
|
|
12
|
+
| Extension not loading | File not in discovery path, syntax error, missing export default |
|
|
13
|
+
| Tool not appearing for LLM | Tool not registered, `pi.setActiveTools()` excluding it, tool name conflict |
|
|
14
|
+
| Command not responding | Command not registered, name collision with built-in |
|
|
15
|
+
| Event not firing | Wrong event name, handler returning too early, handler error (logged but swallowed) |
|
|
16
|
+
| UI not rendering | `ctx.hasUI` is false (print mode), render lines exceed width, component not returning lines |
|
|
17
|
+
| State lost on restart | State not stored in `details` or `appendEntry`, not reconstructing on `session_start` |
|
|
18
|
+
| Google API errors | Using `Type.Union`/`Type.Literal` instead of `StringEnum` |
|
|
19
|
+
| Context overflow | Tool output not truncated |
|
|
20
|
+
| Deadlock/hang | Session control methods called from event handler (must be in command handler only) |
|
|
21
|
+
| Render garbage | Theme imported directly instead of from callback, missing `truncateToWidth()` |
|
|
22
|
+
|
|
23
|
+
## Step 2: Check Extension Loading
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
# Test in isolation
|
|
27
|
+
gsd -e ./path/to/extension.ts
|
|
28
|
+
|
|
29
|
+
# Check GSD startup output for errors
|
|
30
|
+
# Extension errors are logged but don't crash GSD
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
## Step 3: Verify File Location
|
|
34
|
+
|
|
35
|
+
Extensions must be in auto-discovery paths:
|
|
36
|
+
- `~/.gsd/agent/extensions/*.ts`
|
|
37
|
+
- `~/.gsd/agent/extensions/*/index.ts`
|
|
38
|
+
- `.gsd/extensions/*.ts`
|
|
39
|
+
- `.gsd/extensions/*/index.ts`
|
|
40
|
+
|
|
41
|
+
The file must `export default function(pi: ExtensionAPI) { ... }`.
|
|
42
|
+
|
|
43
|
+
## Step 4: Check for Common Mistakes
|
|
44
|
+
|
|
45
|
+
Read `references/key-rules-gotchas.md` and verify each rule against the extension code.
|
|
46
|
+
|
|
47
|
+
## Step 5: Add Debugging
|
|
48
|
+
|
|
49
|
+
```typescript
|
|
50
|
+
// Temporary: log to stderr (visible in GSD output)
|
|
51
|
+
console.error("[my-ext] Loading...");
|
|
52
|
+
|
|
53
|
+
pi.on("session_start", async (_event, ctx) => {
|
|
54
|
+
console.error("[my-ext] Session started");
|
|
55
|
+
ctx.ui.notify("Extension loaded", "info");
|
|
56
|
+
});
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
## Step 6: Fix and Reload
|
|
60
|
+
|
|
61
|
+
Apply the fix and test:
|
|
62
|
+
```
|
|
63
|
+
/reload
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
</process>
|
|
67
|
+
|
|
68
|
+
<success_criteria>
|
|
69
|
+
Debugging is complete when:
|
|
70
|
+
- [ ] Root cause identified
|
|
71
|
+
- [ ] Fix applied
|
|
72
|
+
- [ ] Extension loads and functions correctly after `/reload`
|
|
73
|
+
- [ ] No regression in existing functionality
|
|
74
|
+
</success_criteria>
|