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,57 @@
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
+
10
+ import type { WorkflowEngine } from "./workflow-engine.js";
11
+ import type { ExecutionPolicy } from "./execution-policy.js";
12
+ import { DevWorkflowEngine } from "./dev-workflow-engine.js";
13
+ import { DevExecutionPolicy } from "./dev-execution-policy.js";
14
+ import { CustomWorkflowEngine } from "./custom-workflow-engine.js";
15
+ import { CustomExecutionPolicy } from "./custom-execution-policy.js";
16
+
17
+ /** A resolved engine + policy pair ready for the auto-loop. */
18
+ export interface ResolvedEngine {
19
+ engine: WorkflowEngine;
20
+ policy: ExecutionPolicy;
21
+ }
22
+
23
+ /**
24
+ * Resolve an engine/policy pair for the given session.
25
+ *
26
+ * - `null` or `"dev"` → DevWorkflowEngine + DevExecutionPolicy
27
+ * - any other non-null ID → CustomWorkflowEngine(activeRunDir) + CustomExecutionPolicy()
28
+ * (requires activeRunDir to be a non-empty string)
29
+ *
30
+ * Note: `GSD_ENGINE_BYPASS=1` is checked in autoLoop before calling this function.
31
+ */
32
+ export function resolveEngine(
33
+ session: { activeEngineId: string | null; activeRunDir?: string | null },
34
+ ): ResolvedEngine {
35
+ const { activeEngineId, activeRunDir } = session;
36
+
37
+ if (activeEngineId === null || activeEngineId === "dev") {
38
+ return {
39
+ engine: new DevWorkflowEngine(),
40
+ policy: new DevExecutionPolicy(),
41
+ };
42
+ }
43
+
44
+ // Any non-null, non-"dev" engine ID is a custom workflow engine.
45
+ // activeRunDir is required — the engine reads GRAPH.yaml from it.
46
+ if (!activeRunDir || typeof activeRunDir !== "string") {
47
+ throw new Error(
48
+ `Custom engine "${activeEngineId}" requires activeRunDir to be a non-empty string, ` +
49
+ `got: ${JSON.stringify(activeRunDir)}`,
50
+ );
51
+ }
52
+
53
+ return {
54
+ engine: new CustomWorkflowEngine(activeRunDir),
55
+ policy: new CustomExecutionPolicy(activeRunDir),
56
+ };
57
+ }
@@ -0,0 +1,71 @@
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
+
9
+ /** Snapshot of engine state at a point in time. */
10
+ export interface EngineState {
11
+ phase: string;
12
+ currentMilestoneId: string | null;
13
+ activeSliceId: string | null;
14
+ activeTaskId: string | null;
15
+ isComplete: boolean;
16
+ /** Opaque engine-specific state — never narrowed to a GSD-specific type. */
17
+ raw: unknown;
18
+ }
19
+
20
+ /** A unit of work the engine wants the agent to execute. */
21
+ export interface StepContract {
22
+ unitType: string;
23
+ unitId: string;
24
+ prompt: string;
25
+ }
26
+
27
+ /** UI-facing metadata for progress display. */
28
+ export interface DisplayMetadata {
29
+ engineLabel: string;
30
+ currentPhase: string;
31
+ progressSummary: string;
32
+ stepCount: { completed: number; total: number } | null;
33
+ }
34
+
35
+ /**
36
+ * Discriminated union: what the engine tells the loop to do next.
37
+ *
38
+ * - `dispatch` — execute a step
39
+ * - `stop` — halt the loop with a reason and severity
40
+ * - `skip` — nothing to do right now, advance without executing
41
+ */
42
+ export type EngineDispatchAction =
43
+ | { action: "dispatch"; step: StepContract }
44
+ | { action: "stop"; reason: string; level: "info" | "warning" | "error" }
45
+ | { action: "skip" };
46
+
47
+ /** Outcome of reconciling state after a step completes. */
48
+ export interface ReconcileResult {
49
+ outcome: "continue" | "milestone-complete" | "pause" | "stop";
50
+ reason?: string;
51
+ }
52
+
53
+ /** Recovery strategy when a step fails. */
54
+ export interface RecoveryAction {
55
+ outcome: "retry" | "skip" | "stop" | "pause";
56
+ reason?: string;
57
+ }
58
+
59
+ /** Result of closing out a completed unit. */
60
+ export interface CloseoutResult {
61
+ committed: boolean;
62
+ artifacts: string[];
63
+ }
64
+
65
+ /** Record of a completed execution step. */
66
+ export interface CompletedStep {
67
+ unitType: string;
68
+ unitId: string;
69
+ startedAt: number;
70
+ finishedAt: number;
71
+ }
@@ -0,0 +1,43 @@
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
+
9
+ import type { RecoveryAction, CloseoutResult } from "./engine-types.js";
10
+
11
+ /** Policy governing how each step is executed, verified, and closed out. */
12
+ export interface ExecutionPolicy {
13
+ /** Prepare the workspace before a milestone begins (e.g. worktree setup). */
14
+ prepareWorkspace(basePath: string, milestoneId: string): Promise<void>;
15
+
16
+ /** Select the model tier for a given unit. Returns null to use defaults. */
17
+ selectModel(
18
+ unitType: string,
19
+ unitId: string,
20
+ context: { basePath: string },
21
+ ): Promise<{ tier: string; modelDowngraded: boolean } | null>;
22
+
23
+ /** Verify unit output. Returns disposition for the loop. */
24
+ verify(
25
+ unitType: string,
26
+ unitId: string,
27
+ context: { basePath: string },
28
+ ): Promise<"continue" | "retry" | "pause">;
29
+
30
+ /** Determine recovery action when a unit fails. */
31
+ recover(
32
+ unitType: string,
33
+ unitId: string,
34
+ context: { basePath: string },
35
+ ): Promise<RecoveryAction>;
36
+
37
+ /** Close out a completed unit (commit, snapshot, artifact capture). */
38
+ closeout(
39
+ unitType: string,
40
+ unitId: string,
41
+ context: { basePath: string; startedAt: number },
42
+ ): Promise<CloseoutResult>;
43
+ }
@@ -10,8 +10,20 @@ export function registerExitCommand(
10
10
  description: "Exit GSD gracefully",
11
11
  handler: async (_args: string, ctx: ExtensionCommandContext) => {
12
12
  // Stop auto-mode first so locks and activity state are cleaned up before shutdown.
13
- const stopAuto = deps.stopAuto ?? (await importExtensionModule<typeof import("./auto.js")>(import.meta.url, "./auto.js")).stopAuto;
14
- await stopAuto(ctx, pi, "Graceful exit");
13
+ // Wrapped in try/catch: if gsd-pi was updated on disk mid-session, the dynamic
14
+ // import may resolve a new auto-worktree.js whose static imports reference
15
+ // exports absent from the process-cached native-git-bridge.js (ESM cache is
16
+ // immutable). The user's work is already saved — this is cleanup only.
17
+ try {
18
+ const stopAuto = deps.stopAuto ?? (await importExtensionModule<typeof import("./auto.js")>(import.meta.url, "./auto.js")).stopAuto;
19
+ await stopAuto(ctx, pi, "Graceful exit");
20
+ } catch (e) {
21
+ const msg = e instanceof Error ? e.message : String(e);
22
+ ctx.ui?.notify?.(
23
+ `Auto-mode cleanup skipped (module version mismatch): ${msg}`,
24
+ "warning",
25
+ );
26
+ }
15
27
  ctx.shutdown();
16
28
  },
17
29
  });
