gsd-pi 2.29.0-dev.49d972f → 2.29.0-dev.4c155ee

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/headless.js +4 -0
  3. package/dist/resources/extensions/bg-shell/process-manager.ts +13 -0
  4. package/dist/resources/extensions/gsd/auto-dashboard.ts +217 -65
  5. package/dist/resources/extensions/gsd/auto-dispatch.ts +32 -3
  6. package/dist/resources/extensions/gsd/auto-post-unit.ts +44 -12
  7. package/dist/resources/extensions/gsd/auto-prompts.ts +40 -17
  8. package/dist/resources/extensions/gsd/auto-recovery.ts +2 -1
  9. package/dist/resources/extensions/gsd/auto-start.ts +18 -32
  10. package/dist/resources/extensions/gsd/auto-worktree.ts +21 -182
  11. package/dist/resources/extensions/gsd/auto.ts +2 -9
  12. package/dist/resources/extensions/gsd/captures.ts +4 -10
  13. package/dist/resources/extensions/gsd/commands-handlers.ts +2 -1
  14. package/dist/resources/extensions/gsd/commands-prefs-wizard.ts +44 -14
  15. package/dist/resources/extensions/gsd/commands-workflow-templates.ts +544 -0
  16. package/dist/resources/extensions/gsd/commands.ts +55 -2
  17. package/dist/resources/extensions/gsd/detection.ts +2 -1
  18. package/dist/resources/extensions/gsd/doctor-checks.ts +49 -1
  19. package/dist/resources/extensions/gsd/doctor-types.ts +3 -1
  20. package/dist/resources/extensions/gsd/forensics.ts +2 -2
  21. package/dist/resources/extensions/gsd/git-service.ts +3 -2
  22. package/dist/resources/extensions/gsd/gitignore.ts +9 -63
  23. package/dist/resources/extensions/gsd/gsd-db.ts +1 -165
  24. package/dist/resources/extensions/gsd/guided-flow.ts +8 -5
  25. package/dist/resources/extensions/gsd/index.ts +3 -3
  26. package/dist/resources/extensions/gsd/md-importer.ts +3 -2
  27. package/dist/resources/extensions/gsd/mechanical-completion.ts +430 -0
  28. package/dist/resources/extensions/gsd/migrate/command.ts +3 -2
  29. package/dist/resources/extensions/gsd/migrate/writer.ts +2 -1
  30. package/dist/resources/extensions/gsd/migrate-external.ts +123 -0
  31. package/dist/resources/extensions/gsd/paths.ts +24 -2
  32. package/dist/resources/extensions/gsd/post-unit-hooks.ts +6 -5
  33. package/dist/resources/extensions/gsd/preferences-models.ts +7 -1
  34. package/dist/resources/extensions/gsd/preferences-validation.ts +2 -1
  35. package/dist/resources/extensions/gsd/preferences.ts +10 -5
  36. package/dist/resources/extensions/gsd/prompts/discuss-headless.md +4 -2
  37. package/dist/resources/extensions/gsd/prompts/guided-discuss-milestone.md +1 -1
  38. package/dist/resources/extensions/gsd/prompts/plan-milestone.md +26 -2
  39. package/dist/resources/extensions/gsd/prompts/plan-slice.md +15 -1
  40. package/dist/resources/extensions/gsd/prompts/workflow-start.md +28 -0
  41. package/dist/resources/extensions/gsd/repo-identity.ts +148 -0
  42. package/dist/resources/extensions/gsd/resource-version.ts +99 -0
  43. package/dist/resources/extensions/gsd/session-forensics.ts +4 -3
  44. package/dist/resources/extensions/gsd/tests/activity-log.test.ts +2 -2
  45. package/dist/resources/extensions/gsd/tests/auto-recovery.test.ts +3 -3
  46. package/dist/resources/extensions/gsd/tests/auto-worktree.test.ts +0 -58
  47. package/dist/resources/extensions/gsd/tests/doctor-runtime.test.ts +3 -4
  48. package/dist/resources/extensions/gsd/tests/extension-selector-separator.test.ts +60 -38
  49. package/dist/resources/extensions/gsd/tests/feature-branch-lifecycle-integration.test.ts +5 -18
  50. package/dist/resources/extensions/gsd/tests/git-service.test.ts +10 -37
  51. package/dist/resources/extensions/gsd/tests/knowledge.test.ts +4 -4
  52. package/dist/resources/extensions/gsd/tests/mechanical-completion.test.ts +356 -0
  53. package/dist/resources/extensions/gsd/tests/plan-slice-prompt.test.ts +1 -0
  54. package/dist/resources/extensions/gsd/tests/token-profile.test.ts +14 -16
  55. package/dist/resources/extensions/gsd/tests/workflow-templates.test.ts +173 -0
  56. package/dist/resources/extensions/gsd/triage-resolution.ts +2 -1
  57. package/dist/resources/extensions/gsd/types.ts +2 -0
  58. package/dist/resources/extensions/gsd/workflow-templates/bugfix.md +87 -0
  59. package/dist/resources/extensions/gsd/workflow-templates/dep-upgrade.md +74 -0
  60. package/dist/resources/extensions/gsd/workflow-templates/full-project.md +41 -0
  61. package/dist/resources/extensions/gsd/workflow-templates/hotfix.md +45 -0
  62. package/dist/resources/extensions/gsd/workflow-templates/refactor.md +83 -0
  63. package/dist/resources/extensions/gsd/workflow-templates/registry.json +85 -0
  64. package/dist/resources/extensions/gsd/workflow-templates/security-audit.md +73 -0
  65. package/dist/resources/extensions/gsd/workflow-templates/small-feature.md +81 -0
  66. package/dist/resources/extensions/gsd/workflow-templates/spike.md +69 -0
  67. package/dist/resources/extensions/gsd/workflow-templates.ts +241 -0
  68. package/dist/resources/extensions/gsd/worktree-command.ts +1 -11
  69. package/dist/resources/extensions/gsd/worktree-manager.ts +3 -2
  70. package/dist/resources/extensions/gsd/worktree.ts +42 -5
  71. package/dist/resources/extensions/mcp-client/index.ts +459 -0
  72. package/dist/resources/skills/create-gsd-extension/SKILL.md +87 -0
  73. package/dist/resources/skills/create-gsd-extension/references/compaction-session-control.md +77 -0
  74. package/dist/resources/skills/create-gsd-extension/references/custom-commands.md +139 -0
  75. package/dist/resources/skills/create-gsd-extension/references/custom-rendering.md +108 -0
  76. package/dist/resources/skills/create-gsd-extension/references/custom-tools.md +183 -0
  77. package/dist/resources/skills/create-gsd-extension/references/custom-ui.md +490 -0
  78. package/dist/resources/skills/create-gsd-extension/references/events-reference.md +126 -0
  79. package/dist/resources/skills/create-gsd-extension/references/extension-lifecycle.md +64 -0
  80. package/dist/resources/skills/create-gsd-extension/references/extensionapi-reference.md +75 -0
  81. package/dist/resources/skills/create-gsd-extension/references/extensioncontext-reference.md +53 -0
  82. package/dist/resources/skills/create-gsd-extension/references/key-rules-gotchas.md +36 -0
  83. package/dist/resources/skills/create-gsd-extension/references/mode-behavior.md +32 -0
  84. package/dist/resources/skills/create-gsd-extension/references/model-provider-management.md +89 -0
  85. package/dist/resources/skills/create-gsd-extension/references/packaging-distribution.md +55 -0
  86. package/dist/resources/skills/create-gsd-extension/references/remote-execution-overrides.md +90 -0
  87. package/dist/resources/skills/create-gsd-extension/references/state-management.md +70 -0
  88. package/dist/resources/skills/create-gsd-extension/references/system-prompt-modification.md +52 -0
  89. package/dist/resources/skills/create-gsd-extension/templates/extension-skeleton.ts +51 -0
  90. package/dist/resources/skills/create-gsd-extension/templates/stateful-tool-skeleton.ts +143 -0
  91. package/dist/resources/skills/create-gsd-extension/workflows/add-capability.md +57 -0
  92. package/dist/resources/skills/create-gsd-extension/workflows/create-extension.md +156 -0
  93. package/dist/resources/skills/create-gsd-extension/workflows/debug-extension.md +74 -0
  94. package/dist/resources/skills/create-skill/SKILL.md +184 -0
  95. package/dist/resources/skills/create-skill/references/api-security.md +226 -0
  96. package/dist/resources/skills/create-skill/references/be-clear-and-direct.md +531 -0
  97. package/dist/resources/skills/create-skill/references/common-patterns.md +595 -0
  98. package/dist/resources/skills/create-skill/references/core-principles.md +437 -0
  99. package/dist/resources/skills/create-skill/references/executable-code.md +175 -0
  100. package/dist/resources/skills/create-skill/references/gsd-skill-ecosystem.md +68 -0
  101. package/dist/resources/skills/create-skill/references/iteration-and-testing.md +474 -0
  102. package/dist/resources/skills/create-skill/references/recommended-structure.md +168 -0
  103. package/dist/resources/skills/create-skill/references/skill-structure.md +372 -0
  104. package/dist/resources/skills/create-skill/references/use-xml-tags.md +466 -0
  105. package/dist/resources/skills/create-skill/references/using-scripts.md +113 -0
  106. package/dist/resources/skills/create-skill/references/using-templates.md +112 -0
  107. package/dist/resources/skills/create-skill/references/workflows-and-validation.md +510 -0
  108. package/dist/resources/skills/create-skill/templates/router-skill.md +73 -0
  109. package/dist/resources/skills/create-skill/templates/simple-skill.md +33 -0
  110. package/dist/resources/skills/create-skill/workflows/add-reference.md +96 -0
  111. package/dist/resources/skills/create-skill/workflows/add-script.md +93 -0
  112. package/dist/resources/skills/create-skill/workflows/add-template.md +74 -0
  113. package/dist/resources/skills/create-skill/workflows/add-workflow.md +120 -0
  114. package/dist/resources/skills/create-skill/workflows/audit-skill.md +148 -0
  115. package/dist/resources/skills/create-skill/workflows/create-new-skill.md +196 -0
  116. package/dist/resources/skills/create-skill/workflows/get-guidance.md +121 -0
  117. package/dist/resources/skills/create-skill/workflows/upgrade-to-router.md +161 -0
  118. package/dist/resources/skills/create-skill/workflows/verify-skill.md +204 -0
  119. package/dist/resources/skills/react-best-practices/SKILL.md +1 -1
  120. package/package.json +1 -1
  121. package/packages/native/dist/native.d.ts +2 -0
  122. package/packages/native/dist/native.js +19 -5
  123. package/packages/native/src/native.ts +23 -9
  124. package/packages/pi-coding-agent/dist/core/extensions/loader.d.ts.map +1 -1
  125. package/packages/pi-coding-agent/dist/core/extensions/loader.js +13 -0
  126. package/packages/pi-coding-agent/dist/core/extensions/loader.js.map +1 -1
  127. package/packages/pi-coding-agent/dist/core/lsp/client.d.ts.map +1 -1
  128. package/packages/pi-coding-agent/dist/core/lsp/client.js +3 -0
  129. package/packages/pi-coding-agent/dist/core/lsp/client.js.map +1 -1
  130. package/packages/pi-coding-agent/src/core/extensions/loader.ts +13 -0
  131. package/packages/pi-coding-agent/src/core/lsp/client.ts +3 -0
  132. package/src/resources/extensions/bg-shell/process-manager.ts +13 -0
  133. package/src/resources/extensions/gsd/auto-dashboard.ts +217 -65
  134. package/src/resources/extensions/gsd/auto-dispatch.ts +32 -3
  135. package/src/resources/extensions/gsd/auto-post-unit.ts +44 -12
  136. package/src/resources/extensions/gsd/auto-prompts.ts +40 -17
  137. package/src/resources/extensions/gsd/auto-recovery.ts +2 -1
  138. package/src/resources/extensions/gsd/auto-start.ts +18 -32
  139. package/src/resources/extensions/gsd/auto-worktree.ts +21 -182
  140. package/src/resources/extensions/gsd/auto.ts +2 -9
  141. package/src/resources/extensions/gsd/captures.ts +4 -10
  142. package/src/resources/extensions/gsd/commands-handlers.ts +2 -1
  143. package/src/resources/extensions/gsd/commands-prefs-wizard.ts +44 -14
  144. package/src/resources/extensions/gsd/commands-workflow-templates.ts +544 -0
  145. package/src/resources/extensions/gsd/commands.ts +55 -2
  146. package/src/resources/extensions/gsd/detection.ts +2 -1
  147. package/src/resources/extensions/gsd/doctor-checks.ts +49 -1
  148. package/src/resources/extensions/gsd/doctor-types.ts +3 -1
  149. package/src/resources/extensions/gsd/forensics.ts +2 -2
  150. package/src/resources/extensions/gsd/git-service.ts +3 -2
  151. package/src/resources/extensions/gsd/gitignore.ts +9 -63
  152. package/src/resources/extensions/gsd/gsd-db.ts +1 -165
  153. package/src/resources/extensions/gsd/guided-flow.ts +8 -5
  154. package/src/resources/extensions/gsd/index.ts +3 -3
  155. package/src/resources/extensions/gsd/md-importer.ts +3 -2
  156. package/src/resources/extensions/gsd/mechanical-completion.ts +430 -0
  157. package/src/resources/extensions/gsd/migrate/command.ts +3 -2
  158. package/src/resources/extensions/gsd/migrate/writer.ts +2 -1
  159. package/src/resources/extensions/gsd/migrate-external.ts +123 -0
  160. package/src/resources/extensions/gsd/paths.ts +24 -2
  161. package/src/resources/extensions/gsd/post-unit-hooks.ts +6 -5
  162. package/src/resources/extensions/gsd/preferences-models.ts +7 -1
  163. package/src/resources/extensions/gsd/preferences-validation.ts +2 -1
  164. package/src/resources/extensions/gsd/preferences.ts +10 -5
  165. package/src/resources/extensions/gsd/prompts/discuss-headless.md +4 -2
  166. package/src/resources/extensions/gsd/prompts/guided-discuss-milestone.md +1 -1
  167. package/src/resources/extensions/gsd/prompts/plan-milestone.md +26 -2
  168. package/src/resources/extensions/gsd/prompts/plan-slice.md +15 -1
  169. package/src/resources/extensions/gsd/prompts/workflow-start.md +28 -0
  170. package/src/resources/extensions/gsd/repo-identity.ts +148 -0
  171. package/src/resources/extensions/gsd/resource-version.ts +99 -0
  172. package/src/resources/extensions/gsd/session-forensics.ts +4 -3
  173. package/src/resources/extensions/gsd/tests/activity-log.test.ts +2 -2
  174. package/src/resources/extensions/gsd/tests/auto-recovery.test.ts +3 -3
  175. package/src/resources/extensions/gsd/tests/auto-worktree.test.ts +0 -58
  176. package/src/resources/extensions/gsd/tests/doctor-runtime.test.ts +3 -4
  177. package/src/resources/extensions/gsd/tests/extension-selector-separator.test.ts +60 -38
  178. package/src/resources/extensions/gsd/tests/feature-branch-lifecycle-integration.test.ts +5 -18
  179. package/src/resources/extensions/gsd/tests/git-service.test.ts +10 -37
  180. package/src/resources/extensions/gsd/tests/knowledge.test.ts +4 -4
  181. package/src/resources/extensions/gsd/tests/mechanical-completion.test.ts +356 -0
  182. package/src/resources/extensions/gsd/tests/plan-slice-prompt.test.ts +1 -0
  183. package/src/resources/extensions/gsd/tests/token-profile.test.ts +14 -16
  184. package/src/resources/extensions/gsd/tests/workflow-templates.test.ts +173 -0
  185. package/src/resources/extensions/gsd/triage-resolution.ts +2 -1
  186. package/src/resources/extensions/gsd/types.ts +2 -0
  187. package/src/resources/extensions/gsd/workflow-templates/bugfix.md +87 -0
  188. package/src/resources/extensions/gsd/workflow-templates/dep-upgrade.md +74 -0
  189. package/src/resources/extensions/gsd/workflow-templates/full-project.md +41 -0
  190. package/src/resources/extensions/gsd/workflow-templates/hotfix.md +45 -0
  191. package/src/resources/extensions/gsd/workflow-templates/refactor.md +83 -0
  192. package/src/resources/extensions/gsd/workflow-templates/registry.json +85 -0
  193. package/src/resources/extensions/gsd/workflow-templates/security-audit.md +73 -0
  194. package/src/resources/extensions/gsd/workflow-templates/small-feature.md +81 -0
  195. package/src/resources/extensions/gsd/workflow-templates/spike.md +69 -0
  196. package/src/resources/extensions/gsd/workflow-templates.ts +241 -0
  197. package/src/resources/extensions/gsd/worktree-command.ts +1 -11
  198. package/src/resources/extensions/gsd/worktree-manager.ts +3 -2
  199. package/src/resources/extensions/gsd/worktree.ts +42 -5
  200. package/src/resources/extensions/mcp-client/index.ts +459 -0
  201. package/src/resources/skills/create-gsd-extension/SKILL.md +87 -0
  202. package/src/resources/skills/create-gsd-extension/references/compaction-session-control.md +77 -0
  203. package/src/resources/skills/create-gsd-extension/references/custom-commands.md +139 -0
  204. package/src/resources/skills/create-gsd-extension/references/custom-rendering.md +108 -0
  205. package/src/resources/skills/create-gsd-extension/references/custom-tools.md +183 -0
  206. package/src/resources/skills/create-gsd-extension/references/custom-ui.md +490 -0
  207. package/src/resources/skills/create-gsd-extension/references/events-reference.md +126 -0
  208. package/src/resources/skills/create-gsd-extension/references/extension-lifecycle.md +64 -0
  209. package/src/resources/skills/create-gsd-extension/references/extensionapi-reference.md +75 -0
  210. package/src/resources/skills/create-gsd-extension/references/extensioncontext-reference.md +53 -0
  211. package/src/resources/skills/create-gsd-extension/references/key-rules-gotchas.md +36 -0
  212. package/src/resources/skills/create-gsd-extension/references/mode-behavior.md +32 -0
  213. package/src/resources/skills/create-gsd-extension/references/model-provider-management.md +89 -0
  214. package/src/resources/skills/create-gsd-extension/references/packaging-distribution.md +55 -0
  215. package/src/resources/skills/create-gsd-extension/references/remote-execution-overrides.md +90 -0
  216. package/src/resources/skills/create-gsd-extension/references/state-management.md +70 -0
  217. package/src/resources/skills/create-gsd-extension/references/system-prompt-modification.md +52 -0
  218. package/src/resources/skills/create-gsd-extension/templates/extension-skeleton.ts +51 -0
  219. package/src/resources/skills/create-gsd-extension/templates/stateful-tool-skeleton.ts +143 -0
  220. package/src/resources/skills/create-gsd-extension/workflows/add-capability.md +57 -0
  221. package/src/resources/skills/create-gsd-extension/workflows/create-extension.md +156 -0
  222. package/src/resources/skills/create-gsd-extension/workflows/debug-extension.md +74 -0
  223. package/src/resources/skills/create-skill/SKILL.md +184 -0
  224. package/src/resources/skills/create-skill/references/api-security.md +226 -0
  225. package/src/resources/skills/create-skill/references/be-clear-and-direct.md +531 -0
  226. package/src/resources/skills/create-skill/references/common-patterns.md +595 -0
  227. package/src/resources/skills/create-skill/references/core-principles.md +437 -0
  228. package/src/resources/skills/create-skill/references/executable-code.md +175 -0
  229. package/src/resources/skills/create-skill/references/gsd-skill-ecosystem.md +68 -0
  230. package/src/resources/skills/create-skill/references/iteration-and-testing.md +474 -0
  231. package/src/resources/skills/create-skill/references/recommended-structure.md +168 -0
  232. package/src/resources/skills/create-skill/references/skill-structure.md +372 -0
  233. package/src/resources/skills/create-skill/references/use-xml-tags.md +466 -0
  234. package/src/resources/skills/create-skill/references/using-scripts.md +113 -0
  235. package/src/resources/skills/create-skill/references/using-templates.md +112 -0
  236. package/src/resources/skills/create-skill/references/workflows-and-validation.md +510 -0
  237. package/src/resources/skills/create-skill/templates/router-skill.md +73 -0
  238. package/src/resources/skills/create-skill/templates/simple-skill.md +33 -0
  239. package/src/resources/skills/create-skill/workflows/add-reference.md +96 -0
  240. package/src/resources/skills/create-skill/workflows/add-script.md +93 -0
  241. package/src/resources/skills/create-skill/workflows/add-template.md +74 -0
  242. package/src/resources/skills/create-skill/workflows/add-workflow.md +120 -0
  243. package/src/resources/skills/create-skill/workflows/audit-skill.md +148 -0
  244. package/src/resources/skills/create-skill/workflows/create-new-skill.md +196 -0
  245. package/src/resources/skills/create-skill/workflows/get-guidance.md +121 -0
  246. package/src/resources/skills/create-skill/workflows/upgrade-to-router.md +161 -0
  247. package/src/resources/skills/create-skill/workflows/verify-skill.md +204 -0
  248. package/src/resources/skills/react-best-practices/SKILL.md +1 -1
  249. package/dist/resources/extensions/gsd/auto-worktree-sync.ts +0 -199
  250. package/dist/resources/extensions/gsd/tests/worktree-db-integration.test.ts +0 -205
  251. package/dist/resources/extensions/gsd/tests/worktree-db.test.ts +0 -442
  252. package/dist/resources/extensions/mcporter/index.ts +0 -525
  253. package/src/resources/extensions/gsd/auto-worktree-sync.ts +0 -199
  254. package/src/resources/extensions/gsd/tests/worktree-db-integration.test.ts +0 -205
  255. package/src/resources/extensions/gsd/tests/worktree-db.test.ts +0 -442
  256. package/src/resources/extensions/mcporter/index.ts +0 -525
