gsd-pi 2.41.0-dev.0acbce9 → 2.41.0-dev.5a170d0

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 (291) hide show
  1. package/README.md +1 -1
  2. package/dist/cli-web-branch.d.ts +6 -0
  3. package/dist/cli-web-branch.js +17 -0
  4. package/dist/onboarding.js +2 -1
  5. package/dist/resources/extensions/gsd/auto/loop.js +89 -1
  6. package/dist/resources/extensions/gsd/auto/phases.js +28 -10
  7. package/dist/resources/extensions/gsd/auto/session.js +6 -0
  8. package/dist/resources/extensions/gsd/auto-dashboard.js +8 -2
  9. package/dist/resources/extensions/gsd/auto-dispatch.js +19 -2
  10. package/dist/resources/extensions/gsd/auto-post-unit.js +7 -0
  11. package/dist/resources/extensions/gsd/auto-recovery.js +12 -4
  12. package/dist/resources/extensions/gsd/auto-start.js +8 -3
  13. package/dist/resources/extensions/gsd/auto-worktree.js +147 -13
  14. package/dist/resources/extensions/gsd/auto.js +64 -2
  15. package/dist/resources/extensions/gsd/bootstrap/db-tools.js +199 -164
  16. package/dist/resources/extensions/gsd/bootstrap/journal-tools.js +62 -0
  17. package/dist/resources/extensions/gsd/bootstrap/register-extension.js +2 -0
  18. package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +16 -0
  19. package/dist/resources/extensions/gsd/bootstrap/tool-call-loop-guard.js +7 -2
  20. package/dist/resources/extensions/gsd/commands/catalog.js +40 -1
  21. package/dist/resources/extensions/gsd/commands/handlers/core.js +1 -0
  22. package/dist/resources/extensions/gsd/commands/handlers/ops.js +5 -0
  23. package/dist/resources/extensions/gsd/commands/handlers/workflow.js +146 -0
  24. package/dist/resources/extensions/gsd/context-injector.js +74 -0
  25. package/dist/resources/extensions/gsd/context-store.js +4 -3
  26. package/dist/resources/extensions/gsd/custom-execution-policy.js +47 -0
  27. package/dist/resources/extensions/gsd/custom-verification.js +145 -0
  28. package/dist/resources/extensions/gsd/custom-workflow-engine.js +164 -0
  29. package/dist/resources/extensions/gsd/dashboard-overlay.js +1 -0
  30. package/dist/resources/extensions/gsd/db-writer.js +5 -2
  31. package/dist/resources/extensions/gsd/definition-loader.js +352 -0
  32. package/dist/resources/extensions/gsd/detection.js +1 -1
  33. package/dist/resources/extensions/gsd/dev-execution-policy.js +24 -0
  34. package/dist/resources/extensions/gsd/dev-workflow-engine.js +82 -0
  35. package/dist/resources/extensions/gsd/doctor.js +11 -1
  36. package/dist/resources/extensions/gsd/engine-resolver.js +40 -0
  37. package/dist/resources/extensions/gsd/engine-types.js +8 -0
  38. package/dist/resources/extensions/gsd/execution-policy.js +8 -0
  39. package/dist/resources/extensions/gsd/exit-command.js +12 -2
  40. package/dist/resources/extensions/gsd/export.js +9 -13
  41. package/dist/resources/extensions/gsd/extension-manifest.json +2 -2
  42. package/dist/resources/extensions/gsd/files.js +28 -11
  43. package/dist/resources/extensions/gsd/forensics.js +10 -3
  44. package/dist/resources/extensions/gsd/git-service.js +5 -1
  45. package/dist/resources/extensions/gsd/graph.js +225 -0
  46. package/dist/resources/extensions/gsd/gsd-db.js +25 -8
  47. package/dist/resources/extensions/gsd/guided-flow-queue.js +1 -1
  48. package/dist/resources/extensions/gsd/guided-flow.js +7 -3
  49. package/dist/resources/extensions/gsd/journal.js +85 -0
  50. package/dist/resources/extensions/gsd/md-importer.js +5 -0
  51. package/dist/resources/extensions/gsd/milestone-ids.js +1 -1
  52. package/dist/resources/extensions/gsd/native-git-bridge.js +2 -2
  53. package/dist/resources/extensions/gsd/post-unit-hooks.js +24 -412
  54. package/dist/resources/extensions/gsd/preferences-types.js +1 -0
  55. package/dist/resources/extensions/gsd/preferences.js +1 -0
  56. package/dist/resources/extensions/gsd/prompt-loader.js +34 -4
  57. package/dist/resources/extensions/gsd/prompts/complete-milestone.md +11 -10
  58. package/dist/resources/extensions/gsd/prompts/discuss-headless.md +2 -2
  59. package/dist/resources/extensions/gsd/prompts/discuss.md +1 -1
  60. package/dist/resources/extensions/gsd/prompts/queue.md +1 -1
  61. package/dist/resources/extensions/gsd/repo-identity.js +46 -2
  62. package/dist/resources/extensions/gsd/rule-registry.js +489 -0
  63. package/dist/resources/extensions/gsd/rule-types.js +6 -0
  64. package/dist/resources/extensions/gsd/run-manager.js +134 -0
  65. package/dist/resources/extensions/gsd/service-tier.js +138 -0
  66. package/dist/resources/extensions/gsd/structured-data-formatter.js +2 -1
  67. package/dist/resources/extensions/gsd/templates/decisions.md +2 -2
  68. package/dist/resources/extensions/gsd/workflow-engine.js +7 -0
  69. package/dist/resources/extensions/gsd/workflow-templates.js +13 -1
  70. package/dist/resources/extensions/gsd/worktree-manager.js +20 -6
  71. package/dist/resources/extensions/gsd/worktree-resolver.js +19 -2
  72. package/dist/resources/extensions/subagent/index.js +7 -3
  73. package/dist/resources/extensions/voice/index.js +4 -4
  74. package/dist/resources/skills/create-workflow/SKILL.md +103 -0
  75. package/dist/resources/skills/create-workflow/references/feature-patterns.md +128 -0
  76. package/dist/resources/skills/create-workflow/references/verification-policies.md +76 -0
  77. package/dist/resources/skills/create-workflow/references/yaml-schema-v1.md +46 -0
  78. package/dist/resources/skills/create-workflow/templates/blog-post-pipeline.yaml +60 -0
  79. package/dist/resources/skills/create-workflow/templates/code-audit.yaml +60 -0
  80. package/dist/resources/skills/create-workflow/templates/release-checklist.yaml +66 -0
  81. package/dist/resources/skills/create-workflow/templates/workflow-definition.yaml +32 -0
  82. package/dist/resources/skills/create-workflow/workflows/create-from-scratch.md +104 -0
  83. package/dist/resources/skills/create-workflow/workflows/create-from-template.md +72 -0
  84. package/dist/web/standalone/.next/BUILD_ID +1 -1
  85. package/dist/web/standalone/.next/app-path-routes-manifest.json +16 -16
  86. package/dist/web/standalone/.next/build-manifest.json +3 -3
  87. package/dist/web/standalone/.next/prerender-manifest.json +3 -3
  88. package/dist/web/standalone/.next/react-loadable-manifest.json +1 -1
  89. package/dist/web/standalone/.next/server/app/_global-error.html +2 -2
  90. package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
  91. package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  92. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
  93. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
  94. package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  95. package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  96. package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  97. package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
  98. package/dist/web/standalone/.next/server/app/_not-found.rsc +1 -1
  99. package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
  100. package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  101. package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +1 -1
  102. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  103. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  104. package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
  105. package/dist/web/standalone/.next/server/app/api/boot/route.js +1 -1
  106. package/dist/web/standalone/.next/server/app/api/captures/route.js +1 -1
  107. package/dist/web/standalone/.next/server/app/api/cleanup/route.js +1 -1
  108. package/dist/web/standalone/.next/server/app/api/doctor/route.js +1 -1
  109. package/dist/web/standalone/.next/server/app/api/export-data/route.js +1 -1
  110. package/dist/web/standalone/.next/server/app/api/forensics/route.js +1 -1
  111. package/dist/web/standalone/.next/server/app/api/history/route.js +1 -1
  112. package/dist/web/standalone/.next/server/app/api/hooks/route.js +1 -1
  113. package/dist/web/standalone/.next/server/app/api/recovery/route.js +1 -1
  114. package/dist/web/standalone/.next/server/app/api/settings-data/route.js +1 -1
  115. package/dist/web/standalone/.next/server/app/api/skill-health/route.js +1 -1
  116. package/dist/web/standalone/.next/server/app/api/terminal/input/route.js +1 -1
  117. package/dist/web/standalone/.next/server/app/api/terminal/resize/route.js +1 -1
  118. package/dist/web/standalone/.next/server/app/api/undo/route.js +1 -1
  119. package/dist/web/standalone/.next/server/app/api/visualizer/route.js +1 -1
  120. package/dist/web/standalone/.next/server/app/index.html +1 -1
  121. package/dist/web/standalone/.next/server/app/index.rsc +1 -1
  122. package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +1 -1
  123. package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +1 -1
  124. package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
  125. package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +1 -1
  126. package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
  127. package/dist/web/standalone/.next/server/app-paths-manifest.json +16 -16
  128. package/dist/web/standalone/.next/server/chunks/229.js +3 -3
  129. package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
  130. package/dist/web/standalone/.next/server/middleware-react-loadable-manifest.js +1 -1
  131. package/dist/web/standalone/.next/server/pages/404.html +1 -1
  132. package/dist/web/standalone/.next/server/pages/500.html +2 -2
  133. package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
  134. package/dist/web/standalone/.next/static/chunks/4024.c195dc1fdd2adbea.js +9 -0
  135. package/dist/web/standalone/.next/static/chunks/{webpack-9afaaebf6042a1d7.js → webpack-fa307370fcf9fb2c.js} +1 -1
  136. package/dist/web-mode.d.ts +2 -0
  137. package/dist/web-mode.js +29 -7
  138. package/package.json +1 -1
  139. package/packages/native/src/__tests__/text.test.mjs +33 -0
  140. package/packages/pi-coding-agent/dist/core/discovery-cache.test.js +3 -1
  141. package/packages/pi-coding-agent/dist/core/discovery-cache.test.js.map +1 -1
  142. package/packages/pi-coding-agent/dist/modes/interactive/components/login-dialog.d.ts.map +1 -1
  143. package/packages/pi-coding-agent/dist/modes/interactive/components/login-dialog.js +10 -7
  144. package/packages/pi-coding-agent/dist/modes/interactive/components/login-dialog.js.map +1 -1
  145. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  146. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js +4 -0
  147. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js.map +1 -1
  148. package/packages/pi-coding-agent/src/core/discovery-cache.test.ts +4 -2
  149. package/packages/pi-coding-agent/src/modes/interactive/components/login-dialog.ts +11 -7
  150. package/packages/pi-coding-agent/src/modes/interactive/interactive-mode.ts +5 -0
  151. package/src/resources/extensions/gsd/auto/loop-deps.ts +5 -1
  152. package/src/resources/extensions/gsd/auto/loop.ts +101 -1
  153. package/src/resources/extensions/gsd/auto/phases.ts +30 -10
  154. package/src/resources/extensions/gsd/auto/session.ts +6 -0
  155. package/src/resources/extensions/gsd/auto/types.ts +4 -0
  156. package/src/resources/extensions/gsd/auto-dashboard.ts +9 -2
  157. package/src/resources/extensions/gsd/auto-dispatch.ts +25 -5
  158. package/src/resources/extensions/gsd/auto-post-unit.ts +8 -0
  159. package/src/resources/extensions/gsd/auto-recovery.ts +12 -4
  160. package/src/resources/extensions/gsd/auto-start.ts +8 -3
  161. package/src/resources/extensions/gsd/auto-worktree.ts +162 -18
  162. package/src/resources/extensions/gsd/auto.ts +71 -2
  163. package/src/resources/extensions/gsd/bootstrap/db-tools.ts +209 -162
  164. package/src/resources/extensions/gsd/bootstrap/journal-tools.ts +62 -0
  165. package/src/resources/extensions/gsd/bootstrap/register-extension.ts +2 -0
  166. package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +13 -0
  167. package/src/resources/extensions/gsd/bootstrap/tool-call-loop-guard.ts +9 -2
  168. package/src/resources/extensions/gsd/commands/catalog.ts +40 -1
  169. package/src/resources/extensions/gsd/commands/handlers/core.ts +1 -0
  170. package/src/resources/extensions/gsd/commands/handlers/ops.ts +5 -0
  171. package/src/resources/extensions/gsd/commands/handlers/workflow.ts +164 -0
  172. package/src/resources/extensions/gsd/context-injector.ts +100 -0
  173. package/src/resources/extensions/gsd/context-store.ts +4 -3
  174. package/src/resources/extensions/gsd/custom-execution-policy.ts +73 -0
  175. package/src/resources/extensions/gsd/custom-verification.ts +180 -0
  176. package/src/resources/extensions/gsd/custom-workflow-engine.ts +216 -0
  177. package/src/resources/extensions/gsd/dashboard-overlay.ts +1 -0
  178. package/src/resources/extensions/gsd/db-writer.ts +6 -2
  179. package/src/resources/extensions/gsd/definition-loader.ts +462 -0
  180. package/src/resources/extensions/gsd/detection.ts +1 -1
  181. package/src/resources/extensions/gsd/dev-execution-policy.ts +51 -0
  182. package/src/resources/extensions/gsd/dev-workflow-engine.ts +110 -0
  183. package/src/resources/extensions/gsd/doctor.ts +12 -1
  184. package/src/resources/extensions/gsd/engine-resolver.ts +57 -0
  185. package/src/resources/extensions/gsd/engine-types.ts +71 -0
  186. package/src/resources/extensions/gsd/execution-policy.ts +43 -0
  187. package/src/resources/extensions/gsd/exit-command.ts +14 -2
  188. package/src/resources/extensions/gsd/export.ts +8 -15
  189. package/src/resources/extensions/gsd/extension-manifest.json +2 -2
  190. package/src/resources/extensions/gsd/files.ts +29 -12
  191. package/src/resources/extensions/gsd/forensics.ts +9 -3
  192. package/src/resources/extensions/gsd/git-service.ts +5 -4
  193. package/src/resources/extensions/gsd/graph.ts +312 -0
  194. package/src/resources/extensions/gsd/gsd-db.ts +37 -8
  195. package/src/resources/extensions/gsd/guided-flow-queue.ts +1 -1
  196. package/src/resources/extensions/gsd/guided-flow.ts +7 -3
  197. package/src/resources/extensions/gsd/journal.ts +134 -0
  198. package/src/resources/extensions/gsd/md-importer.ts +6 -0
  199. package/src/resources/extensions/gsd/milestone-ids.ts +1 -1
  200. package/src/resources/extensions/gsd/native-git-bridge.ts +2 -2
  201. package/src/resources/extensions/gsd/post-unit-hooks.ts +24 -462
  202. package/src/resources/extensions/gsd/preferences-types.ts +3 -0
  203. package/src/resources/extensions/gsd/preferences.ts +1 -0
  204. package/src/resources/extensions/gsd/prompt-loader.ts +35 -4
  205. package/src/resources/extensions/gsd/prompts/complete-milestone.md +11 -10
  206. package/src/resources/extensions/gsd/prompts/discuss-headless.md +2 -2
  207. package/src/resources/extensions/gsd/prompts/discuss.md +1 -1
  208. package/src/resources/extensions/gsd/prompts/queue.md +1 -1
  209. package/src/resources/extensions/gsd/repo-identity.ts +47 -2
  210. package/src/resources/extensions/gsd/rule-registry.ts +599 -0
  211. package/src/resources/extensions/gsd/rule-types.ts +68 -0
  212. package/src/resources/extensions/gsd/run-manager.ts +180 -0
  213. package/src/resources/extensions/gsd/service-tier.ts +171 -0
  214. package/src/resources/extensions/gsd/structured-data-formatter.ts +3 -1
  215. package/src/resources/extensions/gsd/templates/decisions.md +2 -2
  216. package/src/resources/extensions/gsd/tests/auto-loop.test.ts +103 -120
  217. package/src/resources/extensions/gsd/tests/auto-recovery.test.ts +85 -0
  218. package/src/resources/extensions/gsd/tests/auto-secrets-gate.test.ts +2 -2
  219. package/src/resources/extensions/gsd/tests/auto-worktree-milestone-merge.test.ts +202 -0
  220. package/src/resources/extensions/gsd/tests/bundled-workflow-defs.test.ts +180 -0
  221. package/src/resources/extensions/gsd/tests/captures.test.ts +12 -1
  222. package/src/resources/extensions/gsd/tests/commands-workflow-custom.test.ts +283 -0
  223. package/src/resources/extensions/gsd/tests/context-injector.test.ts +313 -0
  224. package/src/resources/extensions/gsd/tests/context-store.test.ts +10 -5
  225. package/src/resources/extensions/gsd/tests/continue-here.test.ts +20 -20
  226. package/src/resources/extensions/gsd/tests/custom-engine-loop-integration.test.ts +540 -0
  227. package/src/resources/extensions/gsd/tests/custom-verification.test.ts +382 -0
  228. package/src/resources/extensions/gsd/tests/custom-workflow-engine.test.ts +339 -0
  229. package/src/resources/extensions/gsd/tests/dashboard-custom-engine.test.ts +87 -0
  230. package/src/resources/extensions/gsd/tests/db-writer.test.ts +10 -0
  231. package/src/resources/extensions/gsd/tests/definition-loader.test.ts +778 -0
  232. package/src/resources/extensions/gsd/tests/dev-engine-wrapper.test.ts +318 -0
  233. package/src/resources/extensions/gsd/tests/doctor-completion-deferral.test.ts +15 -10
  234. package/src/resources/extensions/gsd/tests/doctor-fixlevel.test.ts +5 -4
  235. package/src/resources/extensions/gsd/tests/doctor-roadmap-summary-atomicity.test.ts +167 -0
  236. package/src/resources/extensions/gsd/tests/doctor-task-done-missing-summary-slice-loop.test.ts +174 -0
  237. package/src/resources/extensions/gsd/tests/e2e-workflow-pipeline-integration.test.ts +476 -0
  238. package/src/resources/extensions/gsd/tests/engine-interfaces-contract.test.ts +271 -0
  239. package/src/resources/extensions/gsd/tests/exit-command.test.ts +55 -0
  240. package/src/resources/extensions/gsd/tests/graph-operations.test.ts +599 -0
  241. package/src/resources/extensions/gsd/tests/gsd-db.test.ts +8 -1
  242. package/src/resources/extensions/gsd/tests/gsd-tools.test.ts +7 -7
  243. package/src/resources/extensions/gsd/tests/iterate-engine-integration.test.ts +429 -0
  244. package/src/resources/extensions/gsd/tests/journal-integration.test.ts +513 -0
  245. package/src/resources/extensions/gsd/tests/journal-query-tool.test.ts +147 -0
  246. package/src/resources/extensions/gsd/tests/journal.test.ts +386 -0
  247. package/src/resources/extensions/gsd/tests/md-importer.test.ts +31 -1
  248. package/src/resources/extensions/gsd/tests/memory-store.test.ts +2 -2
  249. package/src/resources/extensions/gsd/tests/milestone-id-reservation.test.ts +1 -1
  250. package/src/resources/extensions/gsd/tests/parsers.test.ts +110 -0
  251. package/src/resources/extensions/gsd/tests/preferences.test.ts +47 -25
  252. package/src/resources/extensions/gsd/tests/prompt-db.test.ts +3 -1
  253. package/src/resources/extensions/gsd/tests/repo-identity-worktree.test.ts +61 -1
  254. package/src/resources/extensions/gsd/tests/routing-history.test.ts +11 -22
  255. package/src/resources/extensions/gsd/tests/rule-registry.test.ts +413 -0
  256. package/src/resources/extensions/gsd/tests/run-manager.test.ts +229 -0
  257. package/src/resources/extensions/gsd/tests/service-tier.test.ts +98 -0
  258. package/src/resources/extensions/gsd/tests/skill-lifecycle.test.ts +2 -2
  259. package/src/resources/extensions/gsd/tests/stalled-tool-recovery.test.ts +102 -0
  260. package/src/resources/extensions/gsd/tests/structured-data-formatter.test.ts +4 -3
  261. package/src/resources/extensions/gsd/tests/tool-call-loop-guard.test.ts +45 -0
  262. package/src/resources/extensions/gsd/tests/tool-naming.test.ts +117 -0
  263. package/src/resources/extensions/gsd/tests/triage-dispatch.test.ts +6 -1
  264. package/src/resources/extensions/gsd/tests/windows-path-normalization.test.ts +99 -0
  265. package/src/resources/extensions/gsd/tests/worktree-db-integration.test.ts +1 -0
  266. package/src/resources/extensions/gsd/tests/worktree-db.test.ts +4 -0
  267. package/src/resources/extensions/gsd/tests/worktree-health-dispatch.test.ts +178 -0
  268. package/src/resources/extensions/gsd/tests/worktree-manager.test.ts +195 -105
  269. package/src/resources/extensions/gsd/tests/worktree-resolver.test.ts +78 -3
  270. package/src/resources/extensions/gsd/tests/worktree-symlink-removal.test.ts +140 -0
  271. package/src/resources/extensions/gsd/tests/worktree-sync-milestones.test.ts +74 -0
  272. package/src/resources/extensions/gsd/types.ts +3 -0
  273. package/src/resources/extensions/gsd/workflow-engine.ts +38 -0
  274. package/src/resources/extensions/gsd/workflow-templates.ts +12 -1
  275. package/src/resources/extensions/gsd/worktree-manager.ts +21 -6
  276. package/src/resources/extensions/gsd/worktree-resolver.ts +30 -9
  277. package/src/resources/extensions/subagent/index.ts +7 -3
  278. package/src/resources/extensions/voice/index.ts +4 -4
  279. package/src/resources/skills/create-workflow/SKILL.md +103 -0
  280. package/src/resources/skills/create-workflow/references/feature-patterns.md +128 -0
  281. package/src/resources/skills/create-workflow/references/verification-policies.md +76 -0
  282. package/src/resources/skills/create-workflow/references/yaml-schema-v1.md +46 -0
  283. package/src/resources/skills/create-workflow/templates/blog-post-pipeline.yaml +60 -0
  284. package/src/resources/skills/create-workflow/templates/code-audit.yaml +60 -0
  285. package/src/resources/skills/create-workflow/templates/release-checklist.yaml +66 -0
  286. package/src/resources/skills/create-workflow/templates/workflow-definition.yaml +32 -0
  287. package/src/resources/skills/create-workflow/workflows/create-from-scratch.md +104 -0
  288. package/src/resources/skills/create-workflow/workflows/create-from-template.md +72 -0
  289. package/dist/web/standalone/.next/static/chunks/4024.279c423e4661ece1.js +0 -9
  290. /package/dist/web/standalone/.next/static/{SwbKZ7JPNFlEmU4f8pKEv → K7GYOOPvQWX6TKYEKhODM}/_buildManifest.js +0 -0
  291. /package/dist/web/standalone/.next/static/{SwbKZ7JPNFlEmU4f8pKEv → K7GYOOPvQWX6TKYEKhODM}/_ssgManifest.js +0 -0
