gsd-pi 2.65.0-dev.5c8557b → 2.65.0-dev.d0517ff

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 (316) hide show
  1. package/dist/mcp-server.js +6 -2
  2. package/dist/resources/extensions/browser-tools/capture.js +20 -1
  3. package/dist/resources/extensions/browser-tools/tests/capture-sharp-optional.test.cjs +93 -0
  4. package/dist/resources/extensions/gsd/auto/run-unit.js +13 -2
  5. package/dist/resources/extensions/gsd/auto/session.js +4 -0
  6. package/dist/resources/extensions/gsd/auto-dispatch.js +99 -9
  7. package/dist/resources/extensions/gsd/auto-model-selection.js +7 -5
  8. package/dist/resources/extensions/gsd/auto-post-unit.js +17 -6
  9. package/dist/resources/extensions/gsd/auto-prompts.js +24 -0
  10. package/dist/resources/extensions/gsd/auto-recovery.js +40 -22
  11. package/dist/resources/extensions/gsd/auto-start.js +42 -11
  12. package/dist/resources/extensions/gsd/auto-tool-tracking.js +10 -0
  13. package/dist/resources/extensions/gsd/auto-worktree.js +29 -7
  14. package/dist/resources/extensions/gsd/auto.js +21 -15
  15. package/dist/resources/extensions/gsd/bootstrap/agent-end-recovery.js +17 -4
  16. package/dist/resources/extensions/gsd/bootstrap/db-tools.js +10 -0
  17. package/dist/resources/extensions/gsd/bootstrap/query-tools.js +6 -4
  18. package/dist/resources/extensions/gsd/bootstrap/register-extension.js +5 -1
  19. package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +11 -3
  20. package/dist/resources/extensions/gsd/bootstrap/write-gate.js +31 -1
  21. package/dist/resources/extensions/gsd/commands/context.js +8 -1
  22. package/dist/resources/extensions/gsd/commands/handlers/core.js +20 -0
  23. package/dist/resources/extensions/gsd/commands-extensions.js +1 -1
  24. package/dist/resources/extensions/gsd/config-overlay.js +312 -0
  25. package/dist/resources/extensions/gsd/db-writer.js +13 -3
  26. package/dist/resources/extensions/gsd/detection.js +1 -1
  27. package/dist/resources/extensions/gsd/dispatch-guard.js +2 -1
  28. package/dist/resources/extensions/gsd/docs/preferences-reference.md +1 -0
  29. package/dist/resources/extensions/gsd/doctor.js +2 -1
  30. package/dist/resources/extensions/gsd/gitignore.js +1 -0
  31. package/dist/resources/extensions/gsd/gsd-db.js +47 -4
  32. package/dist/resources/extensions/gsd/guided-flow.js +220 -29
  33. package/dist/resources/extensions/gsd/index.js +1 -1
  34. package/dist/resources/extensions/gsd/json-persistence.js +5 -2
  35. package/dist/resources/extensions/gsd/md-importer.js +14 -7
  36. package/dist/resources/extensions/gsd/parallel-orchestrator.js +17 -11
  37. package/dist/resources/extensions/gsd/pre-execution-checks.js +12 -5
  38. package/dist/resources/extensions/gsd/preferences-types.js +3 -0
  39. package/dist/resources/extensions/gsd/preferences-validation.js +45 -1
  40. package/dist/resources/extensions/gsd/preferences.js +9 -2
  41. package/dist/resources/extensions/gsd/preparation.js +1092 -0
  42. package/dist/resources/extensions/gsd/prompt-validation.js +67 -0
  43. package/dist/resources/extensions/gsd/prompts/complete-milestone.md +3 -3
  44. package/dist/resources/extensions/gsd/prompts/complete-slice.md +1 -1
  45. package/dist/resources/extensions/gsd/prompts/discuss-prepared.md +424 -0
  46. package/dist/resources/extensions/gsd/prompts/discuss.md +2 -0
  47. package/dist/resources/extensions/gsd/prompts/guided-discuss-milestone.md +6 -1
  48. package/dist/resources/extensions/gsd/prompts/guided-discuss-slice.md +5 -4
  49. package/dist/resources/extensions/gsd/prompts/parallel-research-slices.md +23 -0
  50. package/dist/resources/extensions/gsd/prompts/queue.md +2 -0
  51. package/dist/resources/extensions/gsd/prompts/rethink.md +2 -1
  52. package/dist/resources/extensions/gsd/prompts/validate-milestone.md +56 -23
  53. package/dist/resources/extensions/gsd/quick.js +19 -15
  54. package/dist/resources/extensions/gsd/reactive-graph.js +12 -0
  55. package/dist/resources/extensions/gsd/roadmap-slices.js +24 -5
  56. package/dist/resources/extensions/gsd/safety/content-validator.js +3 -3
  57. package/dist/resources/extensions/gsd/session-lock.js +23 -1
  58. package/dist/resources/extensions/gsd/state.js +115 -28
  59. package/dist/resources/extensions/gsd/templates/context-enhanced.md +138 -0
  60. package/dist/resources/extensions/gsd/tools/complete-milestone.js +15 -3
  61. package/dist/resources/extensions/gsd/tools/complete-slice.js +27 -6
  62. package/dist/resources/extensions/gsd/tools/complete-task.js +31 -7
  63. package/dist/resources/extensions/gsd/tools/plan-milestone.js +7 -5
  64. package/dist/resources/extensions/gsd/tools/reassess-roadmap.js +5 -2
  65. package/dist/resources/extensions/gsd/tools/reopen-milestone.js +119 -0
  66. package/dist/resources/extensions/gsd/tools/reopen-slice.js +30 -0
  67. package/dist/resources/extensions/gsd/tools/reopen-task.js +18 -0
  68. package/dist/resources/extensions/gsd/triage-resolution.js +33 -16
  69. package/dist/resources/extensions/gsd/undo.js +3 -2
  70. package/dist/resources/extensions/gsd/workflow-events.js +1 -0
  71. package/dist/resources/extensions/gsd/workflow-logger.js +1 -1
  72. package/dist/resources/extensions/gsd/workflow-projections.js +7 -9
  73. package/dist/resources/extensions/gsd/workflow-reconcile.js +100 -9
  74. package/dist/resources/extensions/gsd/workflow-templates.js +11 -2
  75. package/dist/resources/extensions/gsd/worktree-manager.js +5 -2
  76. package/dist/resources/extensions/gsd/worktree.js +9 -0
  77. package/dist/resources/extensions/shared/interview-ui.js +1 -1
  78. package/dist/web/standalone/.next/BUILD_ID +1 -1
  79. package/dist/web/standalone/.next/app-path-routes-manifest.json +15 -15
  80. package/dist/web/standalone/.next/build-manifest.json +3 -3
  81. package/dist/web/standalone/.next/prerender-manifest.json +3 -3
  82. package/dist/web/standalone/.next/react-loadable-manifest.json +1 -1
  83. package/dist/web/standalone/.next/server/app/_global-error.html +2 -2
  84. package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
  85. package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  86. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
  87. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
  88. package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  89. package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  90. package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  91. package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
  92. package/dist/web/standalone/.next/server/app/_not-found.rsc +1 -1
  93. package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
  94. package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  95. package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +1 -1
  96. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  97. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  98. package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
  99. package/dist/web/standalone/.next/server/app/index.html +1 -1
  100. package/dist/web/standalone/.next/server/app/index.rsc +1 -1
  101. package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +1 -1
  102. package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +1 -1
  103. package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
  104. package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +1 -1
  105. package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
  106. package/dist/web/standalone/.next/server/app-paths-manifest.json +15 -15
  107. package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
  108. package/dist/web/standalone/.next/server/middleware-react-loadable-manifest.js +1 -1
  109. package/dist/web/standalone/.next/server/pages/404.html +1 -1
  110. package/dist/web/standalone/.next/server/pages/500.html +2 -2
  111. package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
  112. package/dist/web/standalone/.next/static/chunks/6502.8874bcae249c02e1.js +9 -0
  113. package/dist/web/standalone/.next/static/chunks/{webpack-a1c1e452c6b32d04.js → webpack-9fed74684e1c5bb1.js} +1 -1
  114. package/package.json +1 -1
  115. package/packages/pi-coding-agent/dist/core/retry-handler.d.ts.map +1 -1
  116. package/packages/pi-coding-agent/dist/core/retry-handler.js +30 -19
  117. package/packages/pi-coding-agent/dist/core/retry-handler.js.map +1 -1
  118. package/packages/pi-coding-agent/dist/core/retry-handler.test.js +51 -0
  119. package/packages/pi-coding-agent/dist/core/retry-handler.test.js.map +1 -1
  120. package/packages/pi-coding-agent/dist/core/sdk.js +9 -9
  121. package/packages/pi-coding-agent/dist/core/sdk.js.map +1 -1
  122. package/packages/pi-coding-agent/dist/modes/interactive/components/provider-manager.d.ts +2 -1
  123. package/packages/pi-coding-agent/dist/modes/interactive/components/provider-manager.d.ts.map +1 -1
  124. package/packages/pi-coding-agent/dist/modes/interactive/components/provider-manager.js +10 -1
  125. package/packages/pi-coding-agent/dist/modes/interactive/components/provider-manager.js.map +1 -1
  126. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.d.ts +1 -0
  127. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
  128. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.js +20 -5
  129. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.js.map +1 -1
  130. package/packages/pi-coding-agent/dist/modes/interactive/controllers/input-controller.js +15 -1
  131. package/packages/pi-coding-agent/dist/modes/interactive/controllers/input-controller.js.map +1 -1
  132. package/packages/pi-coding-agent/dist/modes/interactive/controllers/input-controller.test.js +18 -0
  133. package/packages/pi-coding-agent/dist/modes/interactive/controllers/input-controller.test.js.map +1 -1
  134. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  135. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js +4 -0
  136. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js.map +1 -1
  137. package/packages/pi-coding-agent/src/core/retry-handler.test.ts +80 -0
  138. package/packages/pi-coding-agent/src/core/retry-handler.ts +37 -25
  139. package/packages/pi-coding-agent/src/core/sdk.ts +9 -9
  140. package/packages/pi-coding-agent/src/modes/interactive/components/provider-manager.ts +10 -0
  141. package/packages/pi-coding-agent/src/modes/interactive/components/tool-execution.ts +20 -4
  142. package/packages/pi-coding-agent/src/modes/interactive/controllers/input-controller.test.ts +27 -0
  143. package/packages/pi-coding-agent/src/modes/interactive/controllers/input-controller.ts +16 -1
  144. package/packages/pi-coding-agent/src/modes/interactive/interactive-mode.ts +5 -0
  145. package/packages/pi-tui/dist/components/image.d.ts +2 -0
  146. package/packages/pi-tui/dist/components/image.d.ts.map +1 -1
  147. package/packages/pi-tui/dist/components/image.js +4 -0
  148. package/packages/pi-tui/dist/components/image.js.map +1 -1
  149. package/packages/pi-tui/dist/components/image.test.d.ts +6 -0
  150. package/packages/pi-tui/dist/components/image.test.d.ts.map +1 -0
  151. package/packages/pi-tui/dist/components/image.test.js +32 -0
  152. package/packages/pi-tui/dist/components/image.test.js.map +1 -0
  153. package/packages/pi-tui/src/components/image.test.ts +36 -0
  154. package/packages/pi-tui/src/components/image.ts +5 -0
  155. package/src/resources/extensions/browser-tools/capture.ts +19 -1
  156. package/src/resources/extensions/browser-tools/tests/capture-sharp-optional.test.cjs +93 -0
  157. package/src/resources/extensions/gsd/auto/run-unit.ts +12 -2
  158. package/src/resources/extensions/gsd/auto/session.ts +4 -0
  159. package/src/resources/extensions/gsd/auto-dispatch.ts +110 -9
  160. package/src/resources/extensions/gsd/auto-model-selection.ts +7 -5
  161. package/src/resources/extensions/gsd/auto-post-unit.ts +16 -6
  162. package/src/resources/extensions/gsd/auto-prompts.ts +31 -0
  163. package/src/resources/extensions/gsd/auto-recovery.ts +29 -23
  164. package/src/resources/extensions/gsd/auto-start.ts +45 -10
  165. package/src/resources/extensions/gsd/auto-tool-tracking.ts +10 -0
  166. package/src/resources/extensions/gsd/auto-worktree.ts +28 -7
  167. package/src/resources/extensions/gsd/auto.ts +19 -8
  168. package/src/resources/extensions/gsd/bootstrap/agent-end-recovery.ts +16 -4
  169. package/src/resources/extensions/gsd/bootstrap/db-tools.ts +10 -0
  170. package/src/resources/extensions/gsd/bootstrap/query-tools.ts +5 -4
  171. package/src/resources/extensions/gsd/bootstrap/register-extension.ts +4 -1
  172. package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +11 -3
  173. package/src/resources/extensions/gsd/bootstrap/write-gate.ts +36 -1
  174. package/src/resources/extensions/gsd/commands/context.ts +7 -1
  175. package/src/resources/extensions/gsd/commands/handlers/core.ts +23 -0
  176. package/src/resources/extensions/gsd/commands-extensions.ts +1 -1
  177. package/src/resources/extensions/gsd/config-overlay.ts +331 -0
  178. package/src/resources/extensions/gsd/db-writer.ts +11 -3
  179. package/src/resources/extensions/gsd/detection.ts +1 -1
  180. package/src/resources/extensions/gsd/dispatch-guard.ts +2 -1
  181. package/src/resources/extensions/gsd/docs/preferences-reference.md +1 -0
  182. package/src/resources/extensions/gsd/doctor.ts +2 -1
  183. package/src/resources/extensions/gsd/gitignore.ts +1 -0
  184. package/src/resources/extensions/gsd/gsd-db.ts +46 -4
  185. package/src/resources/extensions/gsd/guided-flow.ts +254 -30
  186. package/src/resources/extensions/gsd/index.ts +1 -0
  187. package/src/resources/extensions/gsd/json-persistence.ts +6 -3
  188. package/src/resources/extensions/gsd/md-importer.ts +13 -6
  189. package/src/resources/extensions/gsd/parallel-orchestrator.ts +19 -11
  190. package/src/resources/extensions/gsd/pre-execution-checks.ts +15 -7
  191. package/src/resources/extensions/gsd/preferences-types.ts +25 -0
  192. package/src/resources/extensions/gsd/preferences-validation.ts +45 -1
  193. package/src/resources/extensions/gsd/preferences.ts +9 -2
  194. package/src/resources/extensions/gsd/preparation.ts +1419 -0
  195. package/src/resources/extensions/gsd/prompt-validation.ts +88 -0
  196. package/src/resources/extensions/gsd/prompts/complete-milestone.md +3 -3
  197. package/src/resources/extensions/gsd/prompts/complete-slice.md +1 -1
  198. package/src/resources/extensions/gsd/prompts/discuss-prepared.md +424 -0
  199. package/src/resources/extensions/gsd/prompts/discuss.md +2 -0
  200. package/src/resources/extensions/gsd/prompts/guided-discuss-milestone.md +6 -1
  201. package/src/resources/extensions/gsd/prompts/guided-discuss-slice.md +5 -4
  202. package/src/resources/extensions/gsd/prompts/parallel-research-slices.md +23 -0
  203. package/src/resources/extensions/gsd/prompts/queue.md +2 -0
  204. package/src/resources/extensions/gsd/prompts/rethink.md +2 -1
  205. package/src/resources/extensions/gsd/prompts/validate-milestone.md +56 -23
  206. package/src/resources/extensions/gsd/quick.ts +20 -15
  207. package/src/resources/extensions/gsd/reactive-graph.ts +18 -0
  208. package/src/resources/extensions/gsd/roadmap-slices.ts +21 -5
  209. package/src/resources/extensions/gsd/safety/content-validator.ts +3 -3
  210. package/src/resources/extensions/gsd/session-lock.ts +17 -1
  211. package/src/resources/extensions/gsd/state.ts +115 -26
  212. package/src/resources/extensions/gsd/templates/context-enhanced.md +138 -0
  213. package/src/resources/extensions/gsd/tests/adversarial-review-fixes.test.ts +223 -0
  214. package/src/resources/extensions/gsd/tests/auto-model-selection.test.ts +33 -2
  215. package/src/resources/extensions/gsd/tests/auto-remediate-slice-status.test.ts +56 -0
  216. package/src/resources/extensions/gsd/tests/clear-stale-autostart.test.ts +41 -0
  217. package/src/resources/extensions/gsd/tests/complete-slice-verification-gate.test.ts +72 -0
  218. package/src/resources/extensions/gsd/tests/complete-task-normalize-lists.test.ts +54 -0
  219. package/src/resources/extensions/gsd/tests/defer-milestone-stamp.test.ts +30 -0
  220. package/src/resources/extensions/gsd/tests/derive-state-db.test.ts +4 -3
  221. package/src/resources/extensions/gsd/tests/discuss-incremental-persistence.test.ts +36 -0
  222. package/src/resources/extensions/gsd/tests/discuss-slice-structured-questions.test.ts +46 -0
  223. package/src/resources/extensions/gsd/tests/dispatch-guard-closed-status.test.ts +33 -0
  224. package/src/resources/extensions/gsd/tests/dispatcher-stuck-planning.test.ts +37 -0
  225. package/src/resources/extensions/gsd/tests/error-success-mask.test.ts +37 -0
  226. package/src/resources/extensions/gsd/tests/find-missing-summaries-closed.test.ts +48 -0
  227. package/src/resources/extensions/gsd/tests/frontmatter-parse-noise.test.ts +42 -0
  228. package/src/resources/extensions/gsd/tests/gitignore-bg-shell.test.ts +38 -0
  229. package/src/resources/extensions/gsd/tests/guided-flow-state-rebuild.test.ts +103 -0
  230. package/src/resources/extensions/gsd/tests/import-done-milestones.test.ts +42 -0
  231. package/src/resources/extensions/gsd/tests/integration/auto-recovery.test.ts +11 -9
  232. package/src/resources/extensions/gsd/tests/integration/state-machine-edge-cases.test.ts +4 -2
  233. package/src/resources/extensions/gsd/tests/integration/state-machine-live-validation.test.ts +28 -30
  234. package/src/resources/extensions/gsd/tests/integration/test-isolation.ts +53 -0
  235. package/src/resources/extensions/gsd/tests/integration-prepared-discussion.test.ts +525 -0
  236. package/src/resources/extensions/gsd/tests/isolation-none-branch-guard.test.ts +62 -0
  237. package/src/resources/extensions/gsd/tests/needs-remediation-revalidation.test.ts +48 -0
  238. package/src/resources/extensions/gsd/tests/note-captures-executed.test.ts +46 -0
  239. package/src/resources/extensions/gsd/tests/parallel-research-dispatch.test.ts +77 -0
  240. package/src/resources/extensions/gsd/tests/phantom-ghost-detection.test.ts +55 -0
  241. package/src/resources/extensions/gsd/tests/phantom-milestone-default-queued.test.ts +39 -0
  242. package/src/resources/extensions/gsd/tests/pre-exec-backtick-strip.test.ts +68 -0
  243. package/src/resources/extensions/gsd/tests/pre-execution-checks.test.ts +218 -20
  244. package/src/resources/extensions/gsd/tests/pre-execution-fail-closed.test.ts +2 -2
  245. package/src/resources/extensions/gsd/tests/pre-execution-pause-wiring.test.ts +2 -2
  246. package/src/resources/extensions/gsd/tests/preparation.test.ts +1211 -0
  247. package/src/resources/extensions/gsd/tests/project-root-cwd-crash.test.ts +53 -0
  248. package/src/resources/extensions/gsd/tests/projection-no-plan-overwrite.test.ts +83 -0
  249. package/src/resources/extensions/gsd/tests/prompt-builder.test.ts +669 -0
  250. package/src/resources/extensions/gsd/tests/prompt-contracts.test.ts +7 -4
  251. package/src/resources/extensions/gsd/tests/prompt-step-ordering.test.ts +85 -0
  252. package/src/resources/extensions/gsd/tests/provider-errors.test.ts +2 -1
  253. package/src/resources/extensions/gsd/tests/query-tools-db-open.test.ts +47 -0
  254. package/src/resources/extensions/gsd/tests/queued-discuss-fast-path.test.ts +107 -0
  255. package/src/resources/extensions/gsd/tests/reactive-graph.test.ts +45 -0
  256. package/src/resources/extensions/gsd/tests/restore-tools-after-discuss.test.ts +63 -0
  257. package/src/resources/extensions/gsd/tests/rogue-file-detection.test.ts +4 -5
  258. package/src/resources/extensions/gsd/tests/run-uat-replay-cap.test.ts +51 -0
  259. package/src/resources/extensions/gsd/tests/show-config-command.test.ts +56 -0
  260. package/src/resources/extensions/gsd/tests/skip-slice-state-rebuild.test.ts +31 -0
  261. package/src/resources/extensions/gsd/tests/skipped-validation-completion.test.ts +39 -0
  262. package/src/resources/extensions/gsd/tests/slice-sequence-insert.test.ts +51 -0
  263. package/src/resources/extensions/gsd/tests/smart-entry-complete.test.ts +1 -1
  264. package/src/resources/extensions/gsd/tests/stale-lockfile-recovery.test.ts +36 -0
  265. package/src/resources/extensions/gsd/tests/stale-queued-milestone.test.ts +147 -0
  266. package/src/resources/extensions/gsd/tests/stale-worktree-cwd.test.ts +13 -0
  267. package/src/resources/extensions/gsd/tests/stash-pop-gsd-conflict.test.ts +21 -0
  268. package/src/resources/extensions/gsd/tests/stash-queued-context-files.test.ts +21 -0
  269. package/src/resources/extensions/gsd/tests/state-machine-full-walkthrough.test.ts +6 -7
  270. package/src/resources/extensions/gsd/tests/status-db-open.test.ts +47 -0
  271. package/src/resources/extensions/gsd/tests/stuck-detection-coverage.test.ts +1 -0
  272. package/src/resources/extensions/gsd/tests/symlink-extension-discovery.test.ts +125 -0
  273. package/src/resources/extensions/gsd/tests/sync-worktree-skip-current.test.ts +65 -0
  274. package/src/resources/extensions/gsd/tests/tool-invocation-error-loop-break.test.ts +29 -1
  275. package/src/resources/extensions/gsd/tests/triage-resolution.test.ts +2 -1
  276. package/src/resources/extensions/gsd/tests/validate-milestone.test.ts +3 -4
  277. package/src/resources/extensions/gsd/tests/verification-operational-gate.test.ts +15 -0
  278. package/src/resources/extensions/gsd/tests/verify-artifact-tightened.test.ts +89 -0
  279. package/src/resources/extensions/gsd/tests/wave1-critical-regressions.test.ts +49 -0
  280. package/src/resources/extensions/gsd/tests/wave2-events-regressions.test.ts +48 -0
  281. package/src/resources/extensions/gsd/tests/wave3-session-regressions.test.ts +47 -0
  282. package/src/resources/extensions/gsd/tests/wave4-write-safety-regressions.test.ts +70 -0
  283. package/src/resources/extensions/gsd/tests/wave5-consistency-regressions.test.ts +165 -0
  284. package/src/resources/extensions/gsd/tests/worker-model-override.test.ts +48 -0
  285. package/src/resources/extensions/gsd/tests/workflow-logger-audit.test.ts +6 -3
  286. package/src/resources/extensions/gsd/tests/worktree-expected-warnings.test.ts +38 -0
  287. package/src/resources/extensions/gsd/tests/worktree-integration.test.ts +16 -0
  288. package/src/resources/extensions/gsd/tests/worktree-main-branch.test.ts +20 -0
  289. package/src/resources/extensions/gsd/tests/worktree-sync-milestones.test.ts +16 -17
  290. package/src/resources/extensions/gsd/tests/worktree-sync-tasks.test.ts +13 -9
  291. package/src/resources/extensions/gsd/tests/worktree.test.ts +26 -9
  292. package/src/resources/extensions/gsd/tests/write-gate.test.ts +127 -2
  293. package/src/resources/extensions/gsd/tests/zero-slice-roadmap-guided.test.ts +19 -0
  294. package/src/resources/extensions/gsd/tools/complete-milestone.ts +13 -3
  295. package/src/resources/extensions/gsd/tools/complete-slice.ts +26 -6
  296. package/src/resources/extensions/gsd/tools/complete-task.ts +29 -7
  297. package/src/resources/extensions/gsd/tools/plan-milestone.ts +11 -9
  298. package/src/resources/extensions/gsd/tools/reassess-roadmap.ts +5 -2
  299. package/src/resources/extensions/gsd/tools/reopen-milestone.ts +152 -0
  300. package/src/resources/extensions/gsd/tools/reopen-slice.ts +27 -0
  301. package/src/resources/extensions/gsd/tools/reopen-task.ts +17 -0
  302. package/src/resources/extensions/gsd/triage-resolution.ts +37 -17
  303. package/src/resources/extensions/gsd/types.ts +4 -0
  304. package/src/resources/extensions/gsd/undo.ts +3 -2
  305. package/src/resources/extensions/gsd/workflow-events.ts +5 -3
  306. package/src/resources/extensions/gsd/workflow-logger.ts +1 -1
  307. package/src/resources/extensions/gsd/workflow-projections.ts +7 -8
  308. package/src/resources/extensions/gsd/workflow-reconcile.ts +109 -8
  309. package/src/resources/extensions/gsd/workflow-templates.ts +11 -2
  310. package/src/resources/extensions/gsd/worktree-manager.ts +4 -2
  311. package/src/resources/extensions/gsd/worktree.ts +10 -0
  312. package/src/resources/extensions/shared/interview-ui.ts +1 -1
  313. package/src/resources/extensions/shared/tests/interview-notes-loop.test.ts +8 -10
  314. package/dist/web/standalone/.next/static/chunks/6502.7593d7797a4b3999.js +0 -9
  315. /package/dist/web/standalone/.next/static/{qq3YfHPfyqvh3DIMVmsRH → JwdBI3y1H8vtBKiYvWfEK}/_buildManifest.js +0 -0
  316. /package/dist/web/standalone/.next/static/{qq3YfHPfyqvh3DIMVmsRH → JwdBI3y1H8vtBKiYvWfEK}/_ssgManifest.js +0 -0