@@ -0,0 +1,544 @@
1
+ /**
2
+ * GSD Workflow Template Commands — /gsd start, /gsd templates
3
+ *
4
+ * Handles the `/gsd start [template] [description]` and `/gsd templates` commands.
5
+ * Resolves templates by name or auto-detection, then dispatches the workflow prompt.
6
+ */
7
+
8
+ import type { ExtensionAPI, ExtensionCommandContext } from "@gsd/pi-coding-agent";
9
+ import { existsSync, mkdirSync, readdirSync, readFileSync, writeFileSync } from "node:fs";
10
+ import { join } from "node:path";
11
+ import {
12
+ resolveByName,
13
+ autoDetect,
14
+ listTemplates,
15
+ getTemplateInfo,
16
+ loadWorkflowTemplate,
17
+ loadRegistry,
18
+ type TemplateMatch,
19
+ } from "./workflow-templates.js";
20
+ import { loadPrompt } from "./prompt-loader.js";
21
+ import { gsdRoot } from "./paths.js";
22
+ import { GitServiceImpl, runGit } from "./git-service.js";
23
+ import { loadEffectiveGSDPreferences } from "./preferences.js";
24
+ import { isAutoActive, isAutoPaused } from "./auto.js";
25
+
26
+ // ─── Helpers ─────────────────────────────────────────────────────────────────
27
+
28
+ /**
29
+ * Generate a URL-friendly slug from text.
30
+ */
31
+ function slugify(text: string): string {
32
+ return text
33
+ .toLowerCase()
34
+ .replace(/[^a-z0-9]+/g, "-")
35
+ .replace(/^-|-$/g, "")
36
+ .slice(0, 40)
37
+ .replace(/-$/, "");
38
+ }
39
+
40
+ /**
41
+ * Get the next workflow task number by scanning existing directories.
42
+ */
43
+ function getNextWorkflowNum(workflowDir: string): number {
44
+ if (!existsSync(workflowDir)) return 1;
45
+ try {
46
+ const entries = readdirSync(workflowDir, { withFileTypes: true });
47
+ let max = 0;
48
+ for (const entry of entries) {
49
+ if (!entry.isDirectory()) continue;
50
+ const match = entry.name.match(/^(\d{6})-(\d+)-/);
51
+ if (match) {
52
+ const num = parseInt(match[2], 10);
53
+ if (num > max) max = num;
54
+ }
55
+ }
56
+ return max + 1;
57
+ } catch {
58
+ return 1;
59
+ }
60
+ }
61
+
62
+ /**
63
+ * Format the date as YYMMDD for directory naming.
64
+ */
65
+ function datePrefix(): string {
66
+ const d = new Date();
67
+ const yy = String(d.getFullYear()).slice(2);
68
+ const mm = String(d.getMonth() + 1).padStart(2, "0");
69
+ const dd = String(d.getDate()).padStart(2, "0");
70
+ return `${yy}${mm}${dd}`;
71
+ }
72
+
73
+ // ─── State Types ─────────────────────────────────────────────────────────────
74
+
75
+ interface WorkflowPhaseState {
76
+ name: string;
77
+ index: number;
78
+ status: "pending" | "active" | "completed";
79
+ }
80
+
81
+ interface WorkflowState {
82
+ template: string;
83
+ templateName: string;
84
+ description: string;
85
+ branch: string;
86
+ phases: WorkflowPhaseState[];
87
+ currentPhase: number;
88
+ startedAt: string;
89
+ updatedAt: string;
90
+ completedAt?: string;
91
+ artifactDir: string;
92
+ }
93
+
94
+ /**
95
+ * Write a STATE.json file to track workflow execution state.
96
+ */
97
+ function writeWorkflowState(
98
+ artifactDir: string,
99
+ templateId: string,
100
+ templateName: string,
101
+ phases: string[],
102
+ description: string,
103
+ branch: string,
104
+ ): void {
105
+ const statePath = join(artifactDir, "STATE.json");
106
+ const state: WorkflowState = {
107
+ template: templateId,
108
+ templateName,
109
+ description,
110
+ branch,
111
+ phases: phases.map((p, i) => ({
112
+ name: p,
113
+ index: i,
114
+ status: i === 0 ? "active" as const : "pending" as const,
115
+ })),
116
+ currentPhase: 0,
117
+ startedAt: new Date().toISOString(),
118
+ updatedAt: new Date().toISOString(),
119
+ artifactDir,
120
+ };
121
+ writeFileSync(statePath, JSON.stringify(state, null, 2) + "\n");
122
+ }
123
+
124
+ /**
125
+ * Scan all workflow artifact directories for in-progress STATE.json files.
126
+ * Returns workflows that were started but not completed.
127
+ */
128
+ function findInProgressWorkflows(basePath: string): WorkflowState[] {
129
+ const workflowsRoot = join(gsdRoot(basePath), "workflows");
130
+ if (!existsSync(workflowsRoot)) return [];
131
+
132
+ const results: WorkflowState[] = [];
133
+ try {
134
+ // Scan each category dir (bugfixes/, features/, spikes/, etc.)
135
+ for (const category of readdirSync(workflowsRoot, { withFileTypes: true })) {
136
+ if (!category.isDirectory()) continue;
137
+ const categoryDir = join(workflowsRoot, category.name);
138
+
139
+ for (const workflow of readdirSync(categoryDir, { withFileTypes: true })) {
140
+ if (!workflow.isDirectory()) continue;
141
+ const statePath = join(categoryDir, workflow.name, "STATE.json");
142
+ if (!existsSync(statePath)) continue;
143
+
144
+ try {
145
+ const raw = readFileSync(statePath, "utf-8");
146
+ const state = JSON.parse(raw) as WorkflowState;
147
+ if (!state.completedAt) {
148
+ results.push(state);
149
+ }
150
+ } catch { /* corrupted state file — skip */ }
151
+ }
152
+ }
153
+ } catch { /* workflows dir unreadable — skip */ }
154
+
155
+ // Sort by most recently updated
156
+ results.sort((a, b) => b.updatedAt.localeCompare(a.updatedAt));
157
+ return results;
158
+ }
159
+
160
+ // ─── /gsd start ──────────────────────────────────────────────────────────────
161
+
162
+ export async function handleStart(
163
+ args: string,
164
+ ctx: ExtensionCommandContext,
165
+ pi: ExtensionAPI,
166
+ ): Promise<void> {
167
+ const trimmed = args.trim();
168
+
169
+ // /gsd start --list → same as /gsd templates
170
+ if (trimmed === "--list" || trimmed === "list") {
171
+ ctx.ui.notify(listTemplates(), "info");
172
+ return;
173
+ }
174
+
175
+ // ─── Auto-mode conflict guard ──────────────────────────────────────────
176
+ // Workflow templates dispatch their own messages and switch git branches,
177
+ // which would conflict with an active auto-mode dispatch loop.
178
+ if (isAutoActive()) {
179
+ ctx.ui.notify(
180
+ "Cannot start a workflow template while auto-mode is running.\n" +
181
+ "Run /gsd pause first, then /gsd start.",
182
+ "warning",
183
+ );
184
+ return;
185
+ }
186
+
187
+ if (isAutoPaused()) {
188
+ ctx.ui.notify(
189
+ "Auto-mode is paused. Starting a workflow template will run independently.\n" +
190
+ "The paused auto-mode session can be resumed later with /gsd auto.",
191
+ "info",
192
+ );
193
+ }
194
+
195
+ // ─── Resume detection ───────────────────────────────────────────────────
196
+ // /gsd start --resume or /gsd start resume → resume in-progress workflow
197
+ if (trimmed === "--resume" || trimmed === "resume") {
198
+ const basePath = process.cwd();
199
+ const inProgress = findInProgressWorkflows(basePath);
200
+ if (inProgress.length === 0) {
201
+ ctx.ui.notify("No in-progress workflows found.", "info");
202
+ return;
203
+ }
204
+
205
+ // Resume the most recent one
206
+ const wf = inProgress[0];
207
+ const activePhase = wf.phases.find(p => p.status === "active");
208
+ const completedCount = wf.phases.filter(p => p.status === "completed").length;
209
+
210
+ ctx.ui.notify(
211
+ `Resuming: ${wf.templateName}\n` +
212
+ `Description: ${wf.description}\n` +
213
+ `Progress: ${completedCount}/${wf.phases.length} phases completed\n` +
214
+ `Current phase: ${activePhase?.name ?? "unknown"}\n` +
215
+ `Branch: ${wf.branch}\n` +
216
+ `Artifacts: ${wf.artifactDir}`,
217
+ "info",
218
+ );
219
+
220
+ const workflowContent = loadWorkflowTemplate(wf.template);
221
+ if (!workflowContent) {
222
+ ctx.ui.notify(`Template "${wf.template}" workflow file not found.`, "warning");
223
+ return;
224
+ }
225
+
226
+ const prompt = loadPrompt("workflow-start", {
227
+ templateId: wf.template,
228
+ templateName: wf.templateName,
229
+ templateDescription: `RESUMING — pick up from phase "${activePhase?.name ?? "unknown"}" (${completedCount}/${wf.phases.length} phases done)`,
230
+ phases: wf.phases.map(p => `${p.name}${p.status === "completed" ? " ✓" : p.status === "active" ? " ←" : ""}`).join(" → "),
231
+ complexity: "resume",
232
+ artifactDir: wf.artifactDir,
233
+ branch: wf.branch,
234
+ description: wf.description,
235
+ issueRef: "(none)",
236
+ date: new Date().toISOString().split("T")[0],
237
+ workflowContent,
238
+ });
239
+
240
+ pi.sendMessage(
241
+ { customType: "gsd-workflow-template", content: prompt, display: false },
242
+ { triggerTurn: true },
243
+ );
244
+ return;
245
+ }
246
+
247
+ // Show in-progress workflows when /gsd start is called with no args
248
+ if (!trimmed) {
249
+ const basePath = process.cwd();
250
+ const inProgress = findInProgressWorkflows(basePath);
251
+ if (inProgress.length > 0) {
252
+ const wf = inProgress[0];
253
+ const activePhase = wf.phases.find(p => p.status === "active");
254
+ const completedCount = wf.phases.filter(p => p.status === "completed").length;
255
+ ctx.ui.notify(
256
+ `In-progress workflow found:\n` +
257
+ ` ${wf.templateName}: "${wf.description}"\n` +
258
+ ` Phase ${completedCount + 1}/${wf.phases.length}: ${activePhase?.name ?? "unknown"}\n\n` +
259
+ `Run /gsd start resume to continue it.\n`,
260
+ "info",
261
+ );
262
+ }
263
+ }
264
+
265
+ // /gsd start --dry-run <template> → preview without executing
266
+ const dryRun = trimmed.includes("--dry-run");
267
+ const cleanedArgs = trimmed.replace(/--dry-run\s*/, "").trim();
268
+
269
+ // Parse: first word might be a template name, rest is description
270
+ const parts = cleanedArgs.split(/\s+/);
271
+ const firstWord = parts[0] ?? "";
272
+
273
+ // Check for --issue flag (bugfix shortcut)
274
+ const issueMatch = cleanedArgs.match(/--issue\s+(\S+)/);
275
+ const issueRef = issueMatch ? issueMatch[1] : null;
276
+
277
+ // Try resolving first word as a template name
278
+ let match: TemplateMatch | null = null;
279
+ let description = "";
280
+
281
+ if (firstWord) {
282
+ match = resolveByName(firstWord);
283
+ if (match) {
284
+ // First word was a template name; rest is description
285
+ description = parts.slice(1).join(" ").replace(/--issue\s+\S+/, "").trim();
286
+ }
287
+ }
288
+
289
+ // If no explicit template, try auto-detection from the full input
290
+ if (!match && cleanedArgs) {
291
+ const detected = autoDetect(cleanedArgs);
292
+ if (detected.length === 1 || (detected.length > 0 && detected[0].confidence === "high")) {
293
+ match = detected[0];
294
+ description = cleanedArgs;
295
+ ctx.ui.notify(
296
+ `Auto-detected template: ${match.template.name} (matched: "${match.matchedTrigger}")`,
297
+ "info",
298
+ );
299
+ } else if (detected.length > 1) {
300
+ const choices = detected.slice(0, 4).map(
301
+ (m) => ` /gsd start ${m.id} ${cleanedArgs}`
302
+ );
303
+ ctx.ui.notify(
304
+ `Multiple templates could match. Pick one:\n\n${choices.join("\n")}\n\nOr specify explicitly: /gsd start <template> <description>`,
305
+ "info",
306
+ );
307
+ return;
308
+ }
309
+ }
310
+
311
+ // No template resolved at all
312
+ if (!match) {
313
+ if (!trimmed) {
314
+ ctx.ui.notify(
315
+ "Usage: /gsd start <template> [description]\n\n" +
316
+ "Templates:\n" +
317
+ " bugfix Triage → fix → verify → ship\n" +
318
+ " small-feature Scope → plan → implement → verify\n" +
319
+ " spike Scope → research → synthesize\n" +
320
+ " hotfix Fix → ship (minimal ceremony)\n" +
321
+ " refactor Inventory → plan → migrate → verify\n" +
322
+ " security-audit Scan → triage → remediate → re-scan\n" +
323
+ " dep-upgrade Assess → upgrade → fix → verify\n" +
324
+ " full-project Complete GSD with full ceremony\n\n" +
325
+ "Examples:\n" +
326
+ " /gsd start bugfix fix login button not responding\n" +
327
+ " /gsd start spike evaluate auth libraries\n" +
328
+ " /gsd start hotfix critical: API returns 500\n\n" +
329
+ "Flags:\n" +
330
+ " --dry-run Preview what would happen without executing\n" +
331
+ " --issue <ref> Link to a GitHub issue\n\n" +
332
+ "Run /gsd templates for detailed template info.",
333
+ "info",
334
+ );
335
+ } else {
336
+ ctx.ui.notify(
337
+ `No template matched "${firstWord}". Run /gsd start to see available templates.`,
338
+ "warning",
339
+ );
340
+ }
341
+ return;
342
+ }
343
+
344
+ // ─── Resolved template ───────────────────────────────────────────────────
345
+
346
+ const templateId = match.id;
347
+ const template = match.template;
348
+ const basePath = process.cwd();
349
+ const date = new Date().toISOString().split("T")[0];
350
+
351
+ // Load the workflow template content
352
+ const workflowContent = loadWorkflowTemplate(templateId);
353
+ if (!workflowContent) {
354
+ ctx.ui.notify(
355
+ `Template "${templateId}" is registered but its workflow file (${template.file}) hasn't been created yet.`,
356
+ "warning",
357
+ );
358
+ return;
359
+ }
360
+
361
+ // ─── Dry-run mode: preview without executing ────────────────────────────
362
+
363
+ if (dryRun) {
364
+ const slug = slugify(description || templateId);
365
+ const lines = [
366
+ `DRY RUN — ${template.name} (${templateId})\n`,
367
+ `Description: ${description || "(none)"}`,
368
+ `Complexity: ${template.estimated_complexity}`,
369
+ `Phases: ${template.phases.join(" → ")}`,
370
+ "",
371
+ ];
372
+ if (template.artifact_dir) {
373
+ const prefix = datePrefix();
374
+ const num = getNextWorkflowNum(join(basePath, template.artifact_dir));
375
+ lines.push(`Artifact dir: ${template.artifact_dir}${prefix}-${num}-${slug}`);
376
+ } else {
377
+ lines.push("Artifact dir: (none — hotfix mode)");
378
+ }
379
+ lines.push(`Branch: gsd/${templateId}/${slug}`);
380
+ if (issueRef) lines.push(`Issue: ${issueRef}`);
381
+ lines.push("", "No changes made. Remove --dry-run to execute.");
382
+ ctx.ui.notify(lines.join("\n"), "info");
383
+ return;
384
+ }
385
+
386
+ // ─── Route full-project to standard GSD workflow ────────────────────────
387
+
388
+ if (templateId === "full-project") {
389
+ const root = gsdRoot(basePath);
390
+ if (!existsSync(root)) {
391
+ ctx.ui.notify(
392
+ "Routing to /gsd init for full project setup...",
393
+ "info",
394
+ );
395
+ // Trigger /gsd init by dispatching to the handler
396
+ pi.sendMessage(
397
+ {
398
+ customType: "gsd-workflow-template",
399
+ content: "The user wants to start a full GSD project. Run `/gsd init` to bootstrap the project, then `/gsd auto` to begin execution.",
400
+ display: false,
401
+ },
402
+ { triggerTurn: true },
403
+ );
404
+ } else {
405
+ ctx.ui.notify(
406
+ "Project already initialized. Use `/gsd auto` to continue or `/gsd discuss` to start a new milestone.",
407
+ "info",
408
+ );
409
+ }
410
+ return;
411
+ }
412
+
413
+ // ─── Create artifact directory ──────────────────────────────────────────
414
+
415
+ let artifactDir = "";
416
+ if (template.artifact_dir) {
417
+ const slug = slugify(description || templateId);
418
+ const prefix = datePrefix();
419
+ const num = getNextWorkflowNum(join(basePath, template.artifact_dir));
420
+ artifactDir = `${template.artifact_dir}${prefix}-${num}-${slug}`;
421
+ mkdirSync(join(basePath, artifactDir), { recursive: true });
422
+ }
423
+
424
+ // ─── Create git branch (unless isolation: none) ─────────────────────────
425
+
426
+ const gitPrefs = loadEffectiveGSDPreferences()?.preferences?.git ?? {};
427
+ const git = new GitServiceImpl(basePath, gitPrefs);
428
+ const skipBranch = gitPrefs.isolation === "none";
429
+ const slug = slugify(description || templateId);
430
+ const branchName = `gsd/${templateId}/${slug}`;
431
+ let branchCreated = false;
432
+
433
+ if (!skipBranch) {
434
+ try {
435
+ const current = git.getCurrentBranch();
436
+ if (current !== branchName) {
437
+ try {
438
+ git.autoCommit("workflow-template", templateId, []);
439
+ } catch { /* nothing to commit */ }
440
+ runGit(basePath, ["checkout", "-b", branchName]);
441
+ branchCreated = true;
442
+ }
443
+ } catch (err) {
444
+ const message = err instanceof Error ? err.message : String(err);
445
+ ctx.ui.notify(
446
+ `Could not create branch ${branchName}: ${message}. Working on current branch.`,
447
+ "warning",
448
+ );
449
+ }
450
+ }
451
+
452
+ const actualBranch = branchCreated ? branchName : git.getCurrentBranch();
453
+
454
+ // ─── Write workflow state for resume support ────────────────────────────
455
+
456
+ if (artifactDir) {
457
+ writeWorkflowState(
458
+ join(basePath, artifactDir),
459
+ templateId,
460
+ template.name,
461
+ template.phases,
462
+ description,
463
+ actualBranch,
464
+ );
465
+ }
466
+
467
+ // ─── Notify and dispatch ────────────────────────────────────────────────
468
+
469
+ const infoLines = [
470
+ `Starting workflow: ${template.name}`,
471
+ `Phases: ${template.phases.join(" → ")}`,
472
+ ];
473
+ if (artifactDir) infoLines.push(`Artifacts: ${artifactDir}`);
474
+ infoLines.push(`Branch: ${actualBranch}`);
475
+ ctx.ui.notify(infoLines.join("\n"), "info");
476
+
477
+ const prompt = loadPrompt("workflow-start", {
478
+ templateId,
479
+ templateName: template.name,
480
+ templateDescription: template.description,
481
+ phases: template.phases.join(" → "),
482
+ complexity: template.estimated_complexity,
483
+ artifactDir: artifactDir || "(none)",
484
+ branch: actualBranch,
485
+ description: description || "(none provided)",
486
+ issueRef: issueRef || "(none)",
487
+ date,
488
+ workflowContent,
489
+ });
490
+
491
+ pi.sendMessage(
492
+ {
493
+ customType: "gsd-workflow-template",
494
+ content: prompt,
495
+ display: false,
496
+ },
497
+ { triggerTurn: true },
498
+ );
499
+ }
500
+
501
+ // ─── /gsd templates ──────────────────────────────────────────────────────────
502
+
503
+ export async function handleTemplates(
504
+ args: string,
505
+ ctx: ExtensionCommandContext,
506
+ ): Promise<void> {
507
+ const trimmed = args.trim();
508
+
509
+ // /gsd templates info <name>
510
+ if (trimmed.startsWith("info ")) {
511
+ const name = trimmed.replace(/^info\s+/, "").trim();
512
+ const info = getTemplateInfo(name);
513
+ if (info) {
514
+ ctx.ui.notify(info, "info");
515
+ } else {
516
+ ctx.ui.notify(
517
+ `Unknown template "${name}". Run /gsd templates to see available templates.`,
518
+ "warning",
519
+ );
520
+ }
521
+ return;
522
+ }
523
+
524
+ // /gsd templates — list all
525
+ ctx.ui.notify(listTemplates(), "info");
526
+ }
527
+
528
+ /**
529
+ * Return template IDs for autocomplete in /gsd templates info <name>.
530
+ */
531
+ export function getTemplateCompletions(prefix: string): Array<{ value: string; label: string; description: string }> {
532
+ try {
533
+ const registry = loadRegistry();
534
+ return Object.entries(registry.templates)
535
+ .filter(([id]) => id.startsWith(prefix))
536
+ .map(([id, entry]) => ({
537
+ value: `info ${id}`,
538
+ label: id,
539
+ description: entry.description,
540
+ }));
541
+ } catch {
542
+ return [];
543
+ }
544
+ }
@@ -8,6 +8,7 @@ import type { ExtensionAPI, ExtensionCommandContext } from "@gsd/pi-coding-agent
8
8
  import type { GSDState } from "./types.js";