@@ -0,0 +1,352 @@
1
+ /**
2
+ * definition-loader.ts — Parse and validate V1 YAML workflow definitions.
3
+ *
4
+ * Loads definition YAML files from `.gsd/workflow-defs/`, validates the
5
+ * V1 schema shape, and returns typed TypeScript objects. Pure functions
6
+ * with no engine or runtime dependencies — just `yaml` and `node:fs`.
7
+ *
8
+ * YAML uses snake_case (`depends_on`, `context_from`) per project convention (P005).
9
+ * TypeScript uses camelCase (`dependsOn`, `contextFrom`).
10
+ *
11
+ * Observability: All validation errors are collected into a string[] — callers
12
+ * can log, surface in dashboards, or return to agents for self-repair.
13
+ * substituteParams errors include the offending key name for traceability.
14
+ */
15
+ import { parse } from "yaml";
16
+ import { readFileSync, existsSync } from "node:fs";
17
+ import { join } from "node:path";
18
+ // ─── Validation ──────────────────────────────────────────────────────────
19
+ /**
20
+ * Validate a parsed (but untyped) YAML object against the V1 workflow schema.
21
+ *
22
+ * Collects all errors (does not short-circuit) so a single call reveals
23
+ * every problem with the definition.
24
+ *
25
+ * Unknown fields are silently accepted for forward compatibility with
26
+ * S05/S06 features (`context_from`, `verify`, `iterate`).
27
+ */
28
+ export function validateDefinition(parsed) {
29
+ const errors = [];
30
+ if (parsed == null || typeof parsed !== "object") {
31
+ return { valid: false, errors: ["Definition must be a non-null object"] };
32
+ }
33
+ const def = parsed;
34
+ // version: must be 1 (number)
35
+ if (def.version === undefined || def.version === null) {
36
+ errors.push("Missing required field: version");
37
+ }
38
+ else if (def.version !== 1) {
39
+ errors.push(`Unsupported version: ${def.version} (expected 1)`);
40
+ }
41
+ // name: must be a non-empty string
42
+ if (typeof def.name !== "string" || def.name.trim() === "") {
43
+ errors.push("Missing or empty required field: name");
44
+ }
45
+ // steps: must be a non-empty array
46
+ if (!Array.isArray(def.steps)) {
47
+ errors.push("Missing required field: steps (must be an array)");
48
+ }
49
+ else if (def.steps.length === 0) {
50
+ errors.push("steps must contain at least one step");
51
+ }
52
+ else {
53
+ // Track whether all steps have valid IDs — graph-level checks only run when true
54
+ let allStepIdsValid = true;
55
+ for (let i = 0; i < def.steps.length; i++) {
56
+ const step = def.steps[i];
57
+ if (step == null || typeof step !== "object") {
58
+ errors.push(`Step at index ${i} is not an object`);
59
+ allStepIdsValid = false;
60
+ continue;
61
+ }
62
+ // Required step fields
63
+ if (typeof step.id !== "string" || step.id.trim() === "") {
64
+ errors.push(`Step at index ${i} missing required field: id`);
65
+ allStepIdsValid = false;
66
+ }
67
+ if (typeof step.name !== "string" || step.name.trim() === "") {
68
+ errors.push(`Step at index ${i} missing required field: name`);
69
+ }
70
+ if (typeof step.prompt !== "string" || step.prompt.trim() === "") {
71
+ errors.push(`Step at index ${i} missing required field: prompt`);
72
+ }
73
+ // produces: path traversal guard
74
+ if (Array.isArray(step.produces)) {
75
+ for (const p of step.produces) {
76
+ if (typeof p === "string" && p.includes("..")) {
77
+ errors.push(`Step "${step.id}" produces path contains disallowed '..': ${p}`);
78
+ }
79
+ }
80
+ }
81
+ // iterate: optional, but if present must conform to IterateConfig shape
82
+ if (step.iterate !== undefined) {
83
+ const it = step.iterate;
84
+ const sid = typeof step.id === "string" ? step.id : `index ${i}`;
85
+ if (it == null || typeof it !== "object" || Array.isArray(it)) {
86
+ errors.push(`Step "${sid}" iterate must be an object with "source" and "pattern" fields`);
87
+ }
88
+ else {
89
+ const itObj = it;
90
+ if (typeof itObj.source !== "string" || itObj.source.trim() === "") {
91
+ errors.push(`Step "${sid}" iterate.source must be a non-empty string`);
92
+ }
93
+ else if (itObj.source.includes("..")) {
94
+ errors.push(`Step "${sid}" iterate.source contains disallowed '..' path traversal`);
95
+ }
96
+ if (typeof itObj.pattern !== "string" || itObj.pattern.trim() === "") {
97
+ errors.push(`Step "${sid}" iterate.pattern must be a non-empty string`);
98
+ }
99
+ else {
100
+ const pat = itObj.pattern;
101
+ let regexValid = true;
102
+ try {
103
+ new RegExp(pat);
104
+ }
105
+ catch {
106
+ regexValid = false;
107
+ errors.push(`Step "${sid}" iterate.pattern is not a valid regex: ${pat}`);
108
+ }
109
+ if (regexValid && !/\((?!\?)/.test(pat)) {
110
+ errors.push(`Step "${sid}" iterate.pattern must contain at least one capture group`);
111
+ }
112
+ }
113
+ }
114
+ }
115
+ // verify: optional, but if present must conform to VerifyPolicy shape
116
+ if (step.verify !== undefined) {
117
+ const v = step.verify;
118
+ const sid = typeof step.id === "string" ? step.id : `index ${i}`;
119
+ if (v == null || typeof v !== "object" || Array.isArray(v)) {
120
+ errors.push(`Step "${sid}" verify must be an object with a "policy" field`);
121
+ }
122
+ else {
123
+ const vObj = v;
124
+ const VALID_POLICIES = ["content-heuristic", "shell-command", "prompt-verify", "human-review"];
125
+ if (typeof vObj.policy !== "string" || !VALID_POLICIES.includes(vObj.policy)) {
126
+ errors.push(`Step "${sid}" verify.policy must be one of: ${VALID_POLICIES.join(", ")}`);
127
+ }
128
+ else {
129
+ // Policy-specific required field checks
130
+ if (vObj.policy === "shell-command") {
131
+ if (typeof vObj.command !== "string" || vObj.command.trim() === "") {
132
+ errors.push(`Step "${sid}" verify policy "shell-command" requires a non-empty "command" field`);
133
+ }
134
+ }
135
+ if (vObj.policy === "prompt-verify") {
136
+ if (typeof vObj.prompt !== "string" || vObj.prompt.trim() === "") {
137
+ errors.push(`Step "${sid}" verify policy "prompt-verify" requires a non-empty "prompt" field`);
138
+ }
139
+ }
140
+ }
141
+ }
142
+ }
143
+ }
144
+ // ─── Graph-level validations (only when all step IDs are valid) ────
145
+ if (allStepIdsValid) {
146
+ const steps = def.steps;
147
+ // 1. Duplicate step ID check
148
+ const idCounts = new Map();
149
+ for (const step of steps) {
150
+ const id = step.id;
151
+ idCounts.set(id, (idCounts.get(id) ?? 0) + 1);
152
+ }
153
+ for (const [id, count] of idCounts) {
154
+ if (count > 1) {
155
+ errors.push(`Duplicate step id: ${id}`);
156
+ }
157
+ }
158
+ // Build valid ID set for remaining checks
159
+ const validIds = new Set(steps.map((s) => s.id));
160
+ // 2. Dangling dependency check + 3. Self-referencing dependency check
161
+ for (const step of steps) {
162
+ const sid = step.id;
163
+ const deps = Array.isArray(step.requires)
164
+ ? step.requires
165
+ : Array.isArray(step.depends_on)
166
+ ? step.depends_on
167
+ : [];
168
+ for (const depId of deps) {
169
+ if (depId === sid) {
170
+ errors.push(`Step '${sid}' depends on itself`);
171
+ }
172
+ else if (!validIds.has(depId)) {
173
+ errors.push(`Step '${sid}' requires unknown step '${depId}'`);
174
+ }
175
+ }
176
+ }
177
+ // 4. Cycle detection (DFS) — only when no duplicate IDs
178
+ if (![...idCounts.values()].some((c) => c > 1)) {
179
+ // Build adjacency list: step → its dependencies
180
+ const adj = new Map();
181
+ for (const step of steps) {
182
+ const sid = step.id;
183
+ const deps = Array.isArray(step.requires)
184
+ ? step.requires
185
+ : Array.isArray(step.depends_on)
186
+ ? step.depends_on
187
+ : [];
188
+ adj.set(sid, deps.filter((d) => validIds.has(d) && d !== sid));
189
+ }
190
+ const WHITE = 0, GRAY = 1, BLACK = 2;
191
+ const color = new Map();
192
+ for (const id of validIds)
193
+ color.set(id, WHITE);
194
+ const parent = new Map();
195
+ function dfs(node) {
196
+ color.set(node, GRAY);
197
+ for (const dep of adj.get(node) ?? []) {
198
+ if (color.get(dep) === GRAY) {
199
+ // Back edge found — reconstruct cycle path
200
+ const cycle = [dep, node];
201
+ let cur = node;
202
+ while (parent.has(cur) && parent.get(cur) !== null && parent.get(cur) !== dep) {
203
+ cur = parent.get(cur);
204
+ cycle.push(cur);
205
+ }
206
+ cycle.push(dep);
207
+ cycle.reverse();
208
+ return cycle;
209
+ }
210
+ if (color.get(dep) === WHITE) {
211
+ parent.set(dep, node);
212
+ const result = dfs(dep);
213
+ if (result)
214
+ return result;
215
+ }
216
+ }
217
+ color.set(node, BLACK);
218
+ return null;
219
+ }
220
+ for (const id of validIds) {
221
+ if (color.get(id) === WHITE) {
222
+ parent.set(id, null);
223
+ const cycle = dfs(id);
224
+ if (cycle) {
225
+ errors.push(`Cycle detected: ${cycle.join(" → ")}`);
226
+ break; // One cycle error is enough
227
+ }
228
+ }
229
+ }
230
+ }
231
+ }
232
+ }
233
+ return { valid: errors.length === 0, errors };
234
+ }
235
+ // ─── Loading ─────────────────────────────────────────────────────────────
236
+ /**
237
+ * Load and validate a YAML workflow definition from the filesystem.
238
+ *
239
+ * Reads `<defsDir>/<name>.yaml`, parses YAML, validates the V1 schema,
240
+ * and converts snake_case YAML keys to camelCase TypeScript types.
241
+ *
242
+ * @param defsDir — directory containing definition YAML files
243
+ * @param name — definition filename without extension
244
+ * @returns Parsed and validated WorkflowDefinition
245
+ * @throws Error if file is missing, YAML is malformed, or schema is invalid
246
+ */
247
+ export function loadDefinition(defsDir, name) {
248
+ const filePath = join(defsDir, `${name}.yaml`);
249
+ if (!existsSync(filePath)) {
250
+ throw new Error(`Definition file not found: ${filePath}`);
251
+ }
252
+ const raw = readFileSync(filePath, "utf-8");
253
+ let parsed;
254
+ try {
255
+ parsed = parse(raw);
256
+ }
257
+ catch (e) {
258
+ const msg = e instanceof Error ? e.message : String(e);
259
+ throw new Error(`Failed to parse YAML in ${filePath}: ${msg}`);
260
+ }
261
+ const { valid, errors } = validateDefinition(parsed);
262
+ if (!valid) {
263
+ throw new Error(`Invalid workflow definition in ${filePath}:\n - ${errors.join("\n - ")}`);
264
+ }
265
+ // Convert snake_case YAML → camelCase TypeScript
266
+ const yamlDef = parsed;
267
+ const yamlSteps = yamlDef.steps;
268
+ return {
269
+ version: yamlDef.version,
270
+ name: yamlDef.name,
271
+ description: typeof yamlDef.description === "string" ? yamlDef.description : undefined,
272
+ params: yamlDef.params != null && typeof yamlDef.params === "object"
273
+ ? Object.fromEntries(Object.entries(yamlDef.params).map(([k, v]) => [k, String(v)]))
274
+ : undefined,
275
+ steps: yamlSteps.map((s) => ({
276
+ id: s.id,
277
+ name: s.name,
278
+ prompt: s.prompt,
279
+ requires: Array.isArray(s.requires)
280
+ ? s.requires
281
+ : Array.isArray(s.depends_on)
282
+ ? s.depends_on
283
+ : [],
284
+ produces: Array.isArray(s.produces) ? s.produces : [],
285
+ contextFrom: Array.isArray(s.context_from) ? s.context_from : undefined,
286
+ verify: s.verify,
287
+ iterate: (s.iterate != null && typeof s.iterate === "object")
288
+ ? s.iterate
289
+ : undefined,
290
+ })),
291
+ };
292
+ }
293
+ // ─── Parameter Substitution ──────────────────────────────────────────────
294
+ /** Regex matching `{{key}}` placeholders — captures the key name. */
295
+ const PARAM_PATTERN = /\{\{(\w+)\}\}/g;
296
+ /**
297
+ * Replace `{{key}}` placeholders in a single prompt string.
298
+ *
299
+ * Exported for use by the engine on iteration-instance prompts that live
300
+ * in GRAPH.yaml (outside the definition's step list).
301
+ *
302
+ * @throws Error if any merged param value contains `..` (path-traversal guard)
303
+ */
304
+ export function substitutePromptString(prompt, merged) {
305
+ return prompt.replace(PARAM_PATTERN, (match, key) => {
306
+ const value = merged[key];
307
+ return value !== undefined ? value : match;
308
+ });
309
+ }
310
+ /**
311
+ * Replace `{{key}}` placeholders in all step prompts with param values.
312
+ *
313
+ * Merge order: `definition.params` (defaults) ← `overrides` (CLI wins).
314
+ * Returns a **new** WorkflowDefinition — the input is never mutated.
315
+ *
316
+ * @throws Error if any param value contains `..` (path-traversal guard)
317
+ * @throws Error if any `{{key}}` remains unresolved after substitution
318
+ */
319
+ export function substituteParams(definition, overrides) {
320
+ const merged = {
321
+ ...(definition.params ?? {}),
322
+ ...(overrides ?? {}),
323
+ };
324
+ // Path-traversal guard: reject any value containing ".."
325
+ for (const [key, value] of Object.entries(merged)) {
326
+ if (value.includes("..")) {
327
+ throw new Error(`Parameter "${key}" contains disallowed '..' (path traversal): ${value}`);
328
+ }
329
+ }
330
+ // Substitute in each step prompt
331
+ const substitutedSteps = definition.steps.map((step) => ({
332
+ ...step,
333
+ prompt: substitutePromptString(step.prompt, merged),
334
+ }));
335
+ // Check for unresolved placeholders
336
+ const unresolved = new Set();
337
+ for (const step of substitutedSteps) {
338
+ let m;
339
+ const re = new RegExp(PARAM_PATTERN.source, "g");
340
+ while ((m = re.exec(step.prompt)) !== null) {
341
+ unresolved.add(m[1]);
342
+ }
343
+ }
344
+ if (unresolved.size > 0) {
345
+ const keys = [...unresolved].sort().join(", ");
346
+ throw new Error(`Unresolved parameter(s) in step prompts: ${keys}`);
347
+ }
348
+ return {
349
+ ...definition,
350
+ steps: substitutedSteps,
351
+ };
352
+ }
@@ -11,7 +11,7 @@ import { homedir } from "node:os";
11
11
  import { gsdRoot } from "./paths.js";
12
12
  const gsdHome = process.env.GSD_HOME || join(homedir(), ".gsd");
13
13
  // ─── Project File Markers ───────────────────────────────────────────────────────
14
- const PROJECT_FILES = [
14
+ export const PROJECT_FILES = [
15
15
  "package.json",
16
16
  "Cargo.toml",
17
17
  "go.mod",
@@ -0,0 +1,24 @@
1
+ /**
2
+ * dev-execution-policy.ts — DevExecutionPolicy implementation.
3
+ *
4
+ * Stub policy for the dev engine. All methods return safe defaults.
5
+ * Real verification/closeout continues running through phases.ts via LoopDeps.
6
+ * Wiring this policy into the loop is S04's responsibility.
7
+ */
8
+ export class DevExecutionPolicy {
9
+ async prepareWorkspace(_basePath, _milestoneId) {
10
+ // no-op — workspace preparation handled by existing GSD logic
11
+ }
12
+ async selectModel(_unitType, _unitId, _context) {
13
+ return null; // use default model selection
14
+ }
15
+ async verify(_unitType, _unitId, _context) {
16
+ return "continue";
17
+ }
18
+ async recover(_unitType, _unitId, _context) {
19
+ return { outcome: "retry" };
20
+ }
21
+ async closeout(_unitType, _unitId, _context) {
22
+ return { committed: false, artifacts: [] };
23
+ }
24
+ }
@@ -0,0 +1,82 @@
1
+ /**
2
+ * dev-workflow-engine.ts — DevWorkflowEngine implementation.
3
+ *
4
+ * Implements WorkflowEngine by delegating to existing GSD state derivation
5
+ * and dispatch logic. This is the "dev" engine — it wraps the current GSD
6
+ * auto-mode behavior behind the engine-polymorphic interface.
7
+ */
8
+ import { deriveState } from "./state.js";
9
+ import { resolveDispatch } from "./auto-dispatch.js";
10
+ import { loadEffectiveGSDPreferences } from "./preferences.js";
11
+ // ─── Bridge: DispatchAction → EngineDispatchAction ────────────────────────
12
+ /**
13
+ * Map a GSD-specific DispatchAction (which carries `matchedRule`, `unitType`,
14
+ * etc.) to the engine-generic EngineDispatchAction discriminated union.
15
+ *
16
+ * Exported for unit testing.
17
+ */
18
+ export function bridgeDispatchAction(da) {
19
+ switch (da.action) {
20
+ case "dispatch":
21
+ return {
22
+ action: "dispatch",
23
+ step: {
24
+ unitType: da.unitType,
25
+ unitId: da.unitId,
26
+ prompt: da.prompt,
27
+ },
28
+ };
29
+ case "stop":
30
+ return {
31
+ action: "stop",
32
+ reason: da.reason,
33
+ level: da.level,
34
+ };
35
+ case "skip":
36
+ return { action: "skip" };
37
+ }
38
+ }
39
+ // ─── DevWorkflowEngine ───────────────────────────────────────────────────
40
+ export class DevWorkflowEngine {
41
+ engineId = "dev";
42
+ async deriveState(basePath) {
43
+ const gsd = await deriveState(basePath);
44
+ return {
45
+ phase: gsd.phase,
46
+ currentMilestoneId: gsd.activeMilestone?.id ?? null,
47
+ activeSliceId: gsd.activeSlice?.id ?? null,
48
+ activeTaskId: gsd.activeTask?.id ?? null,
49
+ isComplete: gsd.phase === "complete",
50
+ raw: gsd,
51
+ };
52
+ }
53
+ async resolveDispatch(state, context) {
54
+ const gsd = state.raw;
55
+ const mid = gsd.activeMilestone?.id ?? "";
56
+ const midTitle = gsd.activeMilestone?.title ?? "";
57
+ const loaded = loadEffectiveGSDPreferences();
58
+ const prefs = loaded?.preferences ?? undefined;
59
+ const dispatchCtx = {
60
+ basePath: context.basePath,
61
+ mid,
62
+ midTitle,
63
+ state: gsd,
64
+ prefs,
65
+ };
66
+ const result = await resolveDispatch(dispatchCtx);
67
+ return bridgeDispatchAction(result);
68
+ }
69
+ async reconcile(state, _completedStep) {
70
+ return {
71
+ outcome: state.isComplete ? "milestone-complete" : "continue",
72
+ };
73
+ }
74
+ getDisplayMetadata(state) {
75
+ return {
76
+ engineLabel: "GSD Dev",
77
+ currentPhase: state.phase,
78
+ progressSummary: `${state.currentMilestoneId ?? "no milestone"} / ${state.activeSliceId ?? "—"} / ${state.activeTaskId ?? "—"}`,
79
+ stepCount: null,
80
+ };
81
+ }
82
+ }
@@ -745,6 +745,7 @@ export async function runGSDDoctor(basePath, options) {
745
745
  }
746
746
  catch { /* non-fatal */ }
747
747
  let allTasksDone = plan.tasks.length > 0;
748
+ let taskUncheckedByDoctor = false;
748
749
  for (const task of plan.tasks) {
749
750
  const taskUnitId = `${unitId}/${task.id}`;
750
751
  const summaryPath = resolveTaskFile(basePath, milestoneId, slice.id, task.id, "SUMMARY");
@@ -762,6 +763,7 @@ export async function runGSDDoctor(basePath, options) {
762
763
  dryRunCanFix("task_done_missing_summary", `uncheck ${task.id} in plan for ${taskUnitId}`);
763
764
  if (shouldFix("task_done_missing_summary")) {
764
765
  await markTaskUndoneInPlan(basePath, milestoneId, slice.id, task.id, fixesApplied);
766
+ taskUncheckedByDoctor = true;
765
767
  }
766
768
  }
767
769
  if (!task.done && hasSummary) {
@@ -822,6 +824,14 @@ export async function runGSDDoctor(basePath, options) {
822
824
  }
823
825
  allTasksDone = allTasksDone && task.done;
824
826
  }
827
+ // ── #1850: cascade slice uncheck when task_done_missing_summary fires ──
828
+ // When doctor unchecks tasks inside a done slice, the slice must also be
829
+ // unchecked so the state machine re-enters the executing phase. Without
830
+ // this, state.ts skips done slices and the unchecked tasks never run,
831
+ // causing doctor to fire again on every start (infinite loop).
832
+ if (taskUncheckedByDoctor && slice.done) {
833
+ await markSliceUndoneInRoadmap(basePath, milestoneId, slice.id, fixesApplied);
834
+ }
825
835
  // Blocker-without-replan detection
826
836
  const replanPath = resolveSliceFile(basePath, milestoneId, slice.id, "REPLAN");
827
837
  if (!replanPath) {
@@ -898,7 +908,7 @@ export async function runGSDDoctor(basePath, options) {
898
908
  fixable: true,
899
909
  });
900
910
  dryRunCanFix("all_tasks_done_roadmap_not_checked", `mark ${slice.id} done in roadmap`);
901
- if (shouldFix("all_tasks_done_roadmap_not_checked") && (hasSliceSummary || issues.some(issue => issue.code === "all_tasks_done_missing_slice_summary" && issue.unitId === unitId))) {
911
+ if (shouldFix("all_tasks_done_roadmap_not_checked") && (hasSliceSummary || existsSync(join(slicePath, `${slice.id}-SUMMARY.md`)))) {
902
912
  await markSliceDoneInRoadmap(basePath, milestoneId, slice.id, fixesApplied);
903
913
  }
904
914
  }
@@ -0,0 +1,40 @@
1
+ /**
2
+ * engine-resolver.ts — Route sessions to engine/policy pairs.
3
+ *
4
+ * Routes `null` and `"dev"` engine IDs to the DevWorkflowEngine/DevExecutionPolicy
5
+ * pair. Any other non-null engine ID is treated as a custom workflow engine that
6
+ * reads its state from an `activeRunDir`. Respects `GSD_ENGINE_BYPASS=1` kill
7
+ * switch to skip the engine layer entirely.
8
+ */
9
+ import { DevWorkflowEngine } from "./dev-workflow-engine.js";
10
+ import { DevExecutionPolicy } from "./dev-execution-policy.js";
11
+ import { CustomWorkflowEngine } from "./custom-workflow-engine.js";
12
+ import { CustomExecutionPolicy } from "./custom-execution-policy.js";
13
+ /**
14
+ * Resolve an engine/policy pair for the given session.
15
+ *
16
+ * - `null` or `"dev"` → DevWorkflowEngine + DevExecutionPolicy
17
+ * - any other non-null ID → CustomWorkflowEngine(activeRunDir) + CustomExecutionPolicy()
18
+ * (requires activeRunDir to be a non-empty string)
19
+ *
20
+ * Note: `GSD_ENGINE_BYPASS=1` is checked in autoLoop before calling this function.
21
+ */
22
+ export function resolveEngine(session) {
23
+ const { activeEngineId, activeRunDir } = session;
24
+ if (activeEngineId === null || activeEngineId === "dev") {
25
+ return {
26
+ engine: new DevWorkflowEngine(),
27
+ policy: new DevExecutionPolicy(),
28
+ };
29
+ }
30
+ // Any non-null, non-"dev" engine ID is a custom workflow engine.
31
+ // activeRunDir is required — the engine reads GRAPH.yaml from it.
32
+ if (!activeRunDir || typeof activeRunDir !== "string") {
33
+ throw new Error(`Custom engine "${activeEngineId}" requires activeRunDir to be a non-empty string, ` +
34
+ `got: ${JSON.stringify(activeRunDir)}`);
35
+ }
36
+ return {
37
+ engine: new CustomWorkflowEngine(activeRunDir),
38
+ policy: new CustomExecutionPolicy(activeRunDir),
39
+ };
40
+ }
@@ -0,0 +1,8 @@
1
+ /**
2
+ * engine-types.ts — Engine-polymorphic type contracts.
3
+ *
4
+ * LEAF NODE: This file must have ZERO imports from any GSD module.
5
+ * Only `node:` imports are permitted. All engine/policy interfaces
6
+ * depend on these types; nothing here depends on GSD internals.
7
+ */
8
+ export {};
@@ -0,0 +1,8 @@
1
+ /**
2
+ * execution-policy.ts — ExecutionPolicy interface.
3
+ *
4
+ * Defines the policy layer that governs model selection, verification,
5
+ * recovery, and closeout for each execution step. Imports only from
6
+ * the leaf-node engine-types.
7
+ */
8
+ export {};
@@ -4,8 +4,18 @@ export function registerExitCommand(pi, deps = {}) {
4
4
  description: "Exit GSD gracefully",
5
5
  handler: async (_args, ctx) => {
6
6
  // Stop auto-mode first so locks and activity state are cleaned up before shutdown.
7
- const stopAuto = deps.stopAuto ?? (await importExtensionModule(import.meta.url, "./auto.js")).stopAuto;
8
- await stopAuto(ctx, pi, "Graceful exit");
7
+ // Wrapped in try/catch: if gsd-pi was updated on disk mid-session, the dynamic
8
+ // import may resolve a new auto-worktree.js whose static imports reference
9
+ // exports absent from the process-cached native-git-bridge.js (ESM cache is
10
+ // immutable). The user's work is already saved — this is cleanup only.
11
+ try {
12
+ const stopAuto = deps.stopAuto ?? (await importExtensionModule(import.meta.url, "./auto.js")).stopAuto;
13
+ await stopAuto(ctx, pi, "Graceful exit");
14
+ }
15
+ catch (e) {
16
+ const msg = e instanceof Error ? e.message : String(e);
17
+ ctx.ui?.notify?.(`Auto-mode cleanup skipped (module version mismatch): ${msg}`, "warning");
18
+ }
9
19
  ctx.shutdown();
10
20
  },
11
21
  });
@@ -2,7 +2,7 @@
2
2
  // Generate shareable reports of milestone work in JSON or markdown format.
3
3
  import { writeFileSync, mkdirSync } from "node:fs";
4
4
  import { join, basename } from "node:path";
5
- import { exec } from "node:child_process";
5
+ import { execFile } from "node:child_process";
6
6
  import { getLedger, getProjectTotals, aggregateByPhase, aggregateBySlice, aggregateByModel, formatCost, formatTokenCount, loadLedgerFromDisk, } from "./metrics.js";
7
7
  import { gsdRoot } from "./paths.js";
8
8
  import { formatDuration, fileLink } from "../shared/format-utils.js";
@@ -13,18 +13,14 @@ import { getErrorMessage } from "./error-utils.js";
13
13
  * Non-blocking, non-fatal — failures are silently ignored.
14
14
  */
15
15
  export function openInBrowser(filePath) {
16
- const cmd = process.platform === "darwin" ? "open" :
17
- process.platform === "win32" ? "start" :
18
- "xdg-open";
19
- // On Windows, `start` needs an empty title argument when the path has spaces
20
- const args = process.platform === "win32"
21
- ? `"" "${filePath}"`
22
- : `"${filePath}"`;
23
- exec(`${cmd} ${args}`, (err) => {
24
- // Non-fatal — if the browser can't be opened, the file path is still shown
25
- if (err)
26
- void err;
27
- });
16
+ if (process.platform === "win32") {
17
+ // PowerShell's Start-Process handles paths with '&' and spaces safely.
18
+ execFile("powershell", ["-c", `Start-Process '${filePath.replace(/'/g, "''")}'`], () => { });
19
+ }
20
+ else {
21
+ const cmd = process.platform === "darwin" ? "open" : "xdg-open";
22
+ execFile(cmd, [filePath], () => { });
23
+ }
28
24
  }
29
25
  /**
30
26
  * Write an export file directly, without requiring an ExtensionCommandContext.
@@ -8,8 +8,8 @@
8
8
  "provides": {
9
9
  "tools": [
10
10
  "bash", "write", "read", "edit",
11
- "gsd_save_decision", "gsd_save_summary",
12
- "gsd_update_requirement", "gsd_generate_milestone_id"
11
+ "gsd_decision_save", "gsd_summary_save",
12
+ "gsd_requirement_update", "gsd_milestone_generate_id"
13
13
  ],
14
14
  "commands": ["gsd", "kill", "worktree", "exit"],
15
15
  "hooks": ["session_start"],