@opengsd/gsd-pi 1.5.0 → 1.6.0

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 (499) hide show
  1. package/README.md +10 -10
  2. package/dist/resources/.managed-resources-content-hash +1 -1
  3. package/dist/resources/extensions/ask-user-questions.js +1 -1
  4. package/dist/resources/extensions/browser-tools/engine/managed-gsd-browser.js +114 -36
  5. package/dist/resources/extensions/gsd/activity-log.js +1 -1
  6. package/dist/resources/extensions/gsd/auto/closeout.js +97 -5
  7. package/dist/resources/extensions/gsd/auto/orchestrator.js +20 -13
  8. package/dist/resources/extensions/gsd/auto/pre-dispatch.js +6 -3
  9. package/dist/resources/extensions/gsd/auto/unit-phase.js +5 -9
  10. package/dist/resources/extensions/gsd/auto-artifact-paths.js +14 -5
  11. package/dist/resources/extensions/gsd/auto-direct-dispatch.js +11 -7
  12. package/dist/resources/extensions/gsd/auto-dispatch.js +69 -17
  13. package/dist/resources/extensions/gsd/auto-model-selection.js +28 -1
  14. package/dist/resources/extensions/gsd/auto-post-unit.js +4 -3
  15. package/dist/resources/extensions/gsd/auto-prompts.js +29 -117
  16. package/dist/resources/extensions/gsd/auto-recovery.js +50 -6
  17. package/dist/resources/extensions/gsd/auto-start.js +57 -33
  18. package/dist/resources/extensions/gsd/auto-timeout-recovery.js +12 -2
  19. package/dist/resources/extensions/gsd/auto-timers.js +9 -2
  20. package/dist/resources/extensions/gsd/auto-worktree-branch-lifecycle.js +189 -0
  21. package/dist/resources/extensions/gsd/auto-worktree-cleanup.js +133 -0
  22. package/dist/resources/extensions/gsd/auto-worktree-conflict-auto-resolve.js +35 -0
  23. package/dist/resources/extensions/gsd/auto-worktree-creation.js +130 -0
  24. package/dist/resources/extensions/gsd/auto-worktree-entry.js +118 -0
  25. package/dist/resources/extensions/gsd/auto-worktree-merge-already-merged.js +98 -0
  26. package/dist/resources/extensions/gsd/auto-worktree-merge-branch-head.js +52 -0
  27. package/dist/resources/extensions/gsd/auto-worktree-merge-cleanup.js +87 -0
  28. package/dist/resources/extensions/gsd/auto-worktree-merge-code-changes.js +46 -0
  29. package/dist/resources/extensions/gsd/auto-worktree-merge-db-ready.js +68 -0
  30. package/dist/resources/extensions/gsd/auto-worktree-merge-integration-branch.js +51 -0
  31. package/dist/resources/extensions/gsd/auto-worktree-merge-message.js +106 -0
  32. package/dist/resources/extensions/gsd/auto-worktree-merge-pre-teardown.js +64 -0
  33. package/dist/resources/extensions/gsd/auto-worktree-merge-stash.js +168 -0
  34. package/dist/resources/extensions/gsd/auto-worktree-merge.js +302 -0
  35. package/dist/resources/extensions/gsd/auto-worktree-milestone-shelter.js +119 -0
  36. package/dist/resources/extensions/gsd/auto-worktree-path-resolution.js +5 -0
  37. package/dist/resources/extensions/gsd/auto-worktree-path-utils.js +5 -0
  38. package/dist/resources/extensions/gsd/auto-worktree-resource-version.js +41 -0
  39. package/dist/resources/extensions/gsd/auto-worktree-runtime-cleanup.js +99 -0
  40. package/dist/resources/extensions/gsd/auto-worktree-session-registry.js +57 -0
  41. package/dist/resources/extensions/gsd/auto-worktree-sync.js +249 -0
  42. package/dist/resources/extensions/gsd/auto-worktree-teardown.js +120 -0
  43. package/dist/resources/extensions/gsd/auto-worktree.js +20 -2073
  44. package/dist/resources/extensions/gsd/auto.js +106 -34
  45. package/dist/resources/extensions/gsd/bootstrap/dynamic-tools.js +1 -1
  46. package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +20 -2
  47. package/dist/resources/extensions/gsd/bootstrap/system-context.js +1 -1
  48. package/dist/resources/extensions/gsd/bootstrap/tool-call-loop-guard.js +185 -27
  49. package/dist/resources/extensions/gsd/codebase-generator.js +7 -1
  50. package/dist/resources/extensions/gsd/commands-handlers.js +1 -1
  51. package/dist/resources/extensions/gsd/commands-workflow-templates.js +3 -3
  52. package/dist/resources/extensions/gsd/compat/compat-marker.js +44 -0
  53. package/dist/resources/extensions/gsd/config-overlay.js +7 -2
  54. package/dist/resources/extensions/gsd/db/engine.js +33 -0
  55. package/dist/resources/extensions/gsd/db/queries.js +9 -9
  56. package/dist/resources/extensions/gsd/db/writers/cascades.js +20 -2
  57. package/dist/resources/extensions/gsd/db-adapter.js +30 -3
  58. package/dist/resources/extensions/gsd/docs/preferences-reference.md +3 -3
  59. package/dist/resources/extensions/gsd/doctor-engine-checks.js +93 -11
  60. package/dist/resources/extensions/gsd/flat-phase-migration.js +32 -3
  61. package/dist/resources/extensions/gsd/forensics.js +1 -1
  62. package/dist/resources/extensions/gsd/git-conflict-resolve.js +2 -2
  63. package/dist/resources/extensions/gsd/git-service.js +45 -0
  64. package/dist/resources/extensions/gsd/gsd-db.js +23 -11
  65. package/dist/resources/extensions/gsd/guided-flow.js +22 -17
  66. package/dist/resources/extensions/gsd/journal.js +1 -1
  67. package/dist/resources/extensions/gsd/markdown-renderer.js +34 -79
  68. package/dist/resources/extensions/gsd/md-importer.js +89 -23
  69. package/dist/resources/extensions/gsd/metrics.js +2 -2
  70. package/dist/resources/extensions/gsd/migration-auto-check.js +30 -3
  71. package/dist/resources/extensions/gsd/milestone-merge-transaction.js +11 -0
  72. package/dist/resources/extensions/gsd/milestone-settlement.js +1 -1
  73. package/dist/resources/extensions/gsd/parallel-merge.js +1 -1
  74. package/dist/resources/extensions/gsd/parallel-orchestrator.js +3 -1
  75. package/dist/resources/extensions/gsd/paths.js +87 -52
  76. package/dist/resources/extensions/gsd/post-unit-hooks.js +27 -0
  77. package/dist/resources/extensions/gsd/preferences-models.js +66 -15
  78. package/dist/resources/extensions/gsd/preferences-skills.js +10 -16
  79. package/dist/resources/extensions/gsd/preferences-types.js +1 -0
  80. package/dist/resources/extensions/gsd/preferences-validation.js +148 -10
  81. package/dist/resources/extensions/gsd/preferences.js +20 -0
  82. package/dist/resources/extensions/gsd/prompts/system.md +6 -6
  83. package/dist/resources/extensions/gsd/quick.js +12 -3
  84. package/dist/resources/extensions/gsd/rule-registry.js +106 -10
  85. package/dist/resources/extensions/gsd/skill-discovery.js +36 -23
  86. package/dist/resources/extensions/gsd/slice-parallel-orchestrator.js +2 -1
  87. package/dist/resources/extensions/gsd/state/derive/from-db.js +88 -153
  88. package/dist/resources/extensions/gsd/state-reconciliation/drift/artifact-db.js +1 -10
  89. package/dist/resources/extensions/gsd/state-reconciliation/drift/completion.js +3 -24
  90. package/dist/resources/extensions/gsd/state-reconciliation/index.js +10 -0
  91. package/dist/resources/extensions/gsd/tool-contract.js +14 -0
  92. package/dist/resources/extensions/gsd/tools/complete-milestone.js +3 -5
  93. package/dist/resources/extensions/gsd/tools/reassess-roadmap.js +16 -10
  94. package/dist/resources/extensions/gsd/tools/reopen-slice.js +5 -0
  95. package/dist/resources/extensions/gsd/tools/reopen-task.js +13 -5
  96. package/dist/resources/extensions/gsd/tools/validate-milestone.js +3 -8
  97. package/dist/resources/extensions/gsd/uat-dispatch.js +94 -0
  98. package/dist/resources/extensions/gsd/unit-registry.js +12 -2
  99. package/dist/resources/extensions/gsd/unmerged-milestone-guard.js +1 -1
  100. package/dist/resources/extensions/gsd/uok/audit-toggle.js +31 -2
  101. package/dist/resources/extensions/gsd/uok/audit.js +3 -0
  102. package/dist/resources/extensions/gsd/uok/gate-runner.js +22 -30
  103. package/dist/resources/extensions/gsd/uok/gitops.js +18 -15
  104. package/dist/resources/extensions/gsd/uok/kernel.js +120 -46
  105. package/dist/resources/extensions/gsd/uok/model-policy.js +17 -14
  106. package/dist/resources/extensions/gsd/validation-block-guard.js +2 -1
  107. package/dist/resources/extensions/gsd/workflow-event-ledger.js +1 -1
  108. package/dist/resources/extensions/gsd/workflow-logger.js +1 -1
  109. package/dist/resources/extensions/gsd/workflow-projections.js +9 -26
  110. package/dist/resources/extensions/gsd/workspace-git-preflight.js +2 -2
  111. package/dist/resources/extensions/gsd/workspace.js +5 -14
  112. package/dist/resources/extensions/gsd/worktree-command.js +1 -1
  113. package/dist/resources/extensions/gsd/worktree-lifecycle.js +14 -9
  114. package/dist/resources/extensions/gsd/worktree-reentry.js +2 -1
  115. package/dist/resources/extensions/shared/gsd-browser-cli.js +29 -0
  116. package/dist/resources/extensions/shared/interview-ui.js +62 -9
  117. package/dist/tsconfig.extensions.tsbuildinfo +1 -1
  118. package/dist/web/standalone/.next/BUILD_ID +1 -1
  119. package/dist/web/standalone/.next/app-path-routes-manifest.json +9 -9
  120. package/dist/web/standalone/.next/build-manifest.json +2 -2
  121. package/dist/web/standalone/.next/prerender-manifest.json +3 -3
  122. package/dist/web/standalone/.next/server/app/_global-error.html +1 -1
  123. package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
  124. package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  125. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
  126. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
  127. package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  128. package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  129. package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  130. package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
  131. package/dist/web/standalone/.next/server/app/_not-found.rsc +1 -1
  132. package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
  133. package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  134. package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +1 -1
  135. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  136. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  137. package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
  138. package/dist/web/standalone/.next/server/app/api/boot/route.js.nft.json +1 -1
  139. package/dist/web/standalone/.next/server/app/api/bridge-terminal/input/route.js.nft.json +1 -1
  140. package/dist/web/standalone/.next/server/app/api/bridge-terminal/resize/route.js.nft.json +1 -1
  141. package/dist/web/standalone/.next/server/app/api/bridge-terminal/stream/route.js.nft.json +1 -1
  142. package/dist/web/standalone/.next/server/app/api/captures/route.js.nft.json +1 -1
  143. package/dist/web/standalone/.next/server/app/api/cleanup/route.js.nft.json +1 -1
  144. package/dist/web/standalone/.next/server/app/api/doctor/route.js.nft.json +1 -1
  145. package/dist/web/standalone/.next/server/app/api/export-data/route.js.nft.json +1 -1
  146. package/dist/web/standalone/.next/server/app/api/files/route.js.nft.json +1 -1
  147. package/dist/web/standalone/.next/server/app/api/forensics/route.js.nft.json +1 -1
  148. package/dist/web/standalone/.next/server/app/api/git/route.js.nft.json +1 -1
  149. package/dist/web/standalone/.next/server/app/api/history/route.js.nft.json +1 -1
  150. package/dist/web/standalone/.next/server/app/api/hooks/route.js.nft.json +1 -1
  151. package/dist/web/standalone/.next/server/app/api/inspect/route.js.nft.json +1 -1
  152. package/dist/web/standalone/.next/server/app/api/knowledge/route.js.nft.json +1 -1
  153. package/dist/web/standalone/.next/server/app/api/live-state/route.js.nft.json +1 -1
  154. package/dist/web/standalone/.next/server/app/api/mcp-connections/route.js.nft.json +1 -1
  155. package/dist/web/standalone/.next/server/app/api/notifications/route.js.nft.json +1 -1
  156. package/dist/web/standalone/.next/server/app/api/onboarding/route.js.nft.json +1 -1
  157. package/dist/web/standalone/.next/server/app/api/projects/route.js.nft.json +1 -1
  158. package/dist/web/standalone/.next/server/app/api/recovery/route.js.nft.json +1 -1
  159. package/dist/web/standalone/.next/server/app/api/session/browser/route.js.nft.json +1 -1
  160. package/dist/web/standalone/.next/server/app/api/session/command/route.js.nft.json +1 -1
  161. package/dist/web/standalone/.next/server/app/api/session/events/route.js.nft.json +1 -1
  162. package/dist/web/standalone/.next/server/app/api/session/manage/route.js.nft.json +1 -1
  163. package/dist/web/standalone/.next/server/app/api/settings-data/route.js.nft.json +1 -1
  164. package/dist/web/standalone/.next/server/app/api/shutdown/route.js.nft.json +1 -1
  165. package/dist/web/standalone/.next/server/app/api/skill-health/route.js.nft.json +1 -1
  166. package/dist/web/standalone/.next/server/app/api/steer/route.js.nft.json +1 -1
  167. package/dist/web/standalone/.next/server/app/api/switch-root/route.js.nft.json +1 -1
  168. package/dist/web/standalone/.next/server/app/api/terminal/sessions/route.js.nft.json +1 -1
  169. package/dist/web/standalone/.next/server/app/api/terminal/stream/route.js.nft.json +1 -1
  170. package/dist/web/standalone/.next/server/app/api/undo/route.js.nft.json +1 -1
  171. package/dist/web/standalone/.next/server/app/api/visualizer/route.js.nft.json +1 -1
  172. package/dist/web/standalone/.next/server/app/index.html +1 -1
  173. package/dist/web/standalone/.next/server/app/index.rsc +1 -1
  174. package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +1 -1
  175. package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +1 -1
  176. package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
  177. package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +1 -1
  178. package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
  179. package/dist/web/standalone/.next/server/app-paths-manifest.json +9 -9
  180. package/dist/web/standalone/.next/server/chunks/{1128.js → 1991.js} +1 -1
  181. package/dist/web/standalone/.next/server/chunks/8357.js +1 -1
  182. package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
  183. package/dist/web/standalone/.next/server/pages/404.html +1 -1
  184. package/dist/web/standalone/.next/server/pages/500.html +1 -1
  185. package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
  186. package/dist/web/standalone/node_modules/@gsd/native/package.json +1 -1
  187. package/dist/web/standalone/node_modules/node-pty/build/Makefile +1 -1
  188. package/dist/worktree-cli-create.d.ts +10 -0
  189. package/dist/worktree-cli-create.js +11 -0
  190. package/dist/worktree-cli-format.d.ts +12 -0
  191. package/dist/worktree-cli-format.js +38 -0
  192. package/dist/worktree-cli-plan.d.ts +16 -0
  193. package/dist/worktree-cli-plan.js +19 -0
  194. package/dist/worktree-cli-session.d.ts +13 -0
  195. package/dist/worktree-cli-session.js +18 -0
  196. package/dist/worktree-cli-status.d.ts +35 -0
  197. package/dist/worktree-cli-status.js +54 -0
  198. package/dist/worktree-cli.d.ts +1 -16
  199. package/dist/worktree-cli.js +28 -122
  200. package/integrations/hermes/open_gsd_hermes/gsd_client.py +25 -36
  201. package/integrations/hermes/pyproject.toml +1 -1
  202. package/integrations/hermes/tests/test_gsd_client_timeout.py +4 -4
  203. package/package.json +6 -6
  204. package/packages/cloud-mcp-gateway/package.json +2 -2
  205. package/packages/contracts/package.json +1 -1
  206. package/packages/daemon/dist/orchestrator-agent.d.ts +21 -0
  207. package/packages/daemon/dist/orchestrator-agent.d.ts.map +1 -0
  208. package/packages/daemon/dist/orchestrator-agent.js +113 -0
  209. package/packages/daemon/dist/orchestrator-agent.js.map +1 -0
  210. package/packages/daemon/dist/orchestrator-tools.d.ts +12 -0
  211. package/packages/daemon/dist/orchestrator-tools.d.ts.map +1 -0
  212. package/packages/daemon/dist/orchestrator-tools.js +137 -0
  213. package/packages/daemon/dist/orchestrator-tools.js.map +1 -0
  214. package/packages/daemon/dist/orchestrator.d.ts +4 -56
  215. package/packages/daemon/dist/orchestrator.d.ts.map +1 -1
  216. package/packages/daemon/dist/orchestrator.js +13 -303
  217. package/packages/daemon/dist/orchestrator.js.map +1 -1
  218. package/packages/daemon/dist/orchestrator.test.js +11 -1
  219. package/packages/daemon/dist/orchestrator.test.js.map +1 -1
  220. package/packages/daemon/package.json +4 -4
  221. package/packages/gsd-agent-core/dist/export-html/template.js +53 -4
  222. package/packages/gsd-agent-core/package.json +5 -5
  223. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-controller.d.ts.map +1 -1
  224. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-controller.js +3 -2
  225. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-controller.js.map +1 -1
  226. package/packages/gsd-agent-modes/package.json +7 -7
  227. package/packages/mcp-server/package.json +4 -4
  228. package/packages/native/package.json +1 -1
  229. package/packages/pi-agent-core/dist/agent-loop.d.ts.map +1 -1
  230. package/packages/pi-agent-core/dist/agent-loop.js +14 -9
  231. package/packages/pi-agent-core/dist/agent-loop.js.map +1 -1
  232. package/packages/pi-agent-core/package.json +1 -1
  233. package/packages/pi-ai/dist/index.d.ts +1 -0
  234. package/packages/pi-ai/dist/index.d.ts.map +1 -1
  235. package/packages/pi-ai/dist/index.js +1 -0
  236. package/packages/pi-ai/dist/index.js.map +1 -1
  237. package/packages/pi-ai/dist/providers/transform-messages.d.ts.map +1 -1
  238. package/packages/pi-ai/dist/providers/transform-messages.js +7 -3
  239. package/packages/pi-ai/dist/providers/transform-messages.js.map +1 -1
  240. package/packages/pi-ai/dist/tool-result-content.d.ts +3 -0
  241. package/packages/pi-ai/dist/tool-result-content.d.ts.map +1 -0
  242. package/packages/pi-ai/dist/tool-result-content.js +62 -0
  243. package/packages/pi-ai/dist/tool-result-content.js.map +1 -0
  244. package/packages/pi-ai/dist/types.d.ts +8 -20
  245. package/packages/pi-ai/dist/types.d.ts.map +1 -1
  246. package/packages/pi-ai/dist/types.js.map +1 -1
  247. package/packages/pi-ai/package.json +1 -1
  248. package/packages/pi-coding-agent/dist/core/package-manager.d.ts +9 -0
  249. package/packages/pi-coding-agent/dist/core/package-manager.d.ts.map +1 -1
  250. package/packages/pi-coding-agent/dist/core/package-manager.js +74 -53
  251. package/packages/pi-coding-agent/dist/core/package-manager.js.map +1 -1
  252. package/packages/pi-coding-agent/dist/core/resource-loader.d.ts +6 -0
  253. package/packages/pi-coding-agent/dist/core/resource-loader.d.ts.map +1 -1
  254. package/packages/pi-coding-agent/dist/core/resource-loader.js +30 -2
  255. package/packages/pi-coding-agent/dist/core/resource-loader.js.map +1 -1
  256. package/packages/pi-coding-agent/dist/core/skill-directories.d.ts +66 -0
  257. package/packages/pi-coding-agent/dist/core/skill-directories.d.ts.map +1 -0
  258. package/packages/pi-coding-agent/dist/core/skill-directories.js +138 -0
  259. package/packages/pi-coding-agent/dist/core/skill-directories.js.map +1 -0
  260. package/packages/pi-coding-agent/dist/core/skills.d.ts +4 -1
  261. package/packages/pi-coding-agent/dist/core/skills.d.ts.map +1 -1
  262. package/packages/pi-coding-agent/dist/core/skills.js +4 -1
  263. package/packages/pi-coding-agent/dist/core/skills.js.map +1 -1
  264. package/packages/pi-coding-agent/dist/index.d.ts +1 -0
  265. package/packages/pi-coding-agent/dist/index.d.ts.map +1 -1
  266. package/packages/pi-coding-agent/dist/index.js +1 -0
  267. package/packages/pi-coding-agent/dist/index.js.map +1 -1
  268. package/packages/pi-coding-agent/package.json +7 -7
  269. package/packages/pi-tui/package.json +2 -2
  270. package/packages/rpc-client/package.json +2 -2
  271. package/pkg/dist/core/export-html/template.js +53 -4
  272. package/pkg/package.json +1 -1
  273. package/src/resources/extensions/ask-user-questions.ts +1 -1
  274. package/src/resources/extensions/browser-tools/engine/managed-gsd-browser.ts +146 -33
  275. package/src/resources/extensions/browser-tools/tests/gsd-browser-launch-config.test.mjs +25 -0
  276. package/src/resources/extensions/browser-tools/tests/managed-gsd-browser-tools.test.mjs +93 -0
  277. package/src/resources/extensions/gsd/activity-log.ts +1 -1
  278. package/src/resources/extensions/gsd/auto/closeout.ts +114 -7
  279. package/src/resources/extensions/gsd/auto/orchestrator.ts +21 -14
  280. package/src/resources/extensions/gsd/auto/pre-dispatch.ts +6 -3
  281. package/src/resources/extensions/gsd/auto/unit-phase.ts +5 -9
  282. package/src/resources/extensions/gsd/auto-artifact-paths.ts +14 -4
  283. package/src/resources/extensions/gsd/auto-direct-dispatch.ts +13 -7
  284. package/src/resources/extensions/gsd/auto-dispatch.ts +77 -16
  285. package/src/resources/extensions/gsd/auto-model-selection.ts +33 -1
  286. package/src/resources/extensions/gsd/auto-post-unit.ts +4 -2
  287. package/src/resources/extensions/gsd/auto-prompts.ts +53 -113
  288. package/src/resources/extensions/gsd/auto-recovery.ts +50 -6
  289. package/src/resources/extensions/gsd/auto-start.ts +62 -31
  290. package/src/resources/extensions/gsd/auto-timeout-recovery.ts +12 -2
  291. package/src/resources/extensions/gsd/auto-timers.ts +9 -2
  292. package/src/resources/extensions/gsd/auto-worktree-branch-lifecycle.ts +237 -0
  293. package/src/resources/extensions/gsd/auto-worktree-cleanup.ts +166 -0
  294. package/src/resources/extensions/gsd/auto-worktree-conflict-auto-resolve.ts +37 -0
  295. package/src/resources/extensions/gsd/auto-worktree-creation.ts +171 -0
  296. package/src/resources/extensions/gsd/auto-worktree-entry.ts +154 -0
  297. package/src/resources/extensions/gsd/auto-worktree-merge-already-merged.ts +161 -0
  298. package/src/resources/extensions/gsd/auto-worktree-merge-branch-head.ts +83 -0
  299. package/src/resources/extensions/gsd/auto-worktree-merge-cleanup.ts +132 -0
  300. package/src/resources/extensions/gsd/auto-worktree-merge-code-changes.ts +71 -0
  301. package/src/resources/extensions/gsd/auto-worktree-merge-db-ready.ts +112 -0
  302. package/src/resources/extensions/gsd/auto-worktree-merge-integration-branch.ts +99 -0
  303. package/src/resources/extensions/gsd/auto-worktree-merge-message.ts +166 -0
  304. package/src/resources/extensions/gsd/auto-worktree-merge-pre-teardown.ts +93 -0
  305. package/src/resources/extensions/gsd/auto-worktree-merge-stash.ts +213 -0
  306. package/src/resources/extensions/gsd/auto-worktree-merge.ts +391 -0
  307. package/src/resources/extensions/gsd/auto-worktree-milestone-shelter.ts +159 -0
  308. package/src/resources/extensions/gsd/auto-worktree-path-resolution.ts +6 -0
  309. package/src/resources/extensions/gsd/auto-worktree-path-utils.ts +10 -0
  310. package/src/resources/extensions/gsd/auto-worktree-resource-version.ts +44 -0
  311. package/src/resources/extensions/gsd/auto-worktree-runtime-cleanup.ts +119 -0
  312. package/src/resources/extensions/gsd/auto-worktree-session-registry.ts +71 -0
  313. package/src/resources/extensions/gsd/auto-worktree-sync.ts +370 -0
  314. package/src/resources/extensions/gsd/auto-worktree-teardown.ts +161 -0
  315. package/src/resources/extensions/gsd/auto-worktree.ts +69 -2429
  316. package/src/resources/extensions/gsd/auto.ts +114 -47
  317. package/src/resources/extensions/gsd/bootstrap/dynamic-tools.ts +1 -1
  318. package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +20 -2
  319. package/src/resources/extensions/gsd/bootstrap/system-context.ts +1 -1
  320. package/src/resources/extensions/gsd/bootstrap/tool-call-loop-guard.ts +218 -27
  321. package/src/resources/extensions/gsd/codebase-generator.ts +7 -1
  322. package/src/resources/extensions/gsd/commands-handlers.ts +1 -1
  323. package/src/resources/extensions/gsd/commands-workflow-templates.ts +3 -3
  324. package/src/resources/extensions/gsd/compat/compat-marker.ts +47 -0
  325. package/src/resources/extensions/gsd/config-overlay.ts +7 -1
  326. package/src/resources/extensions/gsd/db/engine.ts +36 -0
  327. package/src/resources/extensions/gsd/db/queries.ts +9 -9
  328. package/src/resources/extensions/gsd/db/writers/cascades.ts +23 -1
  329. package/src/resources/extensions/gsd/db-adapter.ts +29 -3
  330. package/src/resources/extensions/gsd/docs/preferences-reference.md +3 -3
  331. package/src/resources/extensions/gsd/doctor-engine-checks.ts +109 -10
  332. package/src/resources/extensions/gsd/flat-phase-migration.ts +34 -3
  333. package/src/resources/extensions/gsd/forensics.ts +1 -1
  334. package/src/resources/extensions/gsd/git-conflict-resolve.ts +2 -2
  335. package/src/resources/extensions/gsd/git-service.ts +53 -0
  336. package/src/resources/extensions/gsd/gsd-db.ts +33 -11
  337. package/src/resources/extensions/gsd/guided-flow.ts +26 -18
  338. package/src/resources/extensions/gsd/journal.ts +1 -1
  339. package/src/resources/extensions/gsd/markdown-renderer.ts +52 -91
  340. package/src/resources/extensions/gsd/md-importer.ts +93 -22
  341. package/src/resources/extensions/gsd/metrics.ts +2 -2
  342. package/src/resources/extensions/gsd/migration-auto-check.ts +32 -3
  343. package/src/resources/extensions/gsd/milestone-merge-transaction.ts +15 -0
  344. package/src/resources/extensions/gsd/milestone-settlement.ts +1 -1
  345. package/src/resources/extensions/gsd/parallel-merge.ts +1 -1
  346. package/src/resources/extensions/gsd/parallel-orchestrator.ts +3 -1
  347. package/src/resources/extensions/gsd/paths.ts +108 -51
  348. package/src/resources/extensions/gsd/post-unit-hooks.ts +32 -0
  349. package/src/resources/extensions/gsd/preferences-models.ts +74 -20
  350. package/src/resources/extensions/gsd/preferences-skills.ts +10 -16
  351. package/src/resources/extensions/gsd/preferences-types.ts +54 -1
  352. package/src/resources/extensions/gsd/preferences-validation.ts +146 -9
  353. package/src/resources/extensions/gsd/preferences.ts +20 -0
  354. package/src/resources/extensions/gsd/prompts/system.md +6 -6
  355. package/src/resources/extensions/gsd/quick.ts +11 -3
  356. package/src/resources/extensions/gsd/rule-registry.ts +111 -9
  357. package/src/resources/extensions/gsd/skill-discovery.ts +47 -23
  358. package/src/resources/extensions/gsd/slice-parallel-orchestrator.ts +3 -1
  359. package/src/resources/extensions/gsd/state/derive/from-db.ts +201 -157
  360. package/src/resources/extensions/gsd/state-reconciliation/drift/artifact-db.ts +1 -9
  361. package/src/resources/extensions/gsd/state-reconciliation/drift/completion.ts +2 -22
  362. package/src/resources/extensions/gsd/state-reconciliation/index.ts +14 -0
  363. package/src/resources/extensions/gsd/tests/auto-artifact-paths.test.ts +169 -1
  364. package/src/resources/extensions/gsd/tests/auto-loop-no-copy-artifacts.test.ts +2 -1
  365. package/src/resources/extensions/gsd/tests/auto-orchestrator.test.ts +41 -2
  366. package/src/resources/extensions/gsd/tests/auto-post-unit-artifact-diagnostic.test.ts +48 -1
  367. package/src/resources/extensions/gsd/tests/auto-recovery.test.ts +57 -0
  368. package/src/resources/extensions/gsd/tests/auto-start-clean-runtime-db-gated.test.ts +1 -1
  369. package/src/resources/extensions/gsd/tests/auto-start-project-milestone-reconcile.test.ts +29 -1
  370. package/src/resources/extensions/gsd/tests/auto-timeout-recovery-supervisor-inflight-guard.test.ts +159 -0
  371. package/src/resources/extensions/gsd/tests/auto-warning-noise-regression.test.ts +2 -1
  372. package/src/resources/extensions/gsd/tests/auto-worktree-auto-resolve.test.ts +1 -1
  373. package/src/resources/extensions/gsd/tests/auto-worktree-merge-already-merged.test.ts +177 -0
  374. package/src/resources/extensions/gsd/tests/auto-worktree-merge-branch-head.test.ts +118 -0
  375. package/src/resources/extensions/gsd/tests/auto-worktree-merge-cleanup.test.ts +115 -0
  376. package/src/resources/extensions/gsd/tests/auto-worktree-merge-code-changes.test.ts +76 -0
  377. package/src/resources/extensions/gsd/tests/auto-worktree-merge-db-ready.test.ts +140 -0
  378. package/src/resources/extensions/gsd/tests/auto-worktree-merge-integration-branch.test.ts +123 -0
  379. package/src/resources/extensions/gsd/tests/auto-worktree-merge-message.test.ts +114 -0
  380. package/src/resources/extensions/gsd/tests/auto-worktree-merge-pre-teardown.test.ts +84 -0
  381. package/src/resources/extensions/gsd/tests/auto-worktree-merge-stash.test.ts +70 -0
  382. package/src/resources/extensions/gsd/tests/auto-worktree-milestone-shelter.test.ts +52 -0
  383. package/src/resources/extensions/gsd/tests/auto-worktree-registry.test.ts +6 -6
  384. package/src/resources/extensions/gsd/tests/auto-worktree-resource-version.test.ts +59 -0
  385. package/src/resources/extensions/gsd/tests/auto-worktree-untracked-content.test.ts +3 -1
  386. package/src/resources/extensions/gsd/tests/codebase-generator.test.ts +22 -0
  387. package/src/resources/extensions/gsd/tests/commands-verdict.test.ts +3 -1
  388. package/src/resources/extensions/gsd/tests/compat-marker.test.ts +85 -0
  389. package/src/resources/extensions/gsd/tests/complete-milestone.test.ts +45 -0
  390. package/src/resources/extensions/gsd/tests/completed-units-metrics-sync.test.ts +1 -1
  391. package/src/resources/extensions/gsd/tests/db-adapter.test.ts +39 -0
  392. package/src/resources/extensions/gsd/tests/db-writable-probe.test.ts +66 -0
  393. package/src/resources/extensions/gsd/tests/derive-state-db.test.ts +4 -0
  394. package/src/resources/extensions/gsd/tests/doctor-scope-db-unavailable.test.ts +174 -0
  395. package/src/resources/extensions/gsd/tests/fast-forward-reused-milestone-branch.test.ts +1 -1
  396. package/src/resources/extensions/gsd/tests/flat-phase-migration.test.ts +71 -1
  397. package/src/resources/extensions/gsd/tests/flat-phase-renderer.test.ts +46 -1
  398. package/src/resources/extensions/gsd/tests/flat-phase-validation-path.test.ts +72 -32
  399. package/src/resources/extensions/gsd/tests/gsd-db.test.ts +40 -0
  400. package/src/resources/extensions/gsd/tests/import-completion-lost-update.test.ts +196 -0
  401. package/src/resources/extensions/gsd/tests/integration/all-milestones-complete-merge.test.ts +4 -6
  402. package/src/resources/extensions/gsd/tests/integration/auto-stash-merge.test.ts +2 -1
  403. package/src/resources/extensions/gsd/tests/integration/auto-worktree-milestone-merge.test.ts +3 -3
  404. package/src/resources/extensions/gsd/tests/integration/auto-worktree.test.ts +7 -8
  405. package/src/resources/extensions/gsd/tests/integration/feature-branch-lifecycle-integration.test.ts +2 -5
  406. package/src/resources/extensions/gsd/tests/integration/git-service.test.ts +76 -0
  407. package/src/resources/extensions/gsd/tests/integration/merge-cwd-restore.test.ts +1 -1
  408. package/src/resources/extensions/gsd/tests/integration/merge-preserve-worktree-on-preteardown-error.test.ts +1 -1
  409. package/src/resources/extensions/gsd/tests/integration/merge-strategy-regular.test.ts +2 -1
  410. package/src/resources/extensions/gsd/tests/integration/milestone-transition-worktree.test.ts +5 -7
  411. package/src/resources/extensions/gsd/tests/integration/paths.test.ts +88 -1
  412. package/src/resources/extensions/gsd/tests/integration/workspace-collapse-integration.test.ts +2 -4
  413. package/src/resources/extensions/gsd/tests/journal-integration.test.ts +16 -15
  414. package/src/resources/extensions/gsd/tests/merge-closeout-consistency-gate.test.ts +1 -1
  415. package/src/resources/extensions/gsd/tests/merge-db-cycle.test.ts +1 -1
  416. package/src/resources/extensions/gsd/tests/merge-self-branch-guard.test.ts +1 -1
  417. package/src/resources/extensions/gsd/tests/migration-auto-check.test.ts +91 -0
  418. package/src/resources/extensions/gsd/tests/milestone-closeout.test.ts +2 -1
  419. package/src/resources/extensions/gsd/tests/milestone-merge-stash-restore.test.ts +439 -0
  420. package/src/resources/extensions/gsd/tests/milestone-merge-transaction.test.ts +24 -0
  421. package/src/resources/extensions/gsd/tests/none-mode-gates.test.ts +1 -1
  422. package/src/resources/extensions/gsd/tests/originalbase-path-comparison.test.ts +3 -3
  423. package/src/resources/extensions/gsd/tests/parallel-worker-lock-contention.test.ts +1 -1
  424. package/src/resources/extensions/gsd/tests/parsers-legacy-importers.test.ts +0 -1
  425. package/src/resources/extensions/gsd/tests/post-unit-hooks.test.ts +269 -0
  426. package/src/resources/extensions/gsd/tests/post-unit-retry-on-orchestrator-bridge.test.ts +8 -1
  427. package/src/resources/extensions/gsd/tests/preferences-worktree-sync.test.ts +1 -4
  428. package/src/resources/extensions/gsd/tests/preferences.test.ts +19 -0
  429. package/src/resources/extensions/gsd/tests/prefs-wizard-coverage.test.ts +5 -0
  430. package/src/resources/extensions/gsd/tests/read-uat-gate-verdict.test.ts +54 -0
  431. package/src/resources/extensions/gsd/tests/reassess-handler.test.ts +49 -1
  432. package/src/resources/extensions/gsd/tests/reopen-slice.test.ts +52 -0
  433. package/src/resources/extensions/gsd/tests/rule-registry.test.ts +95 -1
  434. package/src/resources/extensions/gsd/tests/runtime-invariant-modules.test.ts +20 -0
  435. package/src/resources/extensions/gsd/tests/sibling-model-fallbacks.test.ts +189 -0
  436. package/src/resources/extensions/gsd/tests/single-field-model-thinking.test.ts +156 -0
  437. package/src/resources/extensions/gsd/tests/skill-discovery.test.ts +46 -0
  438. package/src/resources/extensions/gsd/tests/skipped-validation-db-atomicity.test.ts +6 -1
  439. package/src/resources/extensions/gsd/tests/stale-worktree-cwd.test.ts +3 -5
  440. package/src/resources/extensions/gsd/tests/start-auto-detached.test.ts +32 -0
  441. package/src/resources/extensions/gsd/tests/stash-pop-gsd-conflict.test.ts +2 -1
  442. package/src/resources/extensions/gsd/tests/stash-queued-context-files.test.ts +2 -1
  443. package/src/resources/extensions/gsd/tests/steer-worktree-path.test.ts +1 -1
  444. package/src/resources/extensions/gsd/tests/supervisor-model-swap-inflight-guard.test.ts +181 -0
  445. package/src/resources/extensions/gsd/tests/supervisor-model-swap-thinking-clamp.test.ts +122 -0
  446. package/src/resources/extensions/gsd/tests/sync-worktree-skip-current.test.ts +1 -1
  447. package/src/resources/extensions/gsd/tests/system-flat-phase-layout.test.ts +33 -0
  448. package/src/resources/extensions/gsd/tests/teardown-chdir-failure-clears-registry.test.ts +4 -4
  449. package/src/resources/extensions/gsd/tests/teardown-cleanup-parity.test.ts +2 -1
  450. package/src/resources/extensions/gsd/tests/teardown-failure-clears-registry.test.ts +4 -4
  451. package/src/resources/extensions/gsd/tests/tool-call-loop-guard.test.ts +196 -0
  452. package/src/resources/extensions/gsd/tests/uat-dispatch.test.ts +211 -0
  453. package/src/resources/extensions/gsd/tests/uat-stuck-loop-orphaned-worktree.test.ts +1 -1
  454. package/src/resources/extensions/gsd/tests/unit-registry.test.ts +26 -1
  455. package/src/resources/extensions/gsd/tests/uok-gate-runner.test.ts +39 -0
  456. package/src/resources/extensions/gsd/tests/uok-kernel-path.test.ts +226 -2
  457. package/src/resources/extensions/gsd/tests/uok-model-policy.test.ts +6 -0
  458. package/src/resources/extensions/gsd/tests/workflow-projections.test.ts +213 -2
  459. package/src/resources/extensions/gsd/tests/worktree-db-integration.test.ts +1 -1
  460. package/src/resources/extensions/gsd/tests/worktree-db-respawn-truncation.test.ts +1 -1
  461. package/src/resources/extensions/gsd/tests/worktree-db-same-file.test.ts +1 -3
  462. package/src/resources/extensions/gsd/tests/worktree-expected-warnings.test.ts +1 -1
  463. package/src/resources/extensions/gsd/tests/worktree-git-pathspec.test.ts +1 -1
  464. package/src/resources/extensions/gsd/tests/worktree-main-branch.test.ts +1 -1
  465. package/src/resources/extensions/gsd/tests/worktree-preferences-sync.test.ts +1 -1
  466. package/src/resources/extensions/gsd/tests/worktree-reentry.test.ts +2 -1
  467. package/src/resources/extensions/gsd/tests/worktree-sync-milestones.test.ts +5 -2
  468. package/src/resources/extensions/gsd/tests/worktree-sync-overwrite-loop.test.ts +1 -1
  469. package/src/resources/extensions/gsd/tests/worktree-sync-tasks.test.ts +1 -1
  470. package/src/resources/extensions/gsd/tool-contract.ts +29 -0
  471. package/src/resources/extensions/gsd/tools/complete-milestone.ts +9 -5
  472. package/src/resources/extensions/gsd/tools/reassess-roadmap.ts +19 -8
  473. package/src/resources/extensions/gsd/tools/reopen-slice.ts +5 -0
  474. package/src/resources/extensions/gsd/tools/reopen-task.ts +13 -5
  475. package/src/resources/extensions/gsd/tools/validate-milestone.ts +13 -9
  476. package/src/resources/extensions/gsd/types.ts +23 -4
  477. package/src/resources/extensions/gsd/uat-dispatch.ts +176 -0
  478. package/src/resources/extensions/gsd/unit-registry.ts +16 -2
  479. package/src/resources/extensions/gsd/unmerged-milestone-guard.ts +1 -1
  480. package/src/resources/extensions/gsd/uok/audit-toggle.ts +32 -2
  481. package/src/resources/extensions/gsd/uok/audit.ts +2 -0
  482. package/src/resources/extensions/gsd/uok/gate-runner.ts +26 -36
  483. package/src/resources/extensions/gsd/uok/gitops.ts +21 -18
  484. package/src/resources/extensions/gsd/uok/kernel.ts +169 -48
  485. package/src/resources/extensions/gsd/uok/model-policy.ts +20 -17
  486. package/src/resources/extensions/gsd/validation-block-guard.ts +2 -1
  487. package/src/resources/extensions/gsd/workflow-event-ledger.ts +1 -1
  488. package/src/resources/extensions/gsd/workflow-logger.ts +1 -1
  489. package/src/resources/extensions/gsd/workflow-projections.ts +9 -24
  490. package/src/resources/extensions/gsd/workspace-git-preflight.ts +2 -2
  491. package/src/resources/extensions/gsd/workspace.ts +5 -21
  492. package/src/resources/extensions/gsd/worktree-command.ts +1 -1
  493. package/src/resources/extensions/gsd/worktree-lifecycle.ts +19 -15
  494. package/src/resources/extensions/gsd/worktree-reentry.ts +2 -1
  495. package/src/resources/extensions/shared/gsd-browser-cli.ts +29 -0
  496. package/src/resources/extensions/shared/interview-ui.ts +58 -11
  497. package/src/resources/extensions/shared/tests/interview-ui-border.test.ts +32 -0
  498. /package/dist/web/standalone/.next/static/{bCg3aYrFN1DKZr2dqgE7L → 6xYMOzxVhsQgryneJ5KRc}/_buildManifest.js +0 -0
  499. /package/dist/web/standalone/.next/static/{bCg3aYrFN1DKZr2dqgE7L → 6xYMOzxVhsQgryneJ5KRc}/_ssgManifest.js +0 -0