9
9
  import { existsSync, readFileSync, unlinkSync } from "node:fs";
10
10
  import { join } from "node:path";
11
+ import { gsdRoot } from "./paths.js";
11
12
  import { enableDebug } from "./debug-logger.js";
12
13
  import { deriveState } from "./state.js";
13
14
  import { GSDDashboardOverlay } from "./dashboard-overlay.js";
@@ -43,6 +44,7 @@ import { handleInspect } from "./commands-inspect.js";
43
44
  import { handleCleanupBranches, handleCleanupSnapshots, handleSkip, handleDryRun } from "./commands-maintenance.js";
44
45
  import { handleDoctor, handleSteer, handleCapture, handleTriage, handleKnowledge, handleRunHook, handleUpdate, handleSkillHealth } from "./commands-handlers.js";
45
46
  import { handleLogs } from "./commands-logs.js";
47
+ import { handleStart, handleTemplates, getTemplateCompletions } from "./commands-workflow-templates.js";
46
48
 
47
49
 
48
50
  /** Resolve the effective project root, accounting for worktree paths. */
@@ -54,7 +56,7 @@ export function projectRoot(): string {
54
56
 
55
57
  export function registerGSDCommand(pi: ExtensionAPI): void {
56
58
  pi.registerCommand("gsd", {
57
- description: "GSD — Get Shit Done: /gsd help|next|auto|stop|pause|status|visualize|queue|quick|capture|triage|dispatch|history|undo|skip|export|cleanup|mode|prefs|config|keys|hooks|run-hook|skill-health|doctor|forensics|migrate|remote|steer|knowledge|new-milestone|parallel|update",
59
+ description: "GSD — Get Shit Done: /gsd help|start|templates|next|auto|stop|pause|status|visualize|queue|quick|capture|triage|dispatch|history|undo|skip|export|cleanup|mode|prefs|config|keys|hooks|run-hook|skill-health|doctor|forensics|migrate|remote|steer|knowledge|new-milestone|parallel|update",
58
60
  getArgumentCompletions: (prefix: string) => {
59
61
  const subcommands = [
60
62
  { cmd: "help", desc: "Categorized command reference with descriptions" },
@@ -97,6 +99,8 @@ export function registerGSDCommand(pi: ExtensionAPI): void {
97
99
  { cmd: "park", desc: "Park a milestone — skip without deleting" },
98
100
  { cmd: "unpark", desc: "Reactivate a parked milestone" },
99
101
  { cmd: "update", desc: "Update GSD to the latest version" },
102
+ { cmd: "start", desc: "Start a workflow template (bugfix, spike, feature, etc.)" },
103
+ { cmd: "templates", desc: "List available workflow templates" },
100
104
  ];
101
105
  const parts = prefix.trim().split(/\s+/);
102
106
 
@@ -282,6 +286,42 @@ export function registerGSDCommand(pi: ExtensionAPI): void {
282
286
  .map((s) => ({ value: `knowledge ${s.cmd}`, label: s.cmd, description: s.desc }));
283
287
  }
284
288
 
289
+ if (parts[0] === "start" && parts.length <= 2) {
290
+ const subPrefix = parts[1] ?? "";
291
+ const subs = [
292
+ { cmd: "bugfix", desc: "Triage, fix, test, and ship a bug fix" },
293
+ { cmd: "small-feature", desc: "Lightweight feature with optional discussion" },
294
+ { cmd: "spike", desc: "Research, prototype, and document findings" },
295
+ { cmd: "hotfix", desc: "Minimal: fix it, test it, ship it" },
296
+ { cmd: "refactor", desc: "Inventory, plan waves, migrate, verify" },
297
+ { cmd: "security-audit", desc: "Scan, triage, remediate, re-scan" },
298
+ { cmd: "dep-upgrade", desc: "Assess, upgrade, fix breaks, verify" },
299
+ { cmd: "full-project", desc: "Complete GSD workflow with full ceremony" },
300
+ { cmd: "resume", desc: "Resume an in-progress workflow" },
301
+ { cmd: "--list", desc: "List all available templates" },
302
+ { cmd: "--dry-run", desc: "Preview workflow without executing" },
303
+ ];
304
+ return subs
305
+ .filter((s) => s.cmd.startsWith(subPrefix))
306
+ .map((s) => ({ value: `start ${s.cmd}`, label: s.cmd, description: s.desc }));
307
+ }
308
+
309
+ if (parts[0] === "templates" && parts.length <= 2) {
310
+ const subPrefix = parts[1] ?? "";
311
+ const subs = [
312
+ { cmd: "info", desc: "Show detailed template info" },
313
+ ];
314
+ return subs
315
+ .filter((s) => s.cmd.startsWith(subPrefix))
316
+ .map((s) => ({ value: `templates ${s.cmd}`, label: s.cmd, description: s.desc }));
317
+ }
318
+
319
+ if (parts[0] === "templates" && parts[1] === "info" && parts.length <= 3) {
320
+ const namePrefix = parts[2] ?? "";
321
+ return getTemplateCompletions(namePrefix)
322
+ .map((c) => ({ value: `templates ${c.value}`, label: c.label, description: c.description }));
323
+ }
324
+
285
325
  if (parts[0] === "doctor") {
286
326
  const modePrefix = parts[1] ?? "";
287
327
  const modes = [
@@ -659,7 +699,7 @@ export function registerGSDCommand(pi: ExtensionAPI): void {
659
699
 
660
700
  if (trimmed === "new-milestone") {
661
701
  const basePath = projectRoot();
662
- const headlessContextPath = join(basePath, ".gsd", "runtime", "headless-context.md");
702
+ const headlessContextPath = join(gsdRoot(basePath), "runtime", "headless-context.md");
663
703
  if (existsSync(headlessContextPath)) {
664
704
  const seedContext = readFileSync(headlessContextPath, "utf-8");
665
705
  try { unlinkSync(headlessContextPath); } catch { /* non-fatal */ }
@@ -773,6 +813,17 @@ Examples:
773
813
  return;
774
814
  }
775
815
 
816
+ // ─── Workflow Templates ────────────────────────────────────────
817
+ if (trimmed === "start" || trimmed.startsWith("start ")) {
818
+ await handleStart(trimmed.replace(/^start\s*/, "").trim(), ctx, pi);
819
+ return;
820
+ }
821
+
822
+ if (trimmed === "templates" || trimmed.startsWith("templates ")) {
823
+ await handleTemplates(trimmed.replace(/^templates\s*/, "").trim(), ctx);
824
+ return;
825
+ }
826
+
776
827
  if (trimmed === "") {
777
828
  // Bare /gsd defaults to step mode
778
829
  await startAuto(ctx, pi, projectRoot(), false, { step: true });
@@ -791,6 +842,8 @@ function showHelp(ctx: ExtensionCommandContext): void {
791
842
  const lines = [
792
843
  "GSD — Get Shit Done\n",
793
844
  "WORKFLOW",
845
+ " /gsd start <tpl> Start a workflow template (bugfix, spike, feature, hotfix, etc.)",
846
+ " /gsd templates List available workflow templates [info <name>]",
794
847
  " /gsd Run next unit in step mode (same as /gsd next)",
795
848
  " /gsd next Execute next task, then pause [--dry-run] [--verbose]",
796
849
  " /gsd auto Run all queued units continuously [--verbose]",
@@ -9,6 +9,7 @@
9
9
  import { existsSync, readdirSync, readFileSync, statSync } from "node:fs";
10
10
  import { join } from "node:path";
11
11
  import { homedir } from "node:os";
12
+ import { gsdRoot } from "./paths.js";
12
13
 
13
14
  // ─── Types ──────────────────────────────────────────────────────────────────────
14
15
 
@@ -214,7 +215,7 @@ export function detectV1Planning(basePath: string): V1Detection | null {
214
215
  // ─── V2 GSD Detection ──────────────────────────────────────────────────────────
215
216
 
216
217
  function detectV2Gsd(basePath: string): V2Detection | null {
217
- const gsdPath = join(basePath, ".gsd");
218
+ const gsdPath = gsdRoot(basePath);
218
219
 
219
220
  if (!existsSync(gsdPath)) return null;
220
221