@@ -4,7 +4,7 @@
4
4
  import type { ExtensionCommandContext } from "@gsd/pi-coding-agent";
5
5
  import { writeFileSync, mkdirSync } from "node:fs";
6
6
  import { join, basename } from "node:path";
7
- import { exec } from "node:child_process";
7
+ import { exec, execFile } from "node:child_process";
8
8
  import {
9
9
  getLedger, getProjectTotals, aggregateByPhase, aggregateBySlice,
10
10
  aggregateByModel, formatCost, formatTokenCount, loadLedgerFromDisk,
@@ -20,20 +20,13 @@ import { getErrorMessage } from "./error-utils.js";
20
20
  * Non-blocking, non-fatal — failures are silently ignored.
21
21
  */
22
22
  export function openInBrowser(filePath: string): void {
23
- const cmd =
24
- process.platform === "darwin" ? "open" :
25
- process.platform === "win32" ? "start" :
26
- "xdg-open";
27
-
28
- // On Windows, `start` needs an empty title argument when the path has spaces
29
- const args = process.platform === "win32"
30
- ? `"" "${filePath}"`
31
- : `"${filePath}"`;
32
-
33
- exec(`${cmd} ${args}`, (err) => {
34
- // Non-fatal — if the browser can't be opened, the file path is still shown
35
- if (err) void err;
36
- });
23
+ if (process.platform === "win32") {
24
+ // PowerShell's Start-Process handles paths with '&' and spaces safely.
25
+ execFile("powershell", ["-c", `Start-Process '${filePath.replace(/'/g, "''")}'`], () => {});
26
+ } else {
27
+ const cmd = process.platform === "darwin" ? "open" : "xdg-open";
28
+ execFile(cmd, [filePath], () => {});
29
+ }
37
30
  }
38
31
 
39
32
  /**
@@ -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"],
@@ -374,20 +374,37 @@ function _parsePlanImpl(content: string): SlicePlan {
374
374
 
375
375
  for (const line of taskLines) {
376
376
  const cbMatch = line.match(/^-\s+\[([ xX])\]\s+\*\*([\w.]+):\s+(.+?)\*\*\s*(.*)/);
377
- if (cbMatch) {
377
+ // Heading-style: ### T01 -- Title, ### T01: Title, ### T01 — Title
378
+ const hdMatch = !cbMatch ? line.match(/^#{2,4}\s+([\w.]+)\s*(?:--|—|:)\s*(.+)/) : null;
379
+ if (cbMatch || hdMatch) {
378
380
  if (currentTask) tasks.push(currentTask);
379
381
 
380
- const rest = cbMatch[4] || '';
381
- const estMatch = rest.match(/`est:([^`]+)`/);
382
- const estimate = estMatch ? estMatch[1] : '';
383
-
384
- currentTask = {
385
- id: cbMatch[2],
386
- title: cbMatch[3],
387
- description: '',
388
- done: cbMatch[1].toLowerCase() === 'x',
389
- estimate,
390
- };
382
+ if (cbMatch) {
383
+ const rest = cbMatch[4] || '';
384
+ const estMatch = rest.match(/`est:([^`]+)`/);
385
+ const estimate = estMatch ? estMatch[1] : '';
386
+
387
+ currentTask = {
388
+ id: cbMatch[2],
389
+ title: cbMatch[3],
390
+ description: '',
391
+ done: cbMatch[1].toLowerCase() === 'x',
392
+ estimate,
393
+ };
394
+ } else {
395
+ const rest = hdMatch![2] || '';
396
+ const titleEstMatch = rest.match(/^(.+?)\s*`est:([^`]+)`\s*$/);
397
+ const title = titleEstMatch ? titleEstMatch[1].trim() : rest.trim();
398
+ const estimate = titleEstMatch ? titleEstMatch[2] : '';
399
+
400
+ currentTask = {
401
+ id: hdMatch![1],
402
+ title,
403
+ description: '',
404
+ done: false,
405
+ estimate,
406
+ };
407
+ }
391
408
  } else if (currentTask && line.match(/^\s*-\s+Files:\s*(.*)/)) {
392
409
  const filesMatch = line.match(/^\s*-\s+Files:\s*(.*)/);
393
410
  if (filesMatch) {
@@ -12,6 +12,7 @@ import type { ExtensionAPI, ExtensionCommandContext } from "@gsd/pi-coding-agent
12
12
  import { existsSync, mkdirSync, readFileSync, readdirSync, statSync, writeFileSync } from "node:fs";
13
13
  import { join, dirname, relative } from "node:path";
14
14
  import { fileURLToPath } from "node:url";
15
+ import { homedir } from "node:os";
15
16
 
16
17
  import { extractTrace, type ExecutionTrace } from "./session-forensics.js";
17
18
  import { nativeParseJsonlTail } from "./native-parser-bridge.js";
@@ -102,9 +103,14 @@ export async function handleForensics(
102
103
  const report = await buildForensicReport(basePath);
103
104
  const savedPath = saveForensicReport(basePath, report, problemDescription);
104
105
 
105
- // Derive GSD source dir for prompt
106
- const __extensionDir = dirname(fileURLToPath(import.meta.url));
107
- const gsdSourceDir = __extensionDir;
106
+ // Derive GSD source dir for prompt — fall back to ~/.gsd/agent/extensions/gsd/
107
+ // when import.meta.url resolves to the npm-global install path (Windows).
108
+ let gsdSourceDir = dirname(fileURLToPath(import.meta.url));
109
+ if (!existsSync(join(gsdSourceDir, "prompts"))) {
110
+ const gsdHome = process.env.GSD_HOME || join(homedir(), ".gsd");
111
+ const fallback = join(gsdHome, "agent", "extensions", "gsd");
112
+ if (existsSync(join(fallback, "prompts"))) gsdSourceDir = fallback;
113
+ }
108
114
 
109
115
  const forensicData = formatReportForPrompt(report);
110
116
  const content = loadPrompt("forensics", {
@@ -683,10 +683,11 @@ export function createDraftPR(
683
683
  body: string,
684
684
  ): string | null {
685
685
  try {
686
- const result = execSync(
687
- `gh pr create --draft --title ${JSON.stringify(title)} --body ${JSON.stringify(body)}`,
688
- { cwd: basePath, encoding: "utf8", timeout: 30000, env: GIT_NO_PROMPT_ENV },
689
- );
686
+ const result = execFileSync("gh", [
687
+ "pr", "create", "--draft",
688
+ "--title", title,
689
+ "--body", body,
690
+ ], { cwd: basePath, encoding: "utf8", timeout: 30000, env: GIT_NO_PROMPT_ENV });
690
691
  return result.trim();
691
692
  } catch {
692
693
  return null;
@@ -0,0 +1,312 @@
1
+ /**
2
+ * graph.ts — Pure data module for GRAPH.yaml workflow step tracking.
3
+ *
4
+ * Provides types and functions for reading, writing, and querying the
5
+ * step graph that drives CustomWorkflowEngine. Zero engine dependencies.
6
+ *
7
+ * GRAPH.yaml lives in a run directory and tracks step statuses
8
+ * (pending → active → complete) with optional dependency edges.
9
+ *
10
+ * Observability:
11
+ * - readGraph/writeGraph use YAML on disk — human-readable, diffable,
12
+ * inspectable with `cat` or any YAML viewer.
13
+ * - Each GraphStep has status, startedAt, finishedAt fields visible in GRAPH.yaml.
14
+ * - writeGraph uses atomic write (tmp + rename) for crash safety.
15
+ * - All operations are immutable — callers always get a new graph object.
16
+ */
17
+
18
+ import { parse, stringify } from "yaml";
19
+ import { readFileSync, writeFileSync, renameSync, existsSync, mkdirSync } from "node:fs";
20
+ import { join } from "node:path";
21
+ import type { WorkflowDefinition } from "./definition-loader.js";
22
+
23
+ // ─── Types ───────────────────────────────────────────────────────────────
24
+
25
+ export interface GraphStep {
26
+ /** Unique step identifier within the workflow. */
27
+ id: string;
28
+ /** Human-readable step title. */
29
+ title: string;
30
+ /** Current status: pending → active → complete → expanded (iterate parent). */
31
+ status: "pending" | "active" | "complete" | "expanded";
32
+ /** The prompt to dispatch for this step. */
33
+ prompt: string;
34
+ /** IDs of steps that must be "complete" before this step can run. */
35
+ dependsOn: string[];
36
+ /** For iteration instances: ID of the parent step that was expanded. */
37
+ parentStepId?: string;
38
+ /** ISO timestamp when the step started executing. */
39
+ startedAt?: string;
40
+ /** ISO timestamp when the step finished executing. */
41
+ finishedAt?: string;
42
+ }
43
+
44
+ export interface WorkflowGraph {
45
+ /** Ordered list of steps in the workflow. */
46
+ steps: GraphStep[];
47
+ /** Workflow metadata. */
48
+ metadata: {
49
+ name: string;
50
+ createdAt: string;
51
+ };
52
+ }
53
+
54
+ // ─── YAML schema mapping ─────────────────────────────────────────────────
55
+
56
+ const GRAPH_FILENAME = "GRAPH.yaml";
57
+
58
+ /**
59
+ * Internal YAML shape — uses snake_case for YAML keys.
60
+ * Converted to/from the camelCase TypeScript types on read/write.
61
+ */
62
+ interface YamlStep {
63
+ id: string;
64
+ title: string;
65
+ status: string;
66
+ prompt: string;
67
+ depends_on?: string[];
68
+ parent_step_id?: string;
69
+ started_at?: string;
70
+ finished_at?: string;
71
+ }
72
+
73
+ interface YamlGraph {
74
+ steps: YamlStep[];
75
+ metadata: { name: string; created_at: string };
76
+ }
77
+
78
+ // ─── Functions ───────────────────────────────────────────────────────────
79
+
80
+ /**
81
+ * Read and parse GRAPH.yaml from a run directory.
82
+ *
83
+ * @param runDir — directory containing GRAPH.yaml
84
+ * @returns Parsed workflow graph
85
+ * @throws Error if file doesn't exist or YAML is malformed
86
+ */
87
+ export function readGraph(runDir: string): WorkflowGraph {
88
+ const filePath = join(runDir, GRAPH_FILENAME);
89
+ if (!existsSync(filePath)) {
90
+ throw new Error(`GRAPH.yaml not found: ${filePath}`);
91
+ }
92
+ const raw = readFileSync(filePath, "utf-8");
93
+ const yaml = parse(raw) as YamlGraph;
94
+
95
+ if (!yaml?.steps || !Array.isArray(yaml.steps)) {
96
+ throw new Error(`Invalid GRAPH.yaml: missing or invalid 'steps' array in ${filePath}`);
97
+ }
98
+
99
+ return {
100
+ steps: yaml.steps.map((s) => ({
101
+ id: s.id,
102
+ title: s.title,
103
+ status: s.status as GraphStep["status"],
104
+ prompt: s.prompt,
105
+ dependsOn: s.depends_on ?? [],
106
+ ...(s.parent_step_id != null ? { parentStepId: s.parent_step_id } : {}),
107
+ ...(s.started_at != null ? { startedAt: s.started_at } : {}),
108
+ ...(s.finished_at != null ? { finishedAt: s.finished_at } : {}),
109
+ })),
110
+ metadata: {
111
+ name: yaml.metadata?.name ?? "unnamed",
112
+ createdAt: yaml.metadata?.created_at ?? new Date().toISOString(),
113
+ },
114
+ };
115
+ }
116
+
117
+ /**
118
+ * Write a workflow graph to GRAPH.yaml in a run directory.
119
+ * Creates the directory if it doesn't exist. Write is atomic (write + rename).
120
+ *
121
+ * @param runDir — directory to write GRAPH.yaml into
122
+ * @param graph — the workflow graph to serialize
123
+ */
124
+ export function writeGraph(runDir: string, graph: WorkflowGraph): void {
125
+ if (!existsSync(runDir)) {
126
+ mkdirSync(runDir, { recursive: true });
127
+ }
128
+
129
+ const yamlData: YamlGraph = {
130
+ steps: graph.steps.map((s) => ({
131
+ id: s.id,
132
+ title: s.title,
133
+ status: s.status,
134
+ prompt: s.prompt,
135
+ depends_on: s.dependsOn.length > 0 ? s.dependsOn : undefined,
136
+ parent_step_id: s.parentStepId ?? undefined,
137
+ started_at: s.startedAt ?? undefined,
138
+ finished_at: s.finishedAt ?? undefined,
139
+ })) as YamlStep[],
140
+ metadata: {
141
+ name: graph.metadata.name,
142
+ created_at: graph.metadata.createdAt,
143
+ },
144
+ };
145
+
146
+ const filePath = join(runDir, GRAPH_FILENAME);
147
+ const tmpPath = filePath + ".tmp";
148
+ const content = stringify(yamlData);
149
+ writeFileSync(tmpPath, content, "utf-8");
150
+ // Atomic rename for crash safety
151
+ renameSync(tmpPath, filePath);
152
+ }
153
+
154
+ /**
155
+ * Get the next pending step whose dependencies are all complete.
156
+ *
157
+ * Returns the first step (in array order) with status "pending" where
158
+ * every step in its `dependsOn` list has status "complete".
159
+ *
160
+ * @param graph — the workflow graph to query
161
+ * @returns The next dispatchable step, or null if none available
162
+ */
163
+ export function getNextPendingStep(graph: WorkflowGraph): GraphStep | null {
164
+ const statusMap = new Map(graph.steps.map((s) => [s.id, s.status]));
165
+
166
+ for (const step of graph.steps) {
167
+ if (step.status !== "pending") continue;
168
+ const depsComplete = step.dependsOn.every(
169
+ (depId) => statusMap.get(depId) === "complete",
170
+ );
171
+ if (depsComplete) return step;
172
+ }
173
+
174
+ return null;
175
+ }
176
+
177
+ /**
178
+ * Return a new graph with the specified step marked as "complete".
179
+ * Immutable — does not mutate the input graph.
180
+ *
181
+ * @param graph — the current workflow graph
182
+ * @param stepId — ID of the step to mark complete
183
+ * @returns New graph with the step's status set to "complete"
184
+ * @throws Error if stepId is not found in the graph
185
+ */
186
+ export function markStepComplete(
187
+ graph: WorkflowGraph,
188
+ stepId: string,
189
+ ): WorkflowGraph {
190
+ const found = graph.steps.some((s) => s.id === stepId);
191
+ if (!found) {
192
+ throw new Error(`Step not found: ${stepId}`);
193
+ }
194
+
195
+ return {
196
+ ...graph,
197
+ steps: graph.steps.map((s) =>
198
+ s.id === stepId
199
+ ? { ...s, status: "complete" as const, finishedAt: new Date().toISOString() }
200
+ : s,
201
+ ),
202
+ };
203
+ }
204
+
205
+ // ─── Iteration expansion ─────────────────────────────────────────────────
206
+
207
+ /**
208
+ * Expand an iterate step into concrete instances. Pure and deterministic —
209
+ * identical inputs always produce identical output.
210
+ *
211
+ * Given a parent step with status "pending" and an array of matched items,
212
+ * creates one instance step per item, marks the parent as "expanded", and
213
+ * rewrites any downstream dependsOn references from the parent ID to the
214
+ * full set of instance IDs.
215
+ *
216
+ * @param graph — the current workflow graph (not mutated)
217
+ * @param stepId — ID of the iterate step to expand
218
+ * @param items — matched items from the source artifact
219
+ * @param promptTemplate — template with {{item}} placeholders
220
+ * @returns New WorkflowGraph with instances inserted and deps rewritten
221
+ * @throws Error if stepId not found or step is not pending
222
+ */
223
+ export function expandIteration(
224
+ graph: WorkflowGraph,
225
+ stepId: string,
226
+ items: string[],
227
+ promptTemplate: string,
228
+ ): WorkflowGraph {
229
+ const parentIndex = graph.steps.findIndex((s) => s.id === stepId);
230
+ if (parentIndex === -1) {
231
+ throw new Error(`expandIteration: step not found: ${stepId}`);
232
+ }
233
+ const parentStep = graph.steps[parentIndex];
234
+ if (parentStep.status !== "pending") {
235
+ throw new Error(
236
+ `expandIteration: step "${stepId}" has status "${parentStep.status}", expected "pending"`,
237
+ );
238
+ }
239
+
240
+ // Create instance steps
241
+ const instanceIds: string[] = [];
242
+ const instances: GraphStep[] = items.map((item, i) => {
243
+ const instanceId = `${stepId}--${String(i + 1).padStart(3, "0")}`;
244
+ instanceIds.push(instanceId);
245
+ return {
246
+ id: instanceId,
247
+ title: `${parentStep.title}: ${item}`,
248
+ status: "pending" as const,
249
+ prompt: promptTemplate.replace(/\{\{item\}\}/g, () => item),
250
+ dependsOn: [...parentStep.dependsOn],
251
+ parentStepId: stepId,
252
+ };
253
+ });
254
+
255
+ // Build new steps array: copy everything, mark parent as expanded,
256
+ // insert instances right after the parent, rewrite downstream deps.
257
+ const newSteps: GraphStep[] = [];
258
+ for (let i = 0; i < graph.steps.length; i++) {
259
+ if (i === parentIndex) {
260
+ // Mark parent as expanded
261
+ newSteps.push({ ...parentStep, status: "expanded" as const });
262
+ // Insert instances immediately after parent
263
+ newSteps.push(...instances);
264
+ } else {
265
+ const step = graph.steps[i];
266
+ // Rewrite dependsOn: replace parent ID with all instance IDs
267
+ const hasDep = step.dependsOn.includes(stepId);
268
+ if (hasDep) {
269
+ const rewritten = step.dependsOn.flatMap((dep) =>
270
+ dep === stepId ? instanceIds : [dep],
271
+ );
272
+ newSteps.push({ ...step, dependsOn: rewritten });
273
+ } else {
274
+ newSteps.push(step);
275
+ }
276
+ }
277
+ }
278
+
279
+ return {
280
+ ...graph,
281
+ steps: newSteps,
282
+ };
283
+ }
284
+
285
+ // ─── Definition → Graph conversion ──────────────────────────────────────
286
+
287
+ /**
288
+ * Convert a parsed WorkflowDefinition into a WorkflowGraph with all
289
+ * steps in "pending" status. Used by run-manager to generate the initial
290
+ * GRAPH.yaml for a new run.
291
+ *
292
+ * @param def — a validated WorkflowDefinition from definition-loader
293
+ * @returns WorkflowGraph with pending steps and metadata from the definition
294
+ */
295
+ export function initializeGraph(def: WorkflowDefinition): WorkflowGraph {
296
+ return {
297
+ steps: def.steps.map((s) => ({
298
+ id: s.id,
299
+ title: s.name,
300
+ status: "pending" as const,
301
+ prompt: s.prompt,
302
+ dependsOn: s.requires ?? [],
303
+ })),
304
+ metadata: {
305
+ name: def.name,
306
+ createdAt: new Date().toISOString(),
307
+ },
308
+ };
309
+ }
310
+
311
+ /** @deprecated Use initializeGraph instead. Kept for backward compatibility. */
312
+ export { initializeGraph as graphFromDefinition };