@@ -6,10 +6,10 @@ import assert from 'node:assert/strict';
6
6
  import { existsSync, mkdtempSync, mkdirSync, rmSync, readFileSync, writeFileSync } from 'node:fs';
7
7
  import { join } from 'node:path';
8
8
  import { tmpdir } from 'node:os';
9
- import { regenerateIfMissing, renderPlanContent, renderStateProjection } from '../workflow-projections.ts';
9
+ import { regenerateIfMissing, renderPlanContent, renderStateProjection, renderSummaryProjection } from '../workflow-projections.ts';
10
10
  import type { SliceRow, TaskRow } from '../gsd-db.ts';
11
11
  import { closeDatabase, insertMilestone, insertSlice, insertTask, openDatabase } from '../gsd-db.ts';
12
- import { clearPathCache, _clearGsdRootCache } from '../paths.ts';
12
+ import { clearPathCache, _clearGsdRootCache, normalizeRealPath, resolveMilestoneFile, resolveTaskFile } from '../paths.ts';
13
13
  import { invalidateStateCache } from '../state.ts';
14
14
  import { clearParseCache } from '../files.ts';
15
15
 
@@ -243,6 +243,217 @@ test('workflow-projections: regenerateIfMissing PLAN restores slice plan and tas
243
243
  }
