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.
Files changed (256) hide show
  1. package/README.md +24 -17
  2. package/dist/cli.js +15 -9
  3. package/dist/resource-loader.js +80 -8
  4. package/dist/resources/extensions/bg-shell/process-manager.ts +13 -0
  5. package/dist/resources/extensions/gsd/auto-dashboard.ts +186 -65
  6. package/dist/resources/extensions/gsd/auto-post-unit.ts +14 -6
  7. package/dist/resources/extensions/gsd/auto-recovery.ts +33 -23
  8. package/dist/resources/extensions/gsd/auto-start.ts +25 -10
  9. package/dist/resources/extensions/gsd/auto-verification.ts +41 -7
  10. package/dist/resources/extensions/gsd/auto-worktree-sync.ts +21 -6
  11. package/dist/resources/extensions/gsd/auto.ts +67 -22
  12. package/dist/resources/extensions/gsd/commands-handlers.ts +3 -11
  13. package/dist/resources/extensions/gsd/commands-logs.ts +536 -0
  14. package/dist/resources/extensions/gsd/commands-prefs-wizard.ts +90 -47
  15. package/dist/resources/extensions/gsd/commands-workflow-templates.ts +544 -0
  16. package/dist/resources/extensions/gsd/commands.ts +75 -29
  17. package/dist/resources/extensions/gsd/dashboard-overlay.ts +2 -1
  18. package/dist/resources/extensions/gsd/doctor-types.ts +13 -0
  19. package/dist/resources/extensions/gsd/doctor.ts +2 -6
  20. package/dist/resources/extensions/gsd/export.ts +28 -2
  21. package/dist/resources/extensions/gsd/gsd-db.ts +19 -0
  22. package/dist/resources/extensions/gsd/index.ts +2 -1
  23. package/dist/resources/extensions/gsd/json-persistence.ts +67 -0
  24. package/dist/resources/extensions/gsd/metrics.ts +17 -31
  25. package/dist/resources/extensions/gsd/paths.ts +0 -8
  26. package/dist/resources/extensions/gsd/prompts/guided-discuss-milestone.md +1 -1
  27. package/dist/resources/extensions/gsd/prompts/workflow-start.md +28 -0
  28. package/dist/resources/extensions/gsd/queue-order.ts +10 -11
  29. package/dist/resources/extensions/gsd/routing-history.ts +13 -17
  30. package/dist/resources/extensions/gsd/session-lock.ts +284 -0
  31. package/dist/resources/extensions/gsd/session-status-io.ts +23 -41
  32. package/dist/resources/extensions/gsd/tests/auto-budget-alerts.test.ts +1 -1
  33. package/dist/resources/extensions/gsd/tests/auto-skip-loop.test.ts +1 -1
  34. package/dist/resources/extensions/gsd/tests/commands-logs.test.ts +241 -0
  35. package/dist/resources/extensions/gsd/tests/extension-selector-separator.test.ts +60 -38
  36. package/dist/resources/extensions/gsd/tests/gsd-inspect.test.ts +1 -1
  37. package/dist/resources/extensions/gsd/tests/parallel-workers-multi-milestone-e2e.test.ts +1 -1
  38. package/dist/resources/extensions/gsd/tests/session-lock.test.ts +315 -0
  39. package/dist/resources/extensions/gsd/tests/validate-milestone.test.ts +55 -0
  40. package/dist/resources/extensions/gsd/tests/verification-evidence.test.ts +26 -24
  41. package/dist/resources/extensions/gsd/tests/verification-gate.test.ts +136 -7
  42. package/dist/resources/extensions/gsd/tests/workflow-templates.test.ts +173 -0
  43. package/dist/resources/extensions/gsd/types.ts +1 -0
  44. package/dist/resources/extensions/gsd/unit-runtime.ts +16 -13
  45. package/dist/resources/extensions/gsd/verification-evidence.ts +2 -0
  46. package/dist/resources/extensions/gsd/verification-gate.ts +13 -2
  47. package/dist/resources/extensions/gsd/workflow-templates/bugfix.md +87 -0
  48. package/dist/resources/extensions/gsd/workflow-templates/dep-upgrade.md +74 -0
  49. package/dist/resources/extensions/gsd/workflow-templates/full-project.md +41 -0
  50. package/dist/resources/extensions/gsd/workflow-templates/hotfix.md +45 -0
  51. package/dist/resources/extensions/gsd/workflow-templates/refactor.md +83 -0
  52. package/dist/resources/extensions/gsd/workflow-templates/registry.json +85 -0
  53. package/dist/resources/extensions/gsd/workflow-templates/security-audit.md +73 -0
  54. package/dist/resources/extensions/gsd/workflow-templates/small-feature.md +81 -0
  55. package/dist/resources/extensions/gsd/workflow-templates/spike.md +69 -0
  56. package/dist/resources/extensions/gsd/workflow-templates.ts +241 -0
  57. package/dist/resources/extensions/mcp-client/index.ts +459 -0
  58. package/dist/resources/extensions/remote-questions/discord-adapter.ts +9 -20
  59. package/dist/resources/extensions/remote-questions/http-client.ts +76 -0
  60. package/dist/resources/extensions/remote-questions/notify.ts +1 -2
  61. package/dist/resources/extensions/remote-questions/slack-adapter.ts +11 -18
  62. package/dist/resources/extensions/remote-questions/telegram-adapter.ts +8 -20
  63. package/dist/resources/extensions/remote-questions/types.ts +3 -0
  64. package/dist/resources/extensions/shared/mod.ts +3 -0
  65. package/dist/resources/skills/create-gsd-extension/SKILL.md +87 -0
  66. package/dist/resources/skills/create-gsd-extension/references/compaction-session-control.md +77 -0
  67. package/dist/resources/skills/create-gsd-extension/references/custom-commands.md +139 -0
  68. package/dist/resources/skills/create-gsd-extension/references/custom-rendering.md +108 -0
  69. package/dist/resources/skills/create-gsd-extension/references/custom-tools.md +183 -0
  70. package/dist/resources/skills/create-gsd-extension/references/custom-ui.md +490 -0
  71. package/dist/resources/skills/create-gsd-extension/references/events-reference.md +126 -0
  72. package/dist/resources/skills/create-gsd-extension/references/extension-lifecycle.md +64 -0
  73. package/dist/resources/skills/create-gsd-extension/references/extensionapi-reference.md +75 -0
  74. package/dist/resources/skills/create-gsd-extension/references/extensioncontext-reference.md +53 -0
  75. package/dist/resources/skills/create-gsd-extension/references/key-rules-gotchas.md +36 -0
  76. package/dist/resources/skills/create-gsd-extension/references/mode-behavior.md +32 -0
  77. package/dist/resources/skills/create-gsd-extension/references/model-provider-management.md +89 -0
  78. package/dist/resources/skills/create-gsd-extension/references/packaging-distribution.md +55 -0
  79. package/dist/resources/skills/create-gsd-extension/references/remote-execution-overrides.md +90 -0
  80. package/dist/resources/skills/create-gsd-extension/references/state-management.md +70 -0
  81. package/dist/resources/skills/create-gsd-extension/references/system-prompt-modification.md +52 -0
  82. package/dist/resources/skills/create-gsd-extension/templates/extension-skeleton.ts +51 -0
  83. package/dist/resources/skills/create-gsd-extension/templates/stateful-tool-skeleton.ts +143 -0
  84. package/dist/resources/skills/create-gsd-extension/workflows/add-capability.md +57 -0
  85. package/dist/resources/skills/create-gsd-extension/workflows/create-extension.md +156 -0
  86. package/dist/resources/skills/create-gsd-extension/workflows/debug-extension.md +74 -0
  87. package/dist/resources/skills/create-skill/SKILL.md +184 -0
  88. package/dist/resources/skills/create-skill/references/api-security.md +226 -0
  89. package/dist/resources/skills/create-skill/references/be-clear-and-direct.md +531 -0
  90. package/dist/resources/skills/create-skill/references/common-patterns.md +595 -0
  91. package/dist/resources/skills/create-skill/references/core-principles.md +437 -0
  92. package/dist/resources/skills/create-skill/references/executable-code.md +175 -0
  93. package/dist/resources/skills/create-skill/references/gsd-skill-ecosystem.md +68 -0
  94. package/dist/resources/skills/create-skill/references/iteration-and-testing.md +474 -0
  95. package/dist/resources/skills/create-skill/references/recommended-structure.md +168 -0
  96. package/dist/resources/skills/create-skill/references/skill-structure.md +372 -0
  97. package/dist/resources/skills/create-skill/references/use-xml-tags.md +466 -0
  98. package/dist/resources/skills/create-skill/references/using-scripts.md +113 -0
  99. package/dist/resources/skills/create-skill/references/using-templates.md +112 -0
  100. package/dist/resources/skills/create-skill/references/workflows-and-validation.md +510 -0
  101. package/dist/resources/skills/create-skill/templates/router-skill.md +73 -0
  102. package/dist/resources/skills/create-skill/templates/simple-skill.md +33 -0
  103. package/dist/resources/skills/create-skill/workflows/add-reference.md +96 -0
  104. package/dist/resources/skills/create-skill/workflows/add-script.md +93 -0
  105. package/dist/resources/skills/create-skill/workflows/add-template.md +74 -0
  106. package/dist/resources/skills/create-skill/workflows/add-workflow.md +120 -0
  107. package/dist/resources/skills/create-skill/workflows/audit-skill.md +148 -0
  108. package/dist/resources/skills/create-skill/workflows/create-new-skill.md +196 -0
  109. package/dist/resources/skills/create-skill/workflows/get-guidance.md +121 -0
  110. package/dist/resources/skills/create-skill/workflows/upgrade-to-router.md +161 -0
  111. package/dist/resources/skills/create-skill/workflows/verify-skill.md +204 -0
  112. package/package.json +6 -3
  113. package/packages/native/dist/native.d.ts +2 -0
  114. package/packages/native/dist/native.js +19 -5
  115. package/packages/native/src/native.ts +23 -9
  116. package/packages/pi-coding-agent/dist/core/extensions/loader.d.ts.map +1 -1
  117. package/packages/pi-coding-agent/dist/core/extensions/loader.js +13 -0
  118. package/packages/pi-coding-agent/dist/core/extensions/loader.js.map +1 -1
  119. package/packages/pi-coding-agent/dist/core/settings-manager.d.ts +3 -0
  120. package/packages/pi-coding-agent/dist/core/settings-manager.d.ts.map +1 -1
  121. package/packages/pi-coding-agent/dist/core/settings-manager.js +8 -0
  122. package/packages/pi-coding-agent/dist/core/settings-manager.js.map +1 -1
  123. package/packages/pi-coding-agent/dist/core/system-prompt.d.ts.map +1 -1
  124. package/packages/pi-coding-agent/dist/core/system-prompt.js +10 -0
  125. package/packages/pi-coding-agent/dist/core/system-prompt.js.map +1 -1
  126. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  127. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js +4 -1
  128. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js.map +1 -1
  129. package/packages/pi-coding-agent/package.json +1 -1
  130. package/packages/pi-coding-agent/scripts/copy-assets.cjs +39 -8
  131. package/packages/pi-coding-agent/src/core/extensions/loader.ts +13 -0
  132. package/packages/pi-coding-agent/src/core/settings-manager.ts +11 -0
  133. package/packages/pi-coding-agent/src/core/system-prompt.ts +11 -0
  134. package/packages/pi-coding-agent/src/modes/interactive/interactive-mode.ts +4 -1
  135. package/packages/pi-tui/dist/autocomplete.d.ts +3 -0
  136. package/packages/pi-tui/dist/autocomplete.d.ts.map +1 -1
  137. package/packages/pi-tui/dist/autocomplete.js +14 -0
  138. package/packages/pi-tui/dist/autocomplete.js.map +1 -1
  139. package/packages/pi-tui/src/autocomplete.ts +19 -1
  140. package/pkg/package.json +1 -1
  141. package/src/resources/extensions/bg-shell/process-manager.ts +13 -0
  142. package/src/resources/extensions/gsd/auto-dashboard.ts +186 -65
  143. package/src/resources/extensions/gsd/auto-post-unit.ts +14 -6
  144. package/src/resources/extensions/gsd/auto-recovery.ts +33 -23
  145. package/src/resources/extensions/gsd/auto-start.ts +25 -10
  146. package/src/resources/extensions/gsd/auto-verification.ts +41 -7
  147. package/src/resources/extensions/gsd/auto-worktree-sync.ts +21 -6
  148. package/src/resources/extensions/gsd/auto.ts +67 -22
  149. package/src/resources/extensions/gsd/commands-handlers.ts +3 -11
  150. package/src/resources/extensions/gsd/commands-logs.ts +536 -0
  151. package/src/resources/extensions/gsd/commands-prefs-wizard.ts +90 -47
  152. package/src/resources/extensions/gsd/commands-workflow-templates.ts +544 -0
  153. package/src/resources/extensions/gsd/commands.ts +75 -29
  154. package/src/resources/extensions/gsd/dashboard-overlay.ts +2 -1
  155. package/src/resources/extensions/gsd/doctor-types.ts +13 -0
  156. package/src/resources/extensions/gsd/doctor.ts +2 -6
  157. package/src/resources/extensions/gsd/export.ts +28 -2
  158. package/src/resources/extensions/gsd/gsd-db.ts +19 -0
  159. package/src/resources/extensions/gsd/index.ts +2 -1
  160. package/src/resources/extensions/gsd/json-persistence.ts +67 -0
  161. package/src/resources/extensions/gsd/metrics.ts +17 -31
  162. package/src/resources/extensions/gsd/paths.ts +0 -8
  163. package/src/resources/extensions/gsd/prompts/guided-discuss-milestone.md +1 -1
  164. package/src/resources/extensions/gsd/prompts/workflow-start.md +28 -0
  165. package/src/resources/extensions/gsd/queue-order.ts +10 -11
  166. package/src/resources/extensions/gsd/routing-history.ts +13 -17
  167. package/src/resources/extensions/gsd/session-lock.ts +284 -0
  168. package/src/resources/extensions/gsd/session-status-io.ts +23 -41
  169. package/src/resources/extensions/gsd/tests/auto-budget-alerts.test.ts +1 -1
  170. package/src/resources/extensions/gsd/tests/auto-skip-loop.test.ts +1 -1
  171. package/src/resources/extensions/gsd/tests/commands-logs.test.ts +241 -0
  172. package/src/resources/extensions/gsd/tests/extension-selector-separator.test.ts +60 -38
  173. package/src/resources/extensions/gsd/tests/gsd-inspect.test.ts +1 -1
  174. package/src/resources/extensions/gsd/tests/parallel-workers-multi-milestone-e2e.test.ts +1 -1
  175. package/src/resources/extensions/gsd/tests/session-lock.test.ts +315 -0
  176. package/src/resources/extensions/gsd/tests/validate-milestone.test.ts +55 -0
  177. package/src/resources/extensions/gsd/tests/verification-evidence.test.ts +26 -24
  178. package/src/resources/extensions/gsd/tests/verification-gate.test.ts +136 -7
  179. package/src/resources/extensions/gsd/tests/workflow-templates.test.ts +173 -0
  180. package/src/resources/extensions/gsd/types.ts +1 -0
  181. package/src/resources/extensions/gsd/unit-runtime.ts +16 -13
  182. package/src/resources/extensions/gsd/verification-evidence.ts +2 -0
  183. package/src/resources/extensions/gsd/verification-gate.ts +13 -2
  184. package/src/resources/extensions/gsd/workflow-templates/bugfix.md +87 -0
  185. package/src/resources/extensions/gsd/workflow-templates/dep-upgrade.md +74 -0
  186. package/src/resources/extensions/gsd/workflow-templates/full-project.md +41 -0
  187. package/src/resources/extensions/gsd/workflow-templates/hotfix.md +45 -0
  188. package/src/resources/extensions/gsd/workflow-templates/refactor.md +83 -0
  189. package/src/resources/extensions/gsd/workflow-templates/registry.json +85 -0
  190. package/src/resources/extensions/gsd/workflow-templates/security-audit.md +73 -0
  191. package/src/resources/extensions/gsd/workflow-templates/small-feature.md +81 -0
  192. package/src/resources/extensions/gsd/workflow-templates/spike.md +69 -0
  193. package/src/resources/extensions/gsd/workflow-templates.ts +241 -0
  194. package/src/resources/extensions/mcp-client/index.ts +459 -0
  195. package/src/resources/extensions/remote-questions/discord-adapter.ts +9 -20
  196. package/src/resources/extensions/remote-questions/http-client.ts +76 -0
  197. package/src/resources/extensions/remote-questions/notify.ts +1 -2
  198. package/src/resources/extensions/remote-questions/slack-adapter.ts +11 -18
  199. package/src/resources/extensions/remote-questions/telegram-adapter.ts +8 -20
  200. package/src/resources/extensions/remote-questions/types.ts +3 -0
  201. package/src/resources/extensions/shared/mod.ts +3 -0
  202. package/src/resources/skills/create-gsd-extension/SKILL.md +87 -0
  203. package/src/resources/skills/create-gsd-extension/references/compaction-session-control.md +77 -0
  204. package/src/resources/skills/create-gsd-extension/references/custom-commands.md +139 -0
  205. package/src/resources/skills/create-gsd-extension/references/custom-rendering.md +108 -0
  206. package/src/resources/skills/create-gsd-extension/references/custom-tools.md +183 -0
  207. package/src/resources/skills/create-gsd-extension/references/custom-ui.md +490 -0
  208. package/src/resources/skills/create-gsd-extension/references/events-reference.md +126 -0
  209. package/src/resources/skills/create-gsd-extension/references/extension-lifecycle.md +64 -0
  210. package/src/resources/skills/create-gsd-extension/references/extensionapi-reference.md +75 -0
  211. package/src/resources/skills/create-gsd-extension/references/extensioncontext-reference.md +53 -0
  212. package/src/resources/skills/create-gsd-extension/references/key-rules-gotchas.md +36 -0
  213. package/src/resources/skills/create-gsd-extension/references/mode-behavior.md +32 -0
  214. package/src/resources/skills/create-gsd-extension/references/model-provider-management.md +89 -0
  215. package/src/resources/skills/create-gsd-extension/references/packaging-distribution.md +55 -0
  216. package/src/resources/skills/create-gsd-extension/references/remote-execution-overrides.md +90 -0
  217. package/src/resources/skills/create-gsd-extension/references/state-management.md +70 -0
  218. package/src/resources/skills/create-gsd-extension/references/system-prompt-modification.md +52 -0
  219. package/src/resources/skills/create-gsd-extension/templates/extension-skeleton.ts +51 -0
  220. package/src/resources/skills/create-gsd-extension/templates/stateful-tool-skeleton.ts +143 -0
  221. package/src/resources/skills/create-gsd-extension/workflows/add-capability.md +57 -0
  222. package/src/resources/skills/create-gsd-extension/workflows/create-extension.md +156 -0
  223. package/src/resources/skills/create-gsd-extension/workflows/debug-extension.md +74 -0
  224. package/src/resources/skills/create-skill/SKILL.md +184 -0
  225. package/src/resources/skills/create-skill/references/api-security.md +226 -0
  226. package/src/resources/skills/create-skill/references/be-clear-and-direct.md +531 -0
  227. package/src/resources/skills/create-skill/references/common-patterns.md +595 -0
  228. package/src/resources/skills/create-skill/references/core-principles.md +437 -0
  229. package/src/resources/skills/create-skill/references/executable-code.md +175 -0
  230. package/src/resources/skills/create-skill/references/gsd-skill-ecosystem.md +68 -0
  231. package/src/resources/skills/create-skill/references/iteration-and-testing.md +474 -0
  232. package/src/resources/skills/create-skill/references/recommended-structure.md +168 -0
  233. package/src/resources/skills/create-skill/references/skill-structure.md +372 -0
  234. package/src/resources/skills/create-skill/references/use-xml-tags.md +466 -0
  235. package/src/resources/skills/create-skill/references/using-scripts.md +113 -0
  236. package/src/resources/skills/create-skill/references/using-templates.md +112 -0
  237. package/src/resources/skills/create-skill/references/workflows-and-validation.md +510 -0
  238. package/src/resources/skills/create-skill/templates/router-skill.md +73 -0
  239. package/src/resources/skills/create-skill/templates/simple-skill.md +33 -0
  240. package/src/resources/skills/create-skill/workflows/add-reference.md +96 -0
  241. package/src/resources/skills/create-skill/workflows/add-script.md +93 -0
  242. package/src/resources/skills/create-skill/workflows/add-template.md +74 -0
  243. package/src/resources/skills/create-skill/workflows/add-workflow.md +120 -0
  244. package/src/resources/skills/create-skill/workflows/audit-skill.md +148 -0
  245. package/src/resources/skills/create-skill/workflows/create-new-skill.md +196 -0
  246. package/src/resources/skills/create-skill/workflows/get-guidance.md +121 -0
  247. package/src/resources/skills/create-skill/workflows/upgrade-to-router.md +161 -0
  248. package/src/resources/skills/create-skill/workflows/verify-skill.md +204 -0
  249. package/dist/resources/extensions/gsd/preferences-hooks.ts +0 -10
  250. package/dist/resources/extensions/mcporter/index.ts +0 -525
  251. package/dist/resources/extensions/shared/progress-widget.ts +0 -282
  252. package/dist/resources/extensions/shared/thinking-widget.ts +0 -107
  253. package/src/resources/extensions/gsd/preferences-hooks.ts +0 -10
  254. package/src/resources/extensions/mcporter/index.ts +0 -525
  255. package/src/resources/extensions/shared/progress-widget.ts +0 -282
  256. 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>