@@ -0,0 +1,138 @@
1
+ # {{milestoneId}}: {{milestoneTitle}}
2
+
3
+ **Gathered:** {{date}}
4
+ **Status:** Ready for planning
5
+
6
+ ## Project Description
7
+
8
+ {{description}}
9
+
10
+ ## Why This Milestone
11
+
12
+ {{whatProblemThisSolves_AND_whyNow}}
13
+
14
+ ## Codebase Brief
15
+
16
+ ### Technology Stack
17
+
18
+ {{techStack}}
19
+
20
+ ### Key Modules
21
+
22
+ {{keyModules}}
23
+
24
+ ### Patterns in Use
25
+
26
+ {{patternsInUse}}
27
+
28
+ ## User-Visible Outcome
29
+
30
+ ### When this milestone is complete, the user can:
31
+
32
+ - {{literalUserActionInRealEnvironment}}
33
+ - {{literalUserActionInRealEnvironment}}
34
+
35
+ ### Entry point / environment
36
+
37
+ - Entry point: {{CLI command / URL / bot / extension / service / workflow}}
38
+ - Environment: {{local dev / browser / mobile / launchd / CI / production-like}}
39
+ - Live dependencies involved: {{telegram / database / webhook / rpc subprocess / none}}
40
+
41
+ ## Completion Class
42
+
43
+ - Contract complete means: {{what can be proven by tests / fixtures / artifacts}}
44
+ - Integration complete means: {{what must work across real subsystems}}
45
+ - Operational complete means: {{what must work under real lifecycle conditions, or none}}
46
+
47
+ ## Architectural Decisions
48
+
49
+ ### {{decisionTitle}}
50
+
51
+ **Decision:** {{decisionStatement}}
52
+
53
+ **Rationale:** {{rationale}}
54
+
55
+ **Evidence:** {{evidence}}
56
+
57
+ **Alternatives Considered:**
58
+ - {{alternative1}} — {{whyNotChosen1}}
59
+ - {{alternative2}} — {{whyNotChosen2}}
60
+
61
+ ---
62
+
63
+ > Add additional decisions as separate `### Decision Title` blocks following the same structure above.
64
+
65
+ ## Interface Contracts
66
+
67
+ {{interfaceContracts}}
68
+
69
+ > Document API boundaries, function signatures, data shapes, or protocol agreements that must be honored. Leave blank or remove if not applicable to this milestone.
70
+
71
+ ## Error Handling Strategy
72
+
73
+ {{errorHandlingStrategy}}
74
+
75
+ > Describe the approach for handling failures, edge cases, and error propagation. Include retry policies, fallback behaviors, and user-facing error messages where relevant.
76
+
77
+ ## Final Integrated Acceptance
78
+
79
+ To call this milestone complete, we must prove:
80
+
81
+ - {{one real end-to-end scenario}}
82
+ - {{one real end-to-end scenario}}
83
+ - {{what cannot be simulated if this milestone is to be considered truly done}}
84
+
85
+ ## Testing Requirements
86
+
87
+ {{testingRequirements}}
88
+
89
+ > Specify test types (unit, integration, e2e), coverage expectations, and any specific test scenarios that must pass.
90
+
91
+ ## Acceptance Criteria
92
+
93
+ {{acceptanceCriteria}}
94
+
95
+ > Per-slice acceptance criteria gathered during discussion. Each slice should have clear, testable criteria.
96
+
97
+ ## Risks and Unknowns
98
+
99
+ - {{riskOrUnknown}} — {{whyItMatters}}
100
+
101
+ ## Existing Codebase / Prior Art
102
+
103
+ - `{{fileOrModule}}` — {{howItRelates}}
104
+ - `{{fileOrModule}}` — {{howItRelates}}
105
+
106
+ > See `.gsd/DECISIONS.md` for all architectural and pattern decisions — it is an append-only register; read it during planning, append to it during execution.
107
+
108
+ ## Relevant Requirements
109
+
110
+ - {{requirementId}} — {{howThisMilestoneAdvancesIt}}
111
+
112
+ ## Scope
113
+
114
+ ### In Scope
115
+
116
+ - {{inScopeItem}}
117
+
118
+ ### Out of Scope / Non-Goals
119
+
120
+ - {{outOfScopeItem}}
121
+
122
+ ## Technical Constraints
123
+
124
+ - {{constraint}}
125
+
126
+ ## Integration Points
127
+
128
+ - {{systemOrService}} — {{howThisMilestoneInteractsWithIt}}
129
+
130
+ ## Ecosystem Notes
131
+
132
+ {{ecosystemNotes}}
133
+
134
+ > Research findings, best practices, known issues, and relevant external documentation discovered during preparation.
135
+
136
+ ## Open Questions
137
+
138
+ - {{question}} — {{currentThinking}}
@@ -15,7 +15,7 @@ import { invalidateStateCache } from "../state.js";
15
15
  import { renderAllProjections, stripIdPrefix } from "../workflow-projections.js";