244
244
  });
245
245
 
246
+ test('workflow-projections: regenerateIfMissing ROADMAP is idempotent for flat-phase roadmap projections', async () => {
247
+ const base = mkdtempSync(join(tmpdir(), 'gsd-projections-flat-roadmap-'));
248
+ const dbPath = join(base, '.gsd', 'gsd.db');
249
+ const phaseDir = join(base, '.gsd', 'phases', '01-milestone');
250
+ mkdirSync(phaseDir, { recursive: true });
251
+ openDatabase(dbPath);
252
+ clearParseCache();
253
+ clearPathCache();
254
+ _clearGsdRootCache();
255
+ invalidateStateCache();
256
+
257
+ try {
258
+ insertMilestone({ id: 'M001', title: 'Milestone', status: 'active', planning: { vision: 'Ship a layout-aware roadmap.' } });
259
+ insertSlice({
260
+ id: 'S01',
261
+ milestoneId: 'M001',
262
+ title: 'Flat slice',
263
+ status: 'pending',
264
+ demo: 'Roadmap exists at the flat-phase path.',
265
+ planning: { goal: 'Keep ROADMAP regeneration idempotent.' },
266
+ });
267
+
268
+ const roadmapPath = join(phaseDir, '01-ROADMAP.md');
269
+ writeFileSync(roadmapPath, '# existing flat roadmap\n');
270
+
271
+ const regenerated = await regenerateIfMissing(base, 'M001', 'S01', 'ROADMAP');
272
+
273
+ assert.equal(regenerated, false, 'existing flat-phase ROADMAP is detected without rewriting');
274
+ assert.equal(readFileSync(roadmapPath, 'utf-8'), '# existing flat roadmap\n');
275
+ assert.equal(normalizeRealPath(resolveMilestoneFile(base, 'M001', 'ROADMAP') ?? ''), normalizeRealPath(roadmapPath));
276
+ } finally {
277
+ closeDatabase();
278
+ rmSync(base, { recursive: true, force: true });
279
+ }
280
+ });
281
+
282
+ test('workflow-projections: regenerateIfMissing ROADMAP regenerates missing flat-phase roadmap projections', async () => {
283
+ const base = mkdtempSync(join(tmpdir(), 'gsd-projections-missing-roadmap-'));
284
+ const dbPath = join(base, '.gsd', 'gsd.db');
285
+ const phaseDir = join(base, '.gsd', 'phases', '01-milestone');
286
+ mkdirSync(phaseDir, { recursive: true });
287
+ openDatabase(dbPath);
288
+ clearParseCache();
289
+ clearPathCache();
290
+ _clearGsdRootCache();
291
+ invalidateStateCache();
292
+
293
+ try {
294
+ insertMilestone({ id: 'M001', title: 'Milestone', status: 'active', planning: { vision: 'Ship a layout-aware roadmap.' } });
295
+ insertSlice({
296
+ id: 'S01',
297
+ milestoneId: 'M001',
298
+ title: 'Flat slice',
299
+ status: 'pending',
300
+ demo: 'Roadmap regenerates at the flat-phase path.',
301
+ planning: { goal: 'Recover ROADMAP from DB.' },
302
+ });
303
+
304
+ const roadmapPath = join(phaseDir, '01-ROADMAP.md');
305
+ const legacyRoadmapPath = join(base, '.gsd', 'milestones', 'M001', 'M001-ROADMAP.md');
306
+ assert.ok(!existsSync(roadmapPath), 'precondition: flat-phase ROADMAP is absent');
307
+
308
+ const regenerated = await regenerateIfMissing(base, 'M001', 'S01', 'ROADMAP');
309
+
310
+ assert.equal(regenerated, true, 'missing flat-phase ROADMAP is regenerated');
311
+ assert.match(readFileSync(roadmapPath, 'utf-8'), /Ship a layout-aware roadmap/);
312
+ assert.equal(existsSync(legacyRoadmapPath), false, 'regeneration does not create a legacy ROADMAP path');
313
+ assert.equal(normalizeRealPath(resolveMilestoneFile(base, 'M001', 'ROADMAP') ?? ''), normalizeRealPath(roadmapPath));
314
+ } finally {
315
+ closeDatabase();
316
+ rmSync(base, { recursive: true, force: true });
317
+ }
318
+ });
319
+
320
+ test('workflow-projections: regenerateIfMissing SUMMARY is idempotent for flat-phase task summaries', async () => {
321
+ const base = mkdtempSync(join(tmpdir(), 'gsd-projections-flat-summary-'));
322
+ const dbPath = join(base, '.gsd', 'gsd.db');
323
+ const phaseDir = join(base, '.gsd', 'phases', '01-milestone');
324
+ mkdirSync(phaseDir, { recursive: true });
325
+ openDatabase(dbPath);
326
+ clearParseCache();
327
+ clearPathCache();
328
+ _clearGsdRootCache();
329
+ invalidateStateCache();
330
+
331
+ try {
332
+ insertMilestone({ id: 'M001', title: 'Milestone', status: 'active' });
333
+ insertSlice({
334
+ id: 'S01',
335
+ milestoneId: 'M001',
336
+ title: 'Flat slice',
337
+ status: 'complete',
338
+ demo: 'Summary regenerates once.',
339
+ planning: { goal: 'Recover flat-phase summaries from DB.' },
340
+ });
341
+ insertTask({
342
+ id: 'T01',
343
+ sliceId: 'S01',
344
+ milestoneId: 'M001',
345
+ title: 'Completed task',
346
+ status: 'complete',
347
+ oneLiner: 'Completed the flat task.',
348
+ narrative: 'The task was completed through the DB-backed projection path.',
349
+ verificationResult: 'passed',
350
+ duration: '5m',
351
+ keyFiles: ['src/example.ts'],
352
+ keyDecisions: ['Use centralized task summary paths.'],
353
+ });
354
+
355
+ const summaryPath = join(phaseDir, 'T01-SUMMARY.md');
356
+ assert.ok(!existsSync(summaryPath), 'precondition: flat-phase task summary absent');
357
+
358
+ const first = await regenerateIfMissing(base, 'M001', 'S01', 'SUMMARY');
359
+ const second = await regenerateIfMissing(base, 'M001', 'S01', 'SUMMARY');
360
+
361
+ assert.equal(first, true, 'first call regenerates the missing task summary');
362
+ assert.equal(second, false, 'second call sees the flat-phase task summary and does not rewrite it');
363
+ assert.equal(normalizeRealPath(resolveTaskFile(base, 'M001', 'S01', 'T01', 'SUMMARY') ?? ''), normalizeRealPath(summaryPath));
364
+ assert.match(readFileSync(summaryPath, 'utf-8'), /# T01: Completed the flat task\./);
365
+ } finally {
366
+ closeDatabase();
367
+ rmSync(base, { recursive: true, force: true });
368
+ }
369
+ });
370
+
371
+ test('workflow-projections: flat-phase SUMMARY regeneration ignores stale nested task summaries', async () => {
372
+ const base = mkdtempSync(join(tmpdir(), 'gsd-projections-flat-stale-nested-'));
373
+ const dbPath = join(base, '.gsd', 'gsd.db');
374
+ const phaseDir = join(base, '.gsd', 'phases', '01-milestone');
375
+ const nestedTasksDir = join(phaseDir, 'tasks');
376
+ mkdirSync(nestedTasksDir, { recursive: true });
377
+ writeFileSync(join(nestedTasksDir, 'T01-SUMMARY.md'), '# stale nested summary\n');
378
+ openDatabase(dbPath);
379
+ clearParseCache();
380
+ clearPathCache();
381
+ _clearGsdRootCache();
382
+ invalidateStateCache();
383
+
384
+ try {
385
+ insertMilestone({ id: 'M001', title: 'Milestone', status: 'active' });
386
+ insertSlice({
387
+ id: 'S01',
388
+ milestoneId: 'M001',
389
+ title: 'Flat slice',
390
+ status: 'complete',
391
+ demo: 'Summary regenerates at phase root.',
392
+ planning: { goal: 'Recover canonical flat-phase summaries from DB.' },
393
+ });
394
+ insertTask({
395
+ id: 'T01',
396
+ sliceId: 'S01',
397
+ milestoneId: 'M001',
398
+ title: 'Completed task',
399
+ status: 'complete',
400
+ });
401
+
402
+ const rootSummaryPath = join(phaseDir, 'T01-SUMMARY.md');
403
+ assert.ok(!existsSync(rootSummaryPath), 'precondition: canonical flat-phase task summary absent');
404
+
405
+ const regenerated = await regenerateIfMissing(base, 'M001', 'S01', 'SUMMARY');
406
+
407
+ assert.equal(regenerated, true, 'missing phase-root summary is regenerated despite stale nested summary');
408
+ assert.equal(normalizeRealPath(resolveTaskFile(base, 'M001', 'S01', 'T01', 'SUMMARY') ?? ''), normalizeRealPath(rootSummaryPath));
409
+ assert.match(readFileSync(rootSummaryPath, 'utf-8'), /# T01: Completed task/);
410
+ assert.equal(readFileSync(join(nestedTasksDir, 'T01-SUMMARY.md'), 'utf-8'), '# stale nested summary\n');
411
+ } finally {
412
+ closeDatabase();
413
+ rmSync(base, { recursive: true, force: true });
414
+ }
415
+ });
416
+
417
+ test('workflow-projections: renderSummaryProjection uses milestone title when creating fresh flat-phase dirs', async () => {
418
+ const base = mkdtempSync(join(tmpdir(), 'gsd-projections-fresh-summary-'));
419
+ const dbPath = join(base, '.gsd', 'gsd.db');
420
+ mkdirSync(join(base, '.gsd'), { recursive: true });
421
+ openDatabase(dbPath);
422
+ clearParseCache();
423
+ clearPathCache();
424
+ _clearGsdRootCache();
425
+ invalidateStateCache();
426
+
427
+ try {
428
+ insertMilestone({ id: 'M001', title: 'Milestone', status: 'active' });
429
+ insertSlice({
430
+ id: 'S01',
431
+ milestoneId: 'M001',
432
+ title: 'Flat slice',
433
+ status: 'complete',
434
+ });
435
+ insertTask({
436
+ id: 'T01',
437
+ sliceId: 'S01',
438
+ milestoneId: 'M001',
439
+ title: 'Completed task',
440
+ status: 'complete',
441
+ });
442
+
443
+ const titleSummaryPath = join(base, '.gsd', 'phases', '01-milestone', 'T01-SUMMARY.md');
444
+ const idSummaryPath = join(base, '.gsd', 'phases', '01-m001', 'T01-SUMMARY.md');
445
+
446
+ renderSummaryProjection(base, 'M001', 'S01', 'T01');
447
+
448
+ assert.ok(existsSync(titleSummaryPath), 'fresh summary projection uses the milestone title slug');
449
+ assert.equal(existsSync(idSummaryPath), false, 'fresh summary projection does not create an id-slug orphan dir');
450
+ assert.equal(normalizeRealPath(resolveTaskFile(base, 'M001', 'S01', 'T01', 'SUMMARY') ?? ''), normalizeRealPath(titleSummaryPath));
451
+ } finally {
452
+ closeDatabase();
453
+ rmSync(base, { recursive: true, force: true });
454
+ }
455
+ });
456
+
246
457
  test('workflow-projections: renderStateProjection does not clobber non-empty STATE.md when manifest has milestones', async () => {
247
458
  const base = mkdtempSync(join(tmpdir(), 'gsd-projection-stale-'));
248
459
  const gsdDir = join(base, '.gsd');
@@ -17,7 +17,7 @@ import { join } from "node:path";
17
17
  import { tmpdir } from "node:os";
18
18
  import { execSync } from "node:child_process";
19
19
 
20
- import { createAutoWorktree } from "../auto-worktree.ts";
20
+ import { createAutoWorktree } from "../auto-worktree-creation.ts";
21
21
  import { worktreePath } from "../worktree-manager.ts";
22
22
  import {
23
23
  copyWorktreeDb,
@@ -17,7 +17,7 @@ import { mkdtempSync, mkdirSync, writeFileSync, rmSync, existsSync, readFileSync
17
17
  import { join } from 'node:path';
18
18
  import { tmpdir } from 'node:os';
19
19
 
20
- import { syncProjectRootToWorktree } from '../auto-worktree.ts';
20
+ import { syncProjectRootToWorktree } from '../auto-worktree-sync.ts';
21
21
  import { describe, test } from 'node:test';
22
22
  import assert from 'node:assert/strict';
23
23
 
@@ -18,9 +18,7 @@ import {
18
18
  reconcileWorktreeDb,
19
19
  insertDecision,
20
20
  } from "../gsd-db.ts";
21
- import {
22
- _shouldReconcileWorktreeDb,
23
- } from "../auto-worktree.ts";
21
+ import { _shouldReconcileWorktreeDb } from "../auto-worktree-sync.ts";
24
22
  import { isInfrastructureError } from "../auto/infra-errors.ts";
25
23
 
26
24
  describe("#2823: reconcileWorktreeDb same-file guard", () => {
@@ -6,7 +6,7 @@ import { mkdtempSync, mkdirSync, rmSync, writeFileSync } from "node:fs";
6
6
  import { join, resolve } from "node:path";
7
7
  import { tmpdir } from "node:os";
8
8
 
9
- import { _isExpectedWorktreeUnlinkError } from "../auto-worktree.ts";
9
+ import { _isExpectedWorktreeUnlinkError } from "../auto-worktree-path-utils.ts";
10
10
  import { resolveGitDir } from "../worktree-manager.ts";
11
11
 
12
12
  describe("worktree expected-condition warning suppression (#3665)", () => {
@@ -5,7 +5,7 @@ import { join } from "node:path";
5
5
  import { tmpdir } from "node:os";
6
6
  import { execFileSync } from "node:child_process";
7
7
 
8
- import { _gitPathspecForWorktreePath } from "../auto-worktree.ts";
8
+ import { _gitPathspecForWorktreePath } from "../auto-worktree-path-utils.ts";
9
9
 
10
10
  function run(cmd: string, args: string[], cwd: string): string {
11
11
  return execFileSync(cmd, args, { cwd, stdio: ["ignore", "pipe", "pipe"], encoding: "utf-8" }).trim();
@@ -3,7 +3,7 @@
3
3
  import { test } from "node:test";
4
4
  import assert from "node:assert/strict";
5
5
 
6
- import { _resolveAutoWorktreeStartPoint } from "../auto-worktree.ts";
6
+ import { _resolveAutoWorktreeStartPoint } from "../auto-worktree-branch-lifecycle.ts";
7
7
 
8
8
  test("auto-worktree start point prefers milestone integration branch", () => {
9
9
  const startPoint = _resolveAutoWorktreeStartPoint(
@@ -26,7 +26,7 @@ import { tmpdir } from "node:os";
26
26
  import {
27
27
  syncGsdStateToWorktree,
28
28
  syncWorktreeStateBack,
29
- } from "../auto-worktree.ts";
29
+ } from "../auto-worktree-sync.ts";
30
30
 
31
31
  // ─── Helpers ─────────────────────────────────────────────────────────
32
32
 
@@ -13,7 +13,8 @@ import { join } from "node:path";
13
13
  import { tmpdir } from "node:os";
14
14
  import { execFileSync } from "node:child_process";
15
15
 
16
- import { createAutoWorktree, _resetAutoWorktreeOriginalBaseForTests } from "../auto-worktree.ts";
16
+ import { createAutoWorktree } from "../auto-worktree-creation.ts";
17
+ import { _resetAutoWorktreeOriginalBaseForTests } from "../auto-worktree-session-registry.ts";
17
18
  import { reenterActiveWorktreeIfNeeded } from "../worktree-reentry.ts";
18
19
 
19
20
  // Safe: all inputs below are hardcoded test strings, not user input.
@@ -27,8 +27,11 @@ import { mkdtempSync, mkdirSync, writeFileSync, rmSync, existsSync, readFileSync
27
27
  import { join } from 'node:path';
28
28
  import { tmpdir } from 'node:os';
29
29
 
30
- import { syncProjectRootToWorktree } from '../auto-worktree.ts';
31
- import { syncGsdStateToWorktree, syncWorktreeStateBack } from '../auto-worktree.ts';
30
+ import {
31
+ syncGsdStateToWorktree,
32
+ syncProjectRootToWorktree,
33
+ syncWorktreeStateBack,
34
+ } from '../auto-worktree-sync.ts';
32
35
  import { describe, test } from 'node:test';
33
36
  import assert from 'node:assert/strict';
34
37
 
@@ -25,7 +25,7 @@ import {
25
25
  import { join } from "node:path";
26
26
  import { tmpdir } from "node:os";
27
27
 
28
- import { syncProjectRootToWorktree } from "../auto-worktree.ts";
28
+ import { syncProjectRootToWorktree } from "../auto-worktree-sync.ts";
29
29
 
30
30
  function createBase(name: string): string {
31
31
  const base = mkdtempSync(join(tmpdir(), `gsd-wt-1886-${name}-`));
@@ -18,7 +18,7 @@ import {
18
18
  import { join } from "node:path";
19
19
  import { tmpdir } from "node:os";
20
20
 
21
- import { syncWorktreeStateBack } from "../auto-worktree.ts";
21
+ import { syncWorktreeStateBack } from "../auto-worktree-sync.ts";
22
22
 
23
23
  function makeTempDir(prefix: string): string {
24
24
  return mkdtempSync(join(tmpdir(), `gsd-sync-test-${prefix}-`));
@@ -85,6 +85,18 @@ export interface UnitWorkflowDispatchReadinessInput {
85
85
  activeTools?: string[];
86
86
  }
87
87
 
88
+ export interface WorkflowDispatchModelContext {
89
+ provider?: string;
90
+ baseUrl?: string;
91
+ }
92
+
93
+ export interface UnitWorkflowDispatchReadinessForModelInput
94
+ extends Omit<UnitWorkflowDispatchReadinessInput, "provider" | "authMode" | "baseUrl"> {
95
+ model?: WorkflowDispatchModelContext | null;
96
+ fallbackModel?: WorkflowDispatchModelContext | null;
97
+ getProviderAuthMode?: (provider: string) => WorkflowCapabilityOptions["authMode"] | undefined;
98
+ }
99
+
88
100
  export function compileUnitContextContract(unitType: string): UnitContextContractResult {
89
101
  const manifest = resolveManifest(unitType);
90
102
  if (!manifest) {
@@ -115,6 +127,23 @@ export function getUnitWorkflowDispatchReadinessError(
115
127
  );
116
128
  }
117
129
 
130
+ export function getUnitWorkflowDispatchReadinessErrorForModel(
131
+ input: UnitWorkflowDispatchReadinessForModelInput,
132
+ ): string | null {
133
+ const provider = input.model?.provider ?? input.fallbackModel?.provider;
134
+ const baseUrl = input.model?.baseUrl ?? input.fallbackModel?.baseUrl;
135
+ return getUnitWorkflowDispatchReadinessError({
136
+ provider,
137
+ unitType: input.unitType,
138
+ projectRoot: input.projectRoot,
139
+ env: input.env,
140
+ surface: input.surface,
141
+ authMode: provider ? input.getProviderAuthMode?.(provider) : undefined,
142
+ baseUrl,
143
+ activeTools: input.activeTools,
144
+ });
145
+ }
146
+
118
147
  export function compileUnitToolContract(unitType: string): ToolContractResult {
119
148
  const manifest = resolveManifest(unitType);
120
149
  const surfaceContract = getUnitToolSurfaceContract(unitType);
@@ -10,7 +10,6 @@
10
10
  * for recovery, and invalidates caches.
11
11
  */
12
12
 
13
- import { join } from "node:path";
14
13
  import { existsSync } from "node:fs";
15
14
 
16
15
  import {
@@ -21,7 +20,7 @@ import {
21
20
  getLatestAssessmentByScope,
22
21
  updateMilestoneStatus,
23
22
  } from "../gsd-db.js";
24
- import { gsdProjectionRoot, clearPathCache, relMilestoneFile } from "../paths.js";
23
+ import { clearPathCache, resolveMilestoneFile, targetMilestoneFile } from "../paths.js";
25
24
  import { resolveCanonicalMilestoneRoot } from "../worktree-manager.js";
26
25
  import { isClosedStatus, isDeferredStatus } from "../status-guards.js";
27
26
  import { saveFile, clearParseCache } from "../files.js";
@@ -210,9 +209,14 @@ export async function handleCompleteMilestone(
210
209
  // ── Filesystem operations (outside transaction) ─────────────────────────
211
210
  const summaryMd = renderMilestoneSummaryMarkdown(params, completedAt);
212
211
 
213
- // Layout-aware: flat-phase → phases/NN-slug/NN-SUMMARY.md;
214
- // legacy milestones/MID/MID-SUMMARY.md.
215
- const summaryPath = join(artifactBasePath, relMilestoneFile(artifactBasePath, params.milestoneId, "SUMMARY"));
212
+ const summaryPath =
213
+ resolveMilestoneFile(artifactBasePath, params.milestoneId, "SUMMARY") ??
214
+ targetMilestoneFile(
215
+ artifactBasePath,
216
+ params.milestoneId,
217
+ "SUMMARY",
218
+ getMilestone(params.milestoneId)?.title,
219
+ );
216
220
 
217
221
  // Guard (#4598): if SUMMARY.md already exists on disk, do not overwrite it.
218
222
  // This handles re-dispatch scenarios (DB/disk state divergence) where a prior
@@ -1,6 +1,6 @@
1
- import { join } from "node:path";
2
1
  import { existsSync, unlinkSync } from "node:fs";
3
- import { relSliceFile, relMilestoneFile } from "../paths.js";
2
+ import { join } from "node:path";
3
+ import { relSliceFile, resolveMilestoneFile, resolveMilestonePath, targetMilestoneFile } from "../paths.js";
4
4
  import { clearParseCache } from "../files.js";
5
5
  import { isClosedStatus } from "../status-guards.js";
6
6
  import { isNonEmptyString } from "../validation.js";
@@ -290,12 +290,23 @@ export async function handleReassessRoadmap(
290
290
  params.sliceChanges.removed.length > 0;
291
291
 
292
292
  if (hasStructuralChanges) {
293
- // Layout-aware: flat-phase phases/NN-slug/NN-VALIDATION.md; legacy → milestones/MID/MID-VALIDATION.md
294
- const validationFile = join(basePath, relMilestoneFile(basePath, params.milestoneId, "VALIDATION"));
295
- try {
296
- if (existsSync(validationFile)) unlinkSync(validationFile);
297
- } catch (e) {
298
- logWarning("tool", `validation file cleanup failed: ${(e as Error).message}`);
293
+ const milestoneDir = resolveMilestonePath(basePath, params.milestoneId);
294
+ const validationFiles = new Set([
295
+ resolveMilestoneFile(basePath, params.milestoneId, "VALIDATION"),
296
+ targetMilestoneFile(
297
+ basePath,
298
+ params.milestoneId,
299
+ "VALIDATION",
300
+ getMilestone(params.milestoneId)?.title,
301
+ ),
302
+ milestoneDir ? join(milestoneDir, `${params.milestoneId}-VALIDATION.md`) : null,
303
+ ].filter((file): file is string => Boolean(file)));
304
+ for (const validationFile of validationFiles) {
305
+ try {
306
+ if (existsSync(validationFile)) unlinkSync(validationFile);
307
+ } catch (e) {
308
+ logWarning("tool", `validation file cleanup failed: ${(e as Error).message}`);
309
+ }
299
310
  }
300
311
  }
301
312
 
@@ -5,6 +5,11 @@
5
5
  * tasks back to "pending". This is intentional — if you're reopening a
6
6
  * slice, you're re-doing the work. Partial resets create ambiguous state.
7
7
  *
8
+ * Also recovers a desynced slice (#1205): when a UAT→planning fallback leaves
9
+ * the slice open (e.g. "pending") but its tasks still "complete", this clears
10
+ * that state so the planner can re-plan without hitting "already complete"
11
+ * rejections.
12
+ *
8
13
  * The parent milestone must still be open (not complete).
9
14
  */
10
15
 
@@ -24,8 +24,8 @@ import { writeManifest } from "../workflow-manifest.js";
24
24
  import { appendEvent } from "../workflow-events.js";
25
25
  import { logWarning } from "../workflow-logger.js";
26
26
  import { existsSync, unlinkSync } from "node:fs";
27
- import { join } from "node:path";
28
- import { resolveTasksDir, clearPathCache } from "../paths.js";
27
+ import { join, basename, dirname } from "node:path";
28
+ import { resolveTasksDir, resolveSlicePath, clearPathCache } from "../paths.js";
29
29
 
30
30
  export interface ReopenTaskParams {
31
31
  milestoneId: string;
@@ -106,10 +106,18 @@ export async function handleReopenTask(
106
106
  // ── Clean up stale filesystem artifacts (M12 fix) ────────────────────────
107
107
  // Without this, the DB-filesystem reconciler sees the SUMMARY.md and
108
108
  // auto-corrects the task back to "complete", making reopen a no-op (#3161).
109
+ // Legacy layout keeps the summary under a tasks/ subdir; flat-phase writes
110
+ // TID-SUMMARY.md directly in the phase dir. A tasks/ subdir may still exist
111
+ // in flat-phase for auxiliary artifacts — its mere existence must NOT redirect
112
+ // summary cleanup into tasks/ (#1208).
109
113
  try {
110
- const tasksDir = resolveTasksDir(basePath, params.milestoneId, params.sliceId);
111
- if (tasksDir) {
112
- const summaryPath = join(tasksDir, `${params.taskId}-SUMMARY.md`);
114
+ const slicePath = resolveSlicePath(basePath, params.milestoneId, params.sliceId);
115
+ if (slicePath) {
116
+ const isLegacySlice = basename(dirname(slicePath)) === "slices";
117
+ const summaryDir = isLegacySlice
118
+ ? (resolveTasksDir(basePath, params.milestoneId, params.sliceId) ?? slicePath)
119
+ : slicePath;
120
+ const summaryPath = join(summaryDir, `${params.taskId}-SUMMARY.md`);
113
121
  if (existsSync(summaryPath)) unlinkSync(summaryPath);
114
122
  }
115
123
  } catch (cleanupErr) {
@@ -12,15 +12,13 @@
12
12
  * despite passing validation.
13
13
  */
14
14
 
15
- import { join } from "node:path";
16
-
17
15
  import {
18
16
  transaction,
19
17
  insertAssessment,
20
18
  getMilestoneSlices,
21
19
  getMilestone,
22
20
  } from "../gsd-db.js";
23
- import { gsdProjectionRoot, clearPathCache, relMilestoneFile } from "../paths.js";
21
+ import { clearPathCache, targetMilestoneFile } from "../paths.js";
24
22
  import { resolveCanonicalMilestoneRoot } from "../worktree-manager.js";
25
23
  import { resolveWorktreeProjectRoot } from "../worktree-root.js";
26
24
  import { saveFile, clearParseCache } from "../files.js";
@@ -160,11 +158,12 @@ export async function handleValidateMilestone(
160
158
  // worktree exists for this milestone, validation reads/writes the
161
159
  // worktree's artifacts instead of stale project-root state.
162
160
  const validationMd = renderValidationMarkdown(effectiveParams);
163
- // Layout-aware: flat-phase → phases/NN-slug/NN-VALIDATION.md;
164
- // legacy → milestones/MID/MID-VALIDATION.md.
165
- // join(artifactBasePath, relMilestoneFile) gives the absolute path; relMilestoneFile
166
- // returns ".gsd/..."-relative so joining with basePath (project/worktree root) is correct.
167
- const validationPath = join(artifactBasePath, relMilestoneFile(artifactBasePath, effectiveParams.milestoneId, "VALIDATION"));
161
+ const validationPath = targetMilestoneFile(
162
+ artifactBasePath,
163
+ effectiveParams.milestoneId,
164
+ "VALIDATION",
165
+ getMilestone(effectiveParams.milestoneId)?.title,
166
+ );
168
167
 
169
168
  // ── DB write first — matches complete-task/complete-slice pattern ───
170
169
  // Write DB before disk so a crash between the two leaves a recoverable
@@ -204,7 +203,12 @@ export async function handleValidateMilestone(
204
203
  const projectRoot = resolveWorktreeProjectRoot(basePath);
205
204
  if (projectRoot !== artifactBasePath) {
206
205
  // Mirror to project root using the project root's layout (same logic as above).
207
- const projectValidationPath = join(projectRoot, relMilestoneFile(projectRoot, effectiveParams.milestoneId, "VALIDATION"));
206
+ const projectValidationPath = targetMilestoneFile(
207
+ projectRoot,
208
+ effectiveParams.milestoneId,
209
+ "VALIDATION",
210
+ getMilestone(effectiveParams.milestoneId)?.title,
211
+ );
208
212
  try {
209
213
  await saveFile(projectValidationPath, validationMd);
210
214
  } catch (mirrorErr) {
@@ -2,6 +2,11 @@
2
2
  // Types consumed by state derivation, file parsing, and status display.
3
3
  // Pure interfaces — no logic, no runtime dependencies.
4
4
 
5
+ // Type-only import (erased at compile time — no runtime dependency): sibling
6
+ // single-model fields share the phase-bucket object form so they honor
7
+ // `fallbacks[]` (#1229).
8
+ import type { GSDPhaseModelConfig } from "./preferences-types.js";
9
+
5
10
  // ─── Enums & Literal Unions ────────────────────────────────────────────────
6
11
 
7
12
  export type RiskLevel = "low" | "medium" | "high";
@@ -303,8 +308,13 @@ export interface PostUnitHookConfig {
303
308
  prompt: string;
304
309
  /** Max times this hook can fire for the same trigger unit. Default 1, max 10. */
305
310
  max_cycles?: number;
306
- /** Model override for hook sessions. */
307
- model?: string;
311
+ /**
312
+ * Model override for hook sessions. Accepts a bare model ID or the extended
313
+ * `{ model, provider?, fallbacks? }` object form so a transient trip of the
314
+ * primary provider falls back to the next entry instead of hard-failing the
315
+ * hook (#1229).
316
+ */
317
+ model?: string | GSDPhaseModelConfig;
308
318
  /** Expected output file name (relative to task/slice dir). Used for idempotency — skip if exists. */
309
319
  artifact?: string;
310
320
  /** Whether the hook is advisory or blocks unit advancement. Default advisory. */
@@ -505,6 +515,11 @@ export interface PreDispatchResult {
505
515
  export interface PersistedHookState {
506
516
  /** Cycle counts keyed as "hookName/triggerUnitType/triggerUnitId". */
507
517
  cycleCounts: Record<string, number>;
518
+ /**
519
+ * Cycle keys already granted a one-shot re-dispatch after a lost/interrupted
520
+ * dispatch, so the refund is bounded to one per gate across resumes.
521
+ */
522
+ redispatchedGateKeys?: string[];
508
523
  /** In-flight hook, persisted so blocking gates cannot be skipped after resume. */
509
524
  activeHook?: HookExecutionState | null;
510
525
  /** Remaining hook queue by hook name and trigger unit. */
@@ -607,8 +622,12 @@ export interface ReactiveExecutionConfig {
607
622
  max_parallel: number;
608
623
  /** Isolation mode for parallel tasks within a slice. Currently only "same-tree" is supported. */
609
624
  isolation_mode: "same-tree";
610
- /** Optional model override for subagents spawned during parallel execution. */
611
- subagent_model?: string;
625
+ /**
626
+ * Optional model override for subagents spawned during parallel execution.
627
+ * Accepts a bare model ID or the extended `{ model, provider?, fallbacks? }`
628
+ * object form for parity with phase buckets (#1229).
629
+ */
630
+ subagent_model?: string | GSDPhaseModelConfig;
612
631
  }
613
632
 
614
633
  /** Per-slice reactive execution runtime state, persisted to disk. */