16
16
  import { writeManifest } from "../workflow-manifest.js";
17
17
  import { appendEvent } from "../workflow-events.js";
18
- import { logWarning } from "../workflow-logger.js";
18
+ import { logWarning, logError } from "../workflow-logger.js";
19
19
  function renderMilestoneSummaryMarkdown(params) {
20
20
  const now = new Date().toISOString();
21
21
  const displayTitle = stripIdPrefix(params.title, params.milestoneId);
@@ -156,9 +156,21 @@ export async function handleCompleteMilestone(params, basePath) {
156
156
  clearPathCache();
157
157
  clearParseCache();
158
158
  // ── Post-mutation hook: projections, manifest, event log ───────────────
159
+ // Separate try/catch per step so a projection failure doesn't prevent
160
+ // the event log entry (critical for worktree reconciliation).
159
161
  try {
160
162
  await renderAllProjections(basePath, params.milestoneId);
163
+ }
164
+ catch (projErr) {
165
+ logWarning("tool", `complete-milestone projection warning: ${projErr.message}`);
166
+ }
167
+ try {
161
168
  writeManifest(basePath);
169
+ }
170
+ catch (mfErr) {
171
+ logWarning("tool", `complete-milestone manifest warning: ${mfErr.message}`);
172
+ }
173
+ try {
162
174
  appendEvent(basePath, {
163
175
  cmd: "complete-milestone",
164
176
  params: { milestoneId: params.milestoneId },
@@ -168,8 +180,8 @@ export async function handleCompleteMilestone(params, basePath) {
168
180
  trigger_reason: params.triggerReason,
169
181
  });
170
182
  }
171
- catch (hookErr) {
172
- logWarning("tool", `complete-milestone post-mutation hook warning: ${hookErr.message}`);
183
+ catch (eventErr) {
184
+ logError("tool", `complete-milestone event log FAILED — completion invisible to reconciliation`, { error: eventErr.message });
173
185
  }
174
186
  return {
175
187
  milestoneId: params.milestoneId,
@@ -18,7 +18,7 @@ import { renderRoadmapCheckboxes } from "../markdown-renderer.js";
18
18
  import { renderAllProjections } from "../workflow-projections.js";
19
19
  import { writeManifest } from "../workflow-manifest.js";
20
20
  import { appendEvent } from "../workflow-events.js";
21
- import { logWarning } from "../workflow-logger.js";
21
+ import { logWarning, logError } from "../workflow-logger.js";
22
22
  /**
23
23
  * Render slice summary markdown matching the template format.
24
24
  * YAML frontmatter uses snake_case keys for parseSummary() compatibility.
@@ -187,8 +187,17 @@ export async function handleCompleteSlice(params, basePath) {
187
187
  if (ownershipErr) {
188
188
  return { error: ownershipErr };
189
189
  }
190
+ // ── Verification content gate (#3580) ──────────────────────────────────
191
+ // Reject completion when the provided verification/UAT clearly indicates
192
+ // the slice is blocked or failed. Prevents prompt regressions from
193
+ // silently advancing blocked slices.
194
+ const BLOCKED_SIGNALS = /\b(status:\s*blocked|verification_result:\s*failed|slice is blocked|cannot complete|verification failed)\b/i;
195
+ if (BLOCKED_SIGNALS.test(params.verification || "") || BLOCKED_SIGNALS.test(params.uatContent || "")) {
196
+ return { error: `slice verification indicates blocked/failed state — do not complete a slice that has not passed verification. Address the blockers and re-verify first.` };
197
+ }
190
198
  // ── Guards + DB writes inside a single transaction (prevents TOCTOU) ───
191
199
  const completedAt = new Date().toISOString();
200
+ const originalSliceStatus = getSlice(params.milestoneId, params.sliceId)?.status ?? "pending";
192
201
  let guardError = null;
193
202
  transaction(() => {
194
203
  // State machine preconditions (inside txn for atomicity).
@@ -217,8 +226,8 @@ export async function handleCompleteSlice(params, basePath) {
217
226
  return;
218
227
  }
219
228
  // All guards passed — perform writes
220
- insertMilestone({ id: params.milestoneId });
221
- insertSlice({ id: params.sliceId, milestoneId: params.milestoneId });
229
+ insertMilestone({ id: params.milestoneId, title: params.milestoneId });
230
+ insertSlice({ id: params.sliceId, milestoneId: params.milestoneId, title: params.sliceId });
222
231
  updateSliceStatus(params.milestoneId, params.sliceId, "complete", completedAt);
223
232
  });
224
233
  if (guardError) {
@@ -256,7 +265,7 @@ export async function handleCompleteSlice(params, basePath) {
256
265
  catch (renderErr) {
257
266
  // Disk render failed — roll back DB status so state stays consistent
258
267
  logWarning("tool", `complete_slice — disk render failed for ${params.milestoneId}/${params.sliceId}, rolling back DB status`, { error: renderErr.message });
259
- updateSliceStatus(params.milestoneId, params.sliceId, 'pending');
268
+ updateSliceStatus(params.milestoneId, params.sliceId, originalSliceStatus);
260
269
  invalidateStateCache();
261
270
  return { error: `disk render failed: ${renderErr.message}` };
262
271
  }
@@ -267,9 +276,21 @@ export async function handleCompleteSlice(params, basePath) {
267
276
  clearPathCache();
268
277
  clearParseCache();
269
278
  // ── Post-mutation hook: projections, manifest, event log ───────────────
279
+ // Separate try/catch per step so a projection failure doesn't prevent
280
+ // the event log entry (critical for worktree reconciliation).
270
281
  try {
271
282
  await renderAllProjections(basePath, params.milestoneId);
283
+ }
284
+ catch (projErr) {
285
+ logWarning("tool", `complete-slice projection warning for ${params.milestoneId}/${params.sliceId}: ${projErr.message}`);
286
+ }
287
+ try {
272
288
  writeManifest(basePath);
289
+ }
290
+ catch (mfErr) {
291
+ logWarning("tool", `complete-slice manifest warning: ${mfErr.message}`);
292
+ }
293
+ try {
273
294
  appendEvent(basePath, {
274
295
  cmd: "complete-slice",
275
296
  params: { milestoneId: params.milestoneId, sliceId: params.sliceId },
@@ -279,8 +300,8 @@ export async function handleCompleteSlice(params, basePath) {
279
300
  trigger_reason: params.triggerReason,
280
301
  });
281
302
  }
282
- catch (hookErr) {
283
- logWarning("tool", `complete-slice post-mutation hook failed for ${params.milestoneId}/${params.sliceId}`, { error: hookErr.message });
303
+ catch (eventErr) {
304
+ logError("tool", `complete-slice event log FAILED completion invisible to reconciliation`, { error: eventErr.message });
284
305
  }
285
306
  return {
286
307
  sliceId: params.sliceId,
@@ -18,7 +18,19 @@ import { renderPlanCheckboxes } from "../markdown-renderer.js";
18
18
  import { renderAllProjections, renderSummaryContent } from "../workflow-projections.js";
19
19
  import { writeManifest } from "../workflow-manifest.js";
20
20
  import { appendEvent } from "../workflow-events.js";
21
- import { logWarning } from "../workflow-logger.js";
21
+ import { logWarning, logError } from "../workflow-logger.js";
22
+ /**
23
+ * Normalize a list parameter that may arrive as a string (newline-delimited
24
+ * bullet list from the LLM) into a string array (#3361).
25
+ */
26
+ function normalizeListParam(value) {
27
+ if (Array.isArray(value))
28
+ return value.map(String);
29
+ if (typeof value === "string" && value.trim()) {
30
+ return value.split(/\n/).map(s => s.replace(/^[\s\-*•]+/, "").trim()).filter(Boolean);
31
+ }
32
+ return [];
33
+ }
22
34
  /**
23
35
  * Build a TaskRow-shaped object from CompleteTaskParams so the unified
24
36
  * renderSummaryContent() can be used at completion time (#2720).
@@ -38,8 +50,8 @@ function paramsToTaskRow(params, completedAt) {
38
50
  blocker_discovered: params.blockerDiscovered ?? false,
39
51
  deviations: params.deviations ?? "",
40
52
  known_issues: params.knownIssues ?? "",
41
- key_files: params.keyFiles ?? [],
42
- key_decisions: params.keyDecisions ?? [],
53
+ key_files: normalizeListParam(params.keyFiles),
54
+ key_decisions: normalizeListParam(params.keyDecisions),
43
55
  full_summary_md: "",
44
56
  description: "",
45
57
  estimate: "",
@@ -101,8 +113,8 @@ export async function handleCompleteTask(params, basePath) {
101
113
  return;
102
114
  }
103
115
  // All guards passed — perform writes
104
- insertMilestone({ id: params.milestoneId });
105
- insertSlice({ id: params.sliceId, milestoneId: params.milestoneId });
116
+ insertMilestone({ id: params.milestoneId, title: params.milestoneId });
117
+ insertSlice({ id: params.sliceId, milestoneId: params.milestoneId, title: params.sliceId });
106
118
  insertTask({
107
119
  id: params.taskId,
108
120
  sliceId: params.sliceId,
@@ -182,9 +194,21 @@ export async function handleCompleteTask(params, basePath) {
182
194
  clearPathCache();
183
195
  clearParseCache();
184
196
  // ── Post-mutation hook: projections, manifest, event log ───────────────
197
+ // Separate try/catch per step so a projection failure doesn't prevent
198
+ // the event log entry (critical for worktree reconciliation).
185
199
  try {
186
200
  await renderAllProjections(basePath, params.milestoneId);
201
+ }
202
+ catch (projErr) {
203
+ logWarning("tool", `complete-task projection warning: ${projErr.message}`);
204
+ }
205
+ try {
187
206
  writeManifest(basePath);
207
+ }
208
+ catch (mfErr) {
209
+ logWarning("tool", `complete-task manifest warning: ${mfErr.message}`);
210
+ }
211
+ try {
188
212
  appendEvent(basePath, {
189
213
  cmd: "complete-task",
190
214
  params: { milestoneId: params.milestoneId, sliceId: params.sliceId, taskId: params.taskId },
@@ -194,8 +218,8 @@ export async function handleCompleteTask(params, basePath) {
194
218
  trigger_reason: params.triggerReason,
195
219
  });
196
220
  }
197
- catch (hookErr) {
198
- logWarning("tool", `complete-task post-mutation hook warning: ${hookErr.message}`);
221
+ catch (eventErr) {
222
+ logError("tool", `complete-task event log FAILED — completion invisible to reconciliation`, { error: eventErr.message });
199
223
  }
200
224
  return {
201
225
  taskId: params.taskId,
@@ -113,10 +113,10 @@ function validateParams(params) {
113
113
  successCriteria: params.successCriteria ? validateStringArray(params.successCriteria, "successCriteria") : [],
114
114
  keyRisks: params.keyRisks ? validateRiskEntries(params.keyRisks) : [],
115
115
  proofStrategy: params.proofStrategy ? validateProofStrategy(params.proofStrategy) : [],
116
- verificationContract: params.verificationContract ?? "Not provided.",
117
- verificationIntegration: params.verificationIntegration ?? "Not provided.",
118
- verificationOperational: params.verificationOperational ?? "Not provided.",
119
- verificationUat: params.verificationUat ?? "Not provided.",
116
+ verificationContract: params.verificationContract ?? "",
117
+ verificationIntegration: params.verificationIntegration ?? "",
118
+ verificationOperational: params.verificationOperational ?? "",
119
+ verificationUat: params.verificationUat ?? "",
120
120
  definitionOfDone: params.definitionOfDone ? validateStringArray(params.definitionOfDone, "definitionOfDone") : [],
121
121
  requirementCoverage: params.requirementCoverage ?? "Not provided.",
122
122
  boundaryMapMarkdown: params.boundaryMapMarkdown ?? "Not provided.",
@@ -191,7 +191,8 @@ export async function handlePlanMilestone(rawParams, basePath) {
191
191
  requirementCoverage: params.requirementCoverage,
192
192
  boundaryMapMarkdown: params.boundaryMapMarkdown,
193
193
  });
194
- for (const slice of params.slices) {
194
+ for (let i = 0; i < params.slices.length; i++) {
195
+ const slice = params.slices[i];
195
196
  // Preserve completed/done status on re-plan (#2558).
196
197
  // Without this, a re-plan after milestone transition would reset
197
198
  // already-completed slices back to "pending".
@@ -207,6 +208,7 @@ export async function handlePlanMilestone(rawParams, basePath) {
207
208
  risk: slice.risk,
208
209
  depends: slice.depends,
209
210
  demo: slice.demo,
211
+ sequence: i + 1, // Preserve agent-ordered sequence (#3356)
210
212
  });
211
213
  upsertSlicePlanning(params.milestoneId, slice.sliceId, {
212
214
  goal: slice.goal,
@@ -129,8 +129,10 @@ export async function handleReassessRoadmap(rawParams, basePath) {
129
129
  demo: mod.demo,
130
130
  });
131
131
  }
132
- // Insert new slices
133
- for (const added of params.sliceChanges.added) {
132
+ // Insert new slices — assign sequence after existing slices (#3356)
133
+ const existingCount = getMilestoneSlices(params.milestoneId).length;
134
+ for (let i = 0; i < params.sliceChanges.added.length; i++) {
135
+ const added = params.sliceChanges.added[i];
134
136
  insertSlice({
135
137
  id: added.sliceId,
136
138
  milestoneId: params.milestoneId,
@@ -139,6 +141,7 @@ export async function handleReassessRoadmap(rawParams, basePath) {
139
141
  risk: added.risk,
140
142
  depends: added.depends,
141
143
  demo: added.demo ?? "",
144
+ sequence: existingCount + i + 1,
142
145
  });
143
146
  }
144
147
  // Delete removed slices
@@ -0,0 +1,119 @@
1
+ // GSD — reopen-milestone tool handler
2
+ /**
3
+ * reopen-milestone handler — the core operation behind gsd_milestone_reopen.
4
+ *
5
+ * Resets a closed milestone back to "active", all of its slices to
6
+ * "in_progress", and all tasks to "pending". Cleans up stale filesystem
7
+ * artifacts so the DB-filesystem reconciler does not auto-correct
8
+ * entities back to "complete".
9
+ */
10
+ import { getMilestone, getMilestoneSlices, getSliceTasks, updateMilestoneStatus, updateSliceStatus, updateTaskStatus, transaction, } from "../gsd-db.js";
11
+ import { invalidateStateCache } from "../state.js";
12
+ import { isClosedStatus } from "../status-guards.js";
13
+ import { renderAllProjections } from "../workflow-projections.js";
14
+ import { writeManifest } from "../workflow-manifest.js";
15
+ import { appendEvent } from "../workflow-events.js";
16
+ import { logWarning } from "../workflow-logger.js";
17
+ import { debugLog } from "../debug-logger.js";
18
+ import { existsSync, unlinkSync } from "node:fs";
19
+ import { join } from "node:path";
20
+ import { resolveMilestonePath, resolveSlicePath, resolveTasksDir, clearPathCache } from "../paths.js";
21
+ export async function handleReopenMilestone(params, basePath) {
22
+ // ── Validate required fields ────────────────────────────────────────────
23
+ if (!params.milestoneId || typeof params.milestoneId !== "string" || params.milestoneId.trim() === "") {
24
+ return { error: "milestoneId is required and must be a non-empty string" };
25
+ }
26
+ // ── Guards + DB writes inside a single transaction (prevents TOCTOU) ───
27
+ let guardError = null;
28
+ let slicesResetCount = 0;
29
+ let tasksResetCount = 0;
30
+ transaction(() => {
31
+ const milestone = getMilestone(params.milestoneId);
32
+ if (!milestone) {
33
+ guardError = `milestone not found: ${params.milestoneId}`;
34
+ return;
35
+ }
36
+ if (!isClosedStatus(milestone.status)) {
37
+ guardError = `milestone ${params.milestoneId} is not closed (status: ${milestone.status}) — nothing to reopen`;
38
+ return;
39
+ }
40
+ updateMilestoneStatus(params.milestoneId, "active", null);
41
+ const slices = getMilestoneSlices(params.milestoneId);
42
+ slicesResetCount = slices.length;
43
+ for (const slice of slices) {
44
+ updateSliceStatus(params.milestoneId, slice.id, "in_progress");
45
+ const tasks = getSliceTasks(params.milestoneId, slice.id);
46
+ tasksResetCount += tasks.length;
47
+ for (const task of tasks) {
48
+ updateTaskStatus(params.milestoneId, slice.id, task.id, "pending");
49
+ }
50
+ }
51
+ });
52
+ if (guardError) {
53
+ return { error: guardError };
54
+ }
55
+ // ── Invalidate caches ────────────────────────────────────────────────────
56
+ invalidateStateCache();
57
+ // ── Clean up stale filesystem artifacts (M12 fix) ────────────────────────
58
+ // Without this, the DB-filesystem reconciler sees SUMMARY.md files and
59
+ // auto-corrects entities back to "complete", making reopen a no-op (#3161).
60
+ try {
61
+ const milestoneDir = resolveMilestonePath(basePath, params.milestoneId);
62
+ if (milestoneDir) {
63
+ const milestoneSummary = join(milestoneDir, `${params.milestoneId}-SUMMARY.md`);
64
+ if (existsSync(milestoneSummary))
65
+ unlinkSync(milestoneSummary);
66
+ }
67
+ const slices = getMilestoneSlices(params.milestoneId);
68
+ for (const slice of slices) {
69
+ const sliceDir = resolveSlicePath(basePath, params.milestoneId, slice.id);
70
+ if (sliceDir) {
71
+ const sliceSummary = join(sliceDir, `${slice.id}-SUMMARY.md`);
72
+ if (existsSync(sliceSummary))
73
+ unlinkSync(sliceSummary);
74
+ const sliceUat = join(sliceDir, `${slice.id}-UAT.md`);
75
+ if (existsSync(sliceUat))
76
+ unlinkSync(sliceUat);
77
+ }
78
+ const tasksDir = resolveTasksDir(basePath, params.milestoneId, slice.id);
79
+ if (tasksDir) {
80
+ const tasks = getSliceTasks(params.milestoneId, slice.id);
81
+ for (const task of tasks) {
82
+ const taskSummary = join(tasksDir, `${task.id}-SUMMARY.md`);
83
+ if (existsSync(taskSummary))
84
+ unlinkSync(taskSummary);
85
+ }
86
+ }
87
+ }
88
+ }
89
+ catch (err) {
90
+ debugLog("reopen-milestone-cleanup-failed", { milestoneId: params.milestoneId, error: String(err) });
91
+ }
92
+ clearPathCache();
93
+ // ── Post-mutation hook ───────────────────────────────────────────────────
94
+ try {
95
+ await renderAllProjections(basePath, params.milestoneId);
96
+ writeManifest(basePath);
97
+ appendEvent(basePath, {
98
+ cmd: "reopen-milestone",
99
+ params: {
100
+ milestoneId: params.milestoneId,
101
+ reason: params.reason ?? null,
102
+ slicesReset: slicesResetCount,
103
+ tasksReset: tasksResetCount,
104
+ },
105
+ ts: new Date().toISOString(),
106
+ actor: "agent",
107
+ actor_name: params.actorName,
108
+ trigger_reason: params.triggerReason,
109
+ });
110
+ }
111
+ catch (hookErr) {
112
+ logWarning("tool", `reopen-milestone post-mutation hook warning: ${hookErr.message}`);
113
+ }
114
+ return {
115
+ milestoneId: params.milestoneId,
116
+ slicesReset: slicesResetCount,
117
+ tasksReset: tasksResetCount,
118
+ };
119
+ }
@@ -16,6 +16,9 @@ import { renderAllProjections } from "../workflow-projections.js";
16
16
  import { writeManifest } from "../workflow-manifest.js";
17
17
  import { appendEvent } from "../workflow-events.js";
18
18
  import { logWarning } from "../workflow-logger.js";
19
+ import { existsSync, unlinkSync } from "node:fs";
20
+ import { join } from "node:path";
21
+ import { resolveTasksDir, resolveSlicePath, clearPathCache } from "../paths.js";
19
22
  export async function handleReopenSlice(params, basePath) {
20
23
  // ── Validate required fields ────────────────────────────────────────────
21
24
  if (!params.sliceId || typeof params.sliceId !== "string" || params.sliceId.trim() === "") {
@@ -59,6 +62,33 @@ export async function handleReopenSlice(params, basePath) {
59
62
  }
60
63
  // ── Invalidate caches ────────────────────────────────────────────────────
61
64
  invalidateStateCache();
65
+ // ── Clean up stale filesystem artifacts (M12 fix) ────────────────────────
66
+ // Without this, the DB-filesystem reconciler sees SUMMARY.md files and
67
+ // auto-corrects tasks back to "complete", making reopen a no-op (#3161).
68
+ try {
69
+ const tasksDir = resolveTasksDir(basePath, params.milestoneId, params.sliceId);
70
+ if (tasksDir) {
71
+ const tasks = getSliceTasks(params.milestoneId, params.sliceId);
72
+ for (const task of tasks) {
73
+ const summaryPath = join(tasksDir, `${task.id}-SUMMARY.md`);
74
+ if (existsSync(summaryPath))
75
+ unlinkSync(summaryPath);
76
+ }
77
+ }
78
+ const sliceDir = resolveSlicePath(basePath, params.milestoneId, params.sliceId);
79
+ if (sliceDir) {
80
+ const sliceSummary = join(sliceDir, `${params.sliceId}-SUMMARY.md`);
81
+ if (existsSync(sliceSummary))
82
+ unlinkSync(sliceSummary);
83
+ const sliceUat = join(sliceDir, `${params.sliceId}-UAT.md`);
84
+ if (existsSync(sliceUat))
85
+ unlinkSync(sliceUat);
86
+ }
87
+ }
88
+ catch (cleanupErr) {
89
+ logWarning("tool", `reopen-slice artifact cleanup warning: ${cleanupErr.message}`);
90
+ }
91
+ clearPathCache();
62
92
  // ── Post-mutation hook ───────────────────────────────────────────────────
63
93
  try {
64
94
  await renderAllProjections(basePath, params.milestoneId);
@@ -15,6 +15,9 @@ import { renderAllProjections } from "../workflow-projections.js";
15
15
  import { writeManifest } from "../workflow-manifest.js";
16
16
  import { appendEvent } from "../workflow-events.js";
17
17
  import { logWarning } from "../workflow-logger.js";
18
+ import { existsSync, unlinkSync } from "node:fs";
19
+ import { join } from "node:path";
20
+ import { resolveTasksDir, clearPathCache } from "../paths.js";
18
21
  export async function handleReopenTask(params, basePath) {
19
22
  // ── Validate required fields ────────────────────────────────────────────
20
23
  if (!params.taskId || typeof params.taskId !== "string" || params.taskId.trim() === "") {
@@ -63,6 +66,21 @@ export async function handleReopenTask(params, basePath) {
63
66
  }
64
67
  // ── Invalidate caches ────────────────────────────────────────────────────
65
68
  invalidateStateCache();
69
+ // ── Clean up stale filesystem artifacts (M12 fix) ────────────────────────
70
+ // Without this, the DB-filesystem reconciler sees the SUMMARY.md and
71
+ // auto-corrects the task back to "complete", making reopen a no-op (#3161).
72
+ try {
73
+ const tasksDir = resolveTasksDir(basePath, params.milestoneId, params.sliceId);
74
+ if (tasksDir) {
75
+ const summaryPath = join(tasksDir, `${params.taskId}-SUMMARY.md`);
76
+ if (existsSync(summaryPath))
77
+ unlinkSync(summaryPath);
78
+ }
79
+ }
80
+ catch (cleanupErr) {
81
+ logWarning("tool", `reopen-task artifact cleanup warning: ${cleanupErr.message}`);
82
+ }
83
+ clearPathCache();
66
84
  // ── Post-mutation hook ───────────────────────────────────────────────────
67
85
  try {
68
86
  await renderAllProjections(basePath, params.milestoneId);