gsd-pi 2.43.0 → 2.44.0-dev.0b97ffd

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 (693) hide show
  1. package/README.md +30 -12
  2. package/dist/cli.js +13 -1
  3. package/dist/help-text.js +24 -0
  4. package/dist/resources/extensions/bg-shell/overlay.js +3 -0
  5. package/dist/resources/extensions/github-sync/sync.js +2 -1
  6. package/dist/resources/extensions/gsd/auto/loop.js +0 -2
  7. package/dist/resources/extensions/gsd/auto/phases.js +7 -12
  8. package/dist/resources/extensions/gsd/auto-dashboard.js +19 -18
  9. package/dist/resources/extensions/gsd/auto-direct-dispatch.js +34 -19
  10. package/dist/resources/extensions/gsd/auto-dispatch.js +36 -21
  11. package/dist/resources/extensions/gsd/auto-post-unit.js +128 -14
  12. package/dist/resources/extensions/gsd/auto-prompts.js +202 -92
  13. package/dist/resources/extensions/gsd/auto-recovery.js +83 -135
  14. package/dist/resources/extensions/gsd/auto-start.js +10 -0
  15. package/dist/resources/extensions/gsd/auto-supervisor.js +14 -0
  16. package/dist/resources/extensions/gsd/auto-timeout-recovery.js +4 -7
  17. package/dist/resources/extensions/gsd/auto-verification.js +5 -10
  18. package/dist/resources/extensions/gsd/auto-worktree.js +123 -30
  19. package/dist/resources/extensions/gsd/auto.js +1 -4
  20. package/dist/resources/extensions/gsd/bootstrap/db-tools.js +611 -0
  21. package/dist/resources/extensions/gsd/bootstrap/dynamic-tools.js +28 -3
  22. package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +7 -0
  23. package/dist/resources/extensions/gsd/commands/catalog.js +3 -1
  24. package/dist/resources/extensions/gsd/commands/handlers/ops.js +15 -1
  25. package/dist/resources/extensions/gsd/commands/handlers/workflow.js +5 -0
  26. package/dist/resources/extensions/gsd/commands-handlers.js +1 -1
  27. package/dist/resources/extensions/gsd/commands-maintenance.js +78 -3
  28. package/dist/resources/extensions/gsd/dashboard-overlay.js +32 -31
  29. package/dist/resources/extensions/gsd/db-writer.js +95 -4
  30. package/dist/resources/extensions/gsd/dispatch-guard.js +35 -30
  31. package/dist/resources/extensions/gsd/doctor-checks.js +28 -11
  32. package/dist/resources/extensions/gsd/doctor-environment.js +28 -0
  33. package/dist/resources/extensions/gsd/doctor-types.js +0 -15
  34. package/dist/resources/extensions/gsd/doctor.js +46 -282
  35. package/dist/resources/extensions/gsd/file-watcher.js +5 -1
  36. package/dist/resources/extensions/gsd/files.js +14 -198
  37. package/dist/resources/extensions/gsd/git-service.js +4 -0
  38. package/dist/resources/extensions/gsd/gitignore.js +4 -0
  39. package/dist/resources/extensions/gsd/gsd-db.js +819 -197
  40. package/dist/resources/extensions/gsd/guided-flow.js +18 -8
  41. package/dist/resources/extensions/gsd/markdown-renderer.js +862 -0
  42. package/dist/resources/extensions/gsd/md-importer.js +182 -4
  43. package/dist/resources/extensions/gsd/native-git-bridge.js +10 -1
  44. package/dist/resources/extensions/gsd/parallel-eligibility.js +14 -19
  45. package/dist/resources/extensions/gsd/parallel-orchestrator.js +38 -0
  46. package/dist/resources/extensions/gsd/parsers-legacy.js +239 -0
  47. package/dist/resources/extensions/gsd/preferences-types.js +1 -0
  48. package/dist/resources/extensions/gsd/preferences-validation.js +9 -0
  49. package/dist/resources/extensions/gsd/preferences.js +1 -0
  50. package/dist/resources/extensions/gsd/prompts/complete-slice.md +22 -9
  51. package/dist/resources/extensions/gsd/prompts/discuss.md +2 -2
  52. package/dist/resources/extensions/gsd/prompts/execute-task.md +15 -5
  53. package/dist/resources/extensions/gsd/prompts/guided-complete-slice.md +1 -1
  54. package/dist/resources/extensions/gsd/prompts/guided-execute-task.md +1 -1
  55. package/dist/resources/extensions/gsd/prompts/guided-plan-milestone.md +1 -1
  56. package/dist/resources/extensions/gsd/prompts/plan-milestone.md +6 -10
  57. package/dist/resources/extensions/gsd/prompts/plan-slice.md +4 -7
  58. package/dist/resources/extensions/gsd/prompts/reactive-execute.md +3 -3
  59. package/dist/resources/extensions/gsd/prompts/reassess-roadmap.md +6 -7
  60. package/dist/resources/extensions/gsd/prompts/replan-slice.md +6 -6
  61. package/dist/resources/extensions/gsd/reactive-graph.js +33 -3
  62. package/dist/resources/extensions/gsd/skill-health.js +3 -1
  63. package/dist/resources/extensions/gsd/state.js +484 -30
  64. package/dist/resources/extensions/gsd/tools/complete-milestone.js +128 -0
  65. package/dist/resources/extensions/gsd/tools/complete-slice.js +244 -0
  66. package/dist/resources/extensions/gsd/tools/complete-task.js +204 -0
  67. package/dist/resources/extensions/gsd/tools/plan-milestone.js +205 -0
  68. package/dist/resources/extensions/gsd/tools/plan-slice.js +155 -0
  69. package/dist/resources/extensions/gsd/tools/plan-task.js +94 -0
  70. package/dist/resources/extensions/gsd/tools/reassess-roadmap.js +152 -0
  71. package/dist/resources/extensions/gsd/tools/replan-slice.js +146 -0
  72. package/dist/resources/extensions/gsd/triage-resolution.js +17 -1
  73. package/dist/resources/extensions/gsd/undo.js +197 -3
  74. package/dist/resources/extensions/gsd/visualizer-data.js +53 -16
  75. package/dist/resources/extensions/gsd/workspace-index.js +63 -39
  76. package/dist/web/standalone/.next/BUILD_ID +1 -1
  77. package/dist/web/standalone/.next/app-path-routes-manifest.json +18 -17
  78. package/dist/web/standalone/.next/build-manifest.json +4 -4
  79. package/dist/web/standalone/.next/prerender-manifest.json +3 -3
  80. package/dist/web/standalone/.next/react-loadable-manifest.json +1 -1
  81. package/dist/web/standalone/.next/required-server-files.json +4 -4
  82. package/dist/web/standalone/.next/routes-manifest.json +6 -0
  83. package/dist/web/standalone/.next/server/app/_global-error/page.js +3 -3
  84. package/dist/web/standalone/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
  85. package/dist/web/standalone/.next/server/app/_global-error.html +2 -2
  86. package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
  87. package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  88. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
  89. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
  90. package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  91. package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  92. package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  93. package/dist/web/standalone/.next/server/app/_not-found/page.js +2 -2
  94. package/dist/web/standalone/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  95. package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
  96. package/dist/web/standalone/.next/server/app/_not-found.rsc +4 -4
  97. package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +4 -4
  98. package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  99. package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +4 -4
  100. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  101. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  102. package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +2 -2
  103. package/dist/web/standalone/.next/server/app/api/boot/route.js +1 -1
  104. package/dist/web/standalone/.next/server/app/api/boot/route_client-reference-manifest.js +1 -1
  105. package/dist/web/standalone/.next/server/app/api/bridge-terminal/input/route.js +1 -1
  106. package/dist/web/standalone/.next/server/app/api/bridge-terminal/input/route_client-reference-manifest.js +1 -1
  107. package/dist/web/standalone/.next/server/app/api/bridge-terminal/resize/route.js +1 -1
  108. package/dist/web/standalone/.next/server/app/api/bridge-terminal/resize/route_client-reference-manifest.js +1 -1
  109. package/dist/web/standalone/.next/server/app/api/bridge-terminal/stream/route.js +2 -2
  110. package/dist/web/standalone/.next/server/app/api/bridge-terminal/stream/route_client-reference-manifest.js +1 -1
  111. package/dist/web/standalone/.next/server/app/api/browse-directories/route.js +1 -1
  112. package/dist/web/standalone/.next/server/app/api/browse-directories/route_client-reference-manifest.js +1 -1
  113. package/dist/web/standalone/.next/server/app/api/captures/route.js +1 -1
  114. package/dist/web/standalone/.next/server/app/api/captures/route_client-reference-manifest.js +1 -1
  115. package/dist/web/standalone/.next/server/app/api/cleanup/route.js +1 -1
  116. package/dist/web/standalone/.next/server/app/api/cleanup/route_client-reference-manifest.js +1 -1
  117. package/dist/web/standalone/.next/server/app/api/dev-mode/route.js +1 -1
  118. package/dist/web/standalone/.next/server/app/api/dev-mode/route_client-reference-manifest.js +1 -1
  119. package/dist/web/standalone/.next/server/app/api/doctor/route.js +1 -1
  120. package/dist/web/standalone/.next/server/app/api/doctor/route_client-reference-manifest.js +1 -1
  121. package/dist/web/standalone/.next/server/app/api/export-data/route.js +1 -1
  122. package/dist/web/standalone/.next/server/app/api/export-data/route_client-reference-manifest.js +1 -1
  123. package/dist/web/standalone/.next/server/app/api/files/route.js +1 -1
  124. package/dist/web/standalone/.next/server/app/api/files/route_client-reference-manifest.js +1 -1
  125. package/dist/web/standalone/.next/server/app/api/forensics/route.js +1 -1
  126. package/dist/web/standalone/.next/server/app/api/forensics/route_client-reference-manifest.js +1 -1
  127. package/dist/web/standalone/.next/server/app/api/git/route.js +1 -1
  128. package/dist/web/standalone/.next/server/app/api/git/route_client-reference-manifest.js +1 -1
  129. package/dist/web/standalone/.next/server/app/api/history/route.js +1 -1
  130. package/dist/web/standalone/.next/server/app/api/history/route_client-reference-manifest.js +1 -1
  131. package/dist/web/standalone/.next/server/app/api/hooks/route.js +1 -1
  132. package/dist/web/standalone/.next/server/app/api/hooks/route_client-reference-manifest.js +1 -1
  133. package/dist/web/standalone/.next/server/app/api/inspect/route.js +1 -1
  134. package/dist/web/standalone/.next/server/app/api/inspect/route_client-reference-manifest.js +1 -1
  135. package/dist/web/standalone/.next/server/app/api/knowledge/route.js +1 -1
  136. package/dist/web/standalone/.next/server/app/api/knowledge/route_client-reference-manifest.js +1 -1
  137. package/dist/web/standalone/.next/server/app/api/live-state/route.js +1 -1
  138. package/dist/web/standalone/.next/server/app/api/live-state/route_client-reference-manifest.js +1 -1
  139. package/dist/web/standalone/.next/server/app/api/onboarding/route.js +1 -1
  140. package/dist/web/standalone/.next/server/app/api/onboarding/route_client-reference-manifest.js +1 -1
  141. package/dist/web/standalone/.next/server/app/api/preferences/route.js +1 -1
  142. package/dist/web/standalone/.next/server/app/api/preferences/route_client-reference-manifest.js +1 -1
  143. package/dist/web/standalone/.next/server/app/api/projects/route.js +1 -1
  144. package/dist/web/standalone/.next/server/app/api/projects/route_client-reference-manifest.js +1 -1
  145. package/dist/web/standalone/.next/server/app/api/recovery/route.js +1 -1
  146. package/dist/web/standalone/.next/server/app/api/recovery/route_client-reference-manifest.js +1 -1
  147. package/dist/web/standalone/.next/server/app/api/remote-questions/route.js +5 -5
  148. package/dist/web/standalone/.next/server/app/api/remote-questions/route_client-reference-manifest.js +1 -1
  149. package/dist/web/standalone/.next/server/app/api/session/browser/route.js +1 -1
  150. package/dist/web/standalone/.next/server/app/api/session/browser/route_client-reference-manifest.js +1 -1
  151. package/dist/web/standalone/.next/server/app/api/session/command/route.js +1 -1
  152. package/dist/web/standalone/.next/server/app/api/session/command/route_client-reference-manifest.js +1 -1
  153. package/dist/web/standalone/.next/server/app/api/session/events/route.js +2 -2
  154. package/dist/web/standalone/.next/server/app/api/session/events/route_client-reference-manifest.js +1 -1
  155. package/dist/web/standalone/.next/server/app/api/session/manage/route.js +1 -1
  156. package/dist/web/standalone/.next/server/app/api/session/manage/route_client-reference-manifest.js +1 -1
  157. package/dist/web/standalone/.next/server/app/api/settings-data/route.js +1 -1
  158. package/dist/web/standalone/.next/server/app/api/settings-data/route_client-reference-manifest.js +1 -1
  159. package/dist/web/standalone/.next/server/app/api/shutdown/route.js +1 -1
  160. package/dist/web/standalone/.next/server/app/api/shutdown/route_client-reference-manifest.js +1 -1
  161. package/dist/web/standalone/.next/server/app/api/skill-health/route.js +1 -1
  162. package/dist/web/standalone/.next/server/app/api/skill-health/route_client-reference-manifest.js +1 -1
  163. package/dist/web/standalone/.next/server/app/api/steer/route.js +1 -1
  164. package/dist/web/standalone/.next/server/app/api/steer/route_client-reference-manifest.js +1 -1
  165. package/dist/web/standalone/.next/server/app/api/switch-root/route.js +1 -0
  166. package/dist/web/standalone/.next/server/app/api/switch-root/route.js.nft.json +1 -0
  167. package/dist/web/standalone/.next/server/app/api/switch-root/route_client-reference-manifest.js +1 -0
  168. package/dist/web/standalone/.next/server/app/api/terminal/input/route.js +1 -1
  169. package/dist/web/standalone/.next/server/app/api/terminal/input/route_client-reference-manifest.js +1 -1
  170. package/dist/web/standalone/.next/server/app/api/terminal/resize/route.js +2 -2
  171. package/dist/web/standalone/.next/server/app/api/terminal/resize/route_client-reference-manifest.js +1 -1
  172. package/dist/web/standalone/.next/server/app/api/terminal/sessions/route.js +2 -2
  173. package/dist/web/standalone/.next/server/app/api/terminal/sessions/route_client-reference-manifest.js +1 -1
  174. package/dist/web/standalone/.next/server/app/api/terminal/stream/route.js +4 -4
  175. package/dist/web/standalone/.next/server/app/api/terminal/stream/route_client-reference-manifest.js +1 -1
  176. package/dist/web/standalone/.next/server/app/api/terminal/upload/route.js +1 -1
  177. package/dist/web/standalone/.next/server/app/api/terminal/upload/route_client-reference-manifest.js +1 -1
  178. package/dist/web/standalone/.next/server/app/api/undo/route.js +1 -1
  179. package/dist/web/standalone/.next/server/app/api/undo/route_client-reference-manifest.js +1 -1
  180. package/dist/web/standalone/.next/server/app/api/update/route.js +1 -1
  181. package/dist/web/standalone/.next/server/app/api/update/route_client-reference-manifest.js +1 -1
  182. package/dist/web/standalone/.next/server/app/api/visualizer/route.js +1 -1
  183. package/dist/web/standalone/.next/server/app/api/visualizer/route_client-reference-manifest.js +1 -1
  184. package/dist/web/standalone/.next/server/app/index.html +1 -1
  185. package/dist/web/standalone/.next/server/app/index.rsc +5 -5
  186. package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +2 -2
  187. package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +5 -5
  188. package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
  189. package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +4 -4
  190. package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +2 -2
  191. package/dist/web/standalone/.next/server/app/page.js +2 -2
  192. package/dist/web/standalone/.next/server/app/page_client-reference-manifest.js +1 -1
  193. package/dist/web/standalone/.next/server/app-paths-manifest.json +18 -17
  194. package/dist/web/standalone/.next/server/chunks/229.js +3 -3
  195. package/dist/web/standalone/.next/server/chunks/471.js +3 -3
  196. package/dist/web/standalone/.next/server/functions-config-manifest.json +1 -0
  197. package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
  198. package/dist/web/standalone/.next/server/middleware-react-loadable-manifest.js +1 -1
  199. package/dist/web/standalone/.next/server/middleware.js +2 -2
  200. package/dist/web/standalone/.next/server/next-font-manifest.js +1 -1
  201. package/dist/web/standalone/.next/server/next-font-manifest.json +1 -1
  202. package/dist/web/standalone/.next/server/pages/404.html +1 -1
  203. package/dist/web/standalone/.next/server/pages/500.html +2 -2
  204. package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
  205. package/dist/web/standalone/.next/static/alS4hoANx0TK4UVZY27da/_buildManifest.js +1 -0
  206. package/dist/web/standalone/.next/static/chunks/{4024.c195dc1fdd2adbea.js → 4024.0de81b543b28b9fe.js} +2 -2
  207. package/dist/web/standalone/.next/static/chunks/app/_global-error/{page-d07a2c023f1aef1e.js → page-d83ba70a25a85472.js} +1 -1
  208. package/dist/web/standalone/.next/static/chunks/app/_not-found/page-f2a7482d42a5614b.js +1 -0
  209. package/dist/web/standalone/.next/static/chunks/app/api/boot/{route-d07a2c023f1aef1e.js → route-d83ba70a25a85472.js} +1 -1
  210. package/dist/web/standalone/.next/static/chunks/app/api/bridge-terminal/input/{route-d07a2c023f1aef1e.js → route-d83ba70a25a85472.js} +1 -1
  211. package/dist/web/standalone/.next/static/chunks/app/api/bridge-terminal/resize/{route-d07a2c023f1aef1e.js → route-d83ba70a25a85472.js} +1 -1
  212. package/dist/web/standalone/.next/static/chunks/app/api/bridge-terminal/stream/route-d83ba70a25a85472.js +1 -0
  213. package/dist/web/standalone/.next/static/chunks/app/api/browse-directories/route-d83ba70a25a85472.js +1 -0
  214. package/dist/web/standalone/.next/static/chunks/app/api/captures/route-d83ba70a25a85472.js +1 -0
  215. package/dist/web/standalone/.next/static/chunks/app/api/cleanup/route-d83ba70a25a85472.js +1 -0
  216. package/dist/web/standalone/.next/static/chunks/app/api/dev-mode/route-d83ba70a25a85472.js +1 -0
  217. package/dist/web/standalone/.next/static/chunks/app/api/doctor/route-d83ba70a25a85472.js +1 -0
  218. package/dist/web/standalone/.next/static/chunks/app/api/export-data/route-d83ba70a25a85472.js +1 -0
  219. package/dist/web/standalone/.next/static/chunks/app/api/files/route-d83ba70a25a85472.js +1 -0
  220. package/dist/web/standalone/.next/static/chunks/app/api/forensics/route-d83ba70a25a85472.js +1 -0
  221. package/dist/web/standalone/.next/static/chunks/app/api/git/route-d83ba70a25a85472.js +1 -0
  222. package/dist/web/standalone/.next/static/chunks/app/api/history/route-d83ba70a25a85472.js +1 -0
  223. package/dist/web/standalone/.next/static/chunks/app/api/hooks/route-d83ba70a25a85472.js +1 -0
  224. package/dist/web/standalone/.next/static/chunks/app/api/inspect/route-d83ba70a25a85472.js +1 -0
  225. package/dist/web/standalone/.next/static/chunks/app/api/knowledge/route-d83ba70a25a85472.js +1 -0
  226. package/dist/web/standalone/.next/static/chunks/app/api/live-state/route-d83ba70a25a85472.js +1 -0
  227. package/dist/web/standalone/.next/static/chunks/app/api/onboarding/route-d83ba70a25a85472.js +1 -0
  228. package/dist/web/standalone/.next/static/chunks/app/api/preferences/route-d83ba70a25a85472.js +1 -0
  229. package/dist/web/standalone/.next/static/chunks/app/api/projects/route-d83ba70a25a85472.js +1 -0
  230. package/dist/web/standalone/.next/static/chunks/app/api/recovery/route-d83ba70a25a85472.js +1 -0
  231. package/dist/web/standalone/.next/static/chunks/app/api/remote-questions/route-d83ba70a25a85472.js +1 -0
  232. package/dist/web/standalone/.next/static/chunks/app/api/session/browser/route-d83ba70a25a85472.js +1 -0
  233. package/dist/web/standalone/.next/static/chunks/app/api/session/command/route-d83ba70a25a85472.js +1 -0
  234. package/dist/web/standalone/.next/static/chunks/app/api/session/events/route-d83ba70a25a85472.js +1 -0
  235. package/dist/web/standalone/.next/static/chunks/app/api/session/manage/route-d83ba70a25a85472.js +1 -0
  236. package/dist/web/standalone/.next/static/chunks/app/api/settings-data/route-d83ba70a25a85472.js +1 -0
  237. package/dist/web/standalone/.next/static/chunks/app/api/shutdown/route-d83ba70a25a85472.js +1 -0
  238. package/dist/web/standalone/.next/static/chunks/app/api/skill-health/route-d83ba70a25a85472.js +1 -0
  239. package/dist/web/standalone/.next/static/chunks/app/api/steer/route-d83ba70a25a85472.js +1 -0
  240. package/dist/web/standalone/.next/static/chunks/app/api/switch-root/route-d83ba70a25a85472.js +1 -0
  241. package/dist/web/standalone/.next/static/chunks/app/api/terminal/input/route-d83ba70a25a85472.js +1 -0
  242. package/dist/web/standalone/.next/static/chunks/app/api/terminal/resize/route-d83ba70a25a85472.js +1 -0
  243. package/dist/web/standalone/.next/static/chunks/app/api/terminal/sessions/route-d83ba70a25a85472.js +1 -0
  244. package/dist/web/standalone/.next/static/chunks/app/api/terminal/stream/route-d83ba70a25a85472.js +1 -0
  245. package/dist/web/standalone/.next/static/chunks/app/api/terminal/upload/route-d83ba70a25a85472.js +1 -0
  246. package/dist/web/standalone/.next/static/chunks/app/api/undo/route-d83ba70a25a85472.js +1 -0
  247. package/dist/web/standalone/.next/static/chunks/app/api/update/route-d83ba70a25a85472.js +1 -0
  248. package/dist/web/standalone/.next/static/chunks/app/api/visualizer/route-d83ba70a25a85472.js +1 -0
  249. package/dist/web/standalone/.next/static/chunks/app/layout-a16c7a7ecdf0c2cf.js +1 -0
  250. package/dist/web/standalone/.next/static/chunks/app/page-b9367c5ae13b99c6.js +1 -0
  251. package/dist/web/standalone/.next/static/chunks/{main-app-2f2ee7b85712c2bd.js → main-app-fdab67f7802d7832.js} +1 -1
  252. package/dist/web/standalone/.next/static/chunks/next/dist/client/components/builtin/app-error-d83ba70a25a85472.js +1 -0
  253. package/dist/web/standalone/.next/static/chunks/next/dist/client/components/builtin/forbidden-d83ba70a25a85472.js +1 -0
  254. package/dist/web/standalone/.next/static/chunks/next/dist/client/components/builtin/global-error-459824ffb8c323dd.js +1 -0
  255. package/dist/web/standalone/.next/static/chunks/next/dist/client/components/builtin/not-found-d83ba70a25a85472.js +1 -0
  256. package/dist/web/standalone/.next/static/chunks/next/dist/client/components/builtin/unauthorized-d83ba70a25a85472.js +1 -0
  257. package/dist/web/standalone/.next/static/chunks/{webpack-fa307370fcf9fb2c.js → webpack-9014b5adb127a98a.js} +1 -1
  258. package/dist/web/standalone/.next/static/css/8a727f372cf53002.css +1 -0
  259. package/dist/web/standalone/node_modules/node-pty/build/Makefile +2 -2
  260. package/dist/web/standalone/node_modules/node-pty/build/Release/pty.node +0 -0
  261. package/dist/web/standalone/node_modules/node-pty/build/pty.target.mk +14 -14
  262. package/dist/web/standalone/node_modules/node-pty/node-addon-api/node_addon_api.target.mk +14 -14
  263. package/dist/web/standalone/node_modules/node-pty/node-addon-api/node_addon_api_except.target.mk +14 -14
  264. package/dist/web/standalone/node_modules/node-pty/node-addon-api/node_addon_api_maybe.target.mk +14 -14
  265. package/dist/web/standalone/server.js +1 -1
  266. package/package.json +4 -4
  267. package/packages/pi-ai/dist/models.custom.d.ts +173 -0
  268. package/packages/pi-ai/dist/models.custom.d.ts.map +1 -0
  269. package/packages/pi-ai/dist/models.custom.js +170 -0
  270. package/packages/pi-ai/dist/models.custom.js.map +1 -0
  271. package/packages/pi-ai/dist/models.d.ts.map +1 -1
  272. package/packages/pi-ai/dist/models.js +16 -1
  273. package/packages/pi-ai/dist/models.js.map +1 -1
  274. package/packages/pi-ai/dist/models.test.d.ts +2 -0
  275. package/packages/pi-ai/dist/models.test.d.ts.map +1 -0
  276. package/packages/pi-ai/dist/models.test.js +67 -0
  277. package/packages/pi-ai/dist/models.test.js.map +1 -0
  278. package/packages/pi-ai/src/models.custom.ts +172 -0
  279. package/packages/pi-ai/src/models.test.ts +85 -0
  280. package/packages/pi-ai/src/models.ts +17 -1
  281. package/packages/pi-coding-agent/dist/core/agent-session.d.ts +10 -3
  282. package/packages/pi-coding-agent/dist/core/agent-session.d.ts.map +1 -1
  283. package/packages/pi-coding-agent/dist/core/agent-session.js +21 -34
  284. package/packages/pi-coding-agent/dist/core/agent-session.js.map +1 -1
  285. package/packages/pi-coding-agent/dist/core/auth-storage.test.js +6 -8
  286. package/packages/pi-coding-agent/dist/core/auth-storage.test.js.map +1 -1
  287. package/packages/pi-coding-agent/dist/core/compaction/branch-summarization.d.ts +2 -2
  288. package/packages/pi-coding-agent/dist/core/compaction/branch-summarization.d.ts.map +1 -1
  289. package/packages/pi-coding-agent/dist/core/compaction/branch-summarization.js.map +1 -1
  290. package/packages/pi-coding-agent/dist/core/compaction/compaction.d.ts +2 -2
  291. package/packages/pi-coding-agent/dist/core/compaction/compaction.d.ts.map +1 -1
  292. package/packages/pi-coding-agent/dist/core/compaction/compaction.js.map +1 -1
  293. package/packages/pi-coding-agent/dist/core/compaction-orchestrator.js +4 -4
  294. package/packages/pi-coding-agent/dist/core/compaction-orchestrator.js.map +1 -1
  295. package/packages/pi-coding-agent/dist/core/extensions/index.d.ts +1 -1
  296. package/packages/pi-coding-agent/dist/core/extensions/index.d.ts.map +1 -1
  297. package/packages/pi-coding-agent/dist/core/extensions/index.js.map +1 -1
  298. package/packages/pi-coding-agent/dist/core/extensions/loader.d.ts +6 -0
  299. package/packages/pi-coding-agent/dist/core/extensions/loader.d.ts.map +1 -1
  300. package/packages/pi-coding-agent/dist/core/extensions/loader.js +80 -0
  301. package/packages/pi-coding-agent/dist/core/extensions/loader.js.map +1 -1
  302. package/packages/pi-coding-agent/dist/core/extensions/loader.test.js +63 -0
  303. package/packages/pi-coding-agent/dist/core/extensions/loader.test.js.map +1 -1
  304. package/packages/pi-coding-agent/dist/core/extensions/runner.test.js +24 -26
  305. package/packages/pi-coding-agent/dist/core/extensions/runner.test.js.map +1 -1
  306. package/packages/pi-coding-agent/dist/core/extensions/types.d.ts +37 -0
  307. package/packages/pi-coding-agent/dist/core/extensions/types.d.ts.map +1 -1
  308. package/packages/pi-coding-agent/dist/core/extensions/types.js.map +1 -1
  309. package/packages/pi-coding-agent/dist/core/fallback-resolver.d.ts.map +1 -1
  310. package/packages/pi-coding-agent/dist/core/fallback-resolver.js +2 -3
  311. package/packages/pi-coding-agent/dist/core/fallback-resolver.js.map +1 -1
  312. package/packages/pi-coding-agent/dist/core/fallback-resolver.test.js +12 -2
  313. package/packages/pi-coding-agent/dist/core/fallback-resolver.test.js.map +1 -1
  314. package/packages/pi-coding-agent/dist/core/fs-utils.test.js +29 -48
  315. package/packages/pi-coding-agent/dist/core/fs-utils.test.js.map +1 -1
  316. package/packages/pi-coding-agent/dist/core/lifecycle-hooks.d.ts +38 -0
  317. package/packages/pi-coding-agent/dist/core/lifecycle-hooks.d.ts.map +1 -0
  318. package/packages/pi-coding-agent/dist/core/lifecycle-hooks.js +192 -0
  319. package/packages/pi-coding-agent/dist/core/lifecycle-hooks.js.map +1 -0
  320. package/packages/pi-coding-agent/dist/core/lsp/client.d.ts +5 -0
  321. package/packages/pi-coding-agent/dist/core/lsp/client.d.ts.map +1 -1
  322. package/packages/pi-coding-agent/dist/core/lsp/client.js +69 -21
  323. package/packages/pi-coding-agent/dist/core/lsp/client.js.map +1 -1
  324. package/packages/pi-coding-agent/dist/core/model-registry-auth-mode.test.d.ts +2 -0
  325. package/packages/pi-coding-agent/dist/core/model-registry-auth-mode.test.d.ts.map +1 -0
  326. package/packages/pi-coding-agent/dist/core/model-registry-auth-mode.test.js +255 -0
  327. package/packages/pi-coding-agent/dist/core/model-registry-auth-mode.test.js.map +1 -0
  328. package/packages/pi-coding-agent/dist/core/model-registry.d.ts +15 -0
  329. package/packages/pi-coding-agent/dist/core/model-registry.d.ts.map +1 -1
  330. package/packages/pi-coding-agent/dist/core/model-registry.js +40 -3
  331. package/packages/pi-coding-agent/dist/core/model-registry.js.map +1 -1
  332. package/packages/pi-coding-agent/dist/core/package-commands.d.ts +25 -0
  333. package/packages/pi-coding-agent/dist/core/package-commands.d.ts.map +1 -0
  334. package/packages/pi-coding-agent/dist/core/package-commands.js +253 -0
  335. package/packages/pi-coding-agent/dist/core/package-commands.js.map +1 -0
  336. package/packages/pi-coding-agent/dist/core/package-commands.test.d.ts +2 -0
  337. package/packages/pi-coding-agent/dist/core/package-commands.test.d.ts.map +1 -0
  338. package/packages/pi-coding-agent/dist/core/package-commands.test.js +225 -0
  339. package/packages/pi-coding-agent/dist/core/package-commands.test.js.map +1 -0
  340. package/packages/pi-coding-agent/dist/core/resolve-config-value.test.js +34 -44
  341. package/packages/pi-coding-agent/dist/core/resolve-config-value.test.js.map +1 -1
  342. package/packages/pi-coding-agent/dist/core/sdk.d.ts.map +1 -1
  343. package/packages/pi-coding-agent/dist/core/sdk.js +4 -0
  344. package/packages/pi-coding-agent/dist/core/sdk.js.map +1 -1
  345. package/packages/pi-coding-agent/dist/core/session-manager.test.js +30 -34
  346. package/packages/pi-coding-agent/dist/core/session-manager.test.js.map +1 -1
  347. package/packages/pi-coding-agent/dist/core/tools/edit-diff.test.js +10 -12
  348. package/packages/pi-coding-agent/dist/core/tools/edit-diff.test.js.map +1 -1
  349. package/packages/pi-coding-agent/dist/index.d.ts +3 -1
  350. package/packages/pi-coding-agent/dist/index.d.ts.map +1 -1
  351. package/packages/pi-coding-agent/dist/index.js +1 -0
  352. package/packages/pi-coding-agent/dist/index.js.map +1 -1
  353. package/packages/pi-coding-agent/dist/main.d.ts.map +1 -1
  354. package/packages/pi-coding-agent/dist/main.js +11 -199
  355. package/packages/pi-coding-agent/dist/main.js.map +1 -1
  356. package/packages/pi-coding-agent/dist/modes/interactive/components/footer.d.ts +6 -0
  357. package/packages/pi-coding-agent/dist/modes/interactive/components/footer.d.ts.map +1 -1
  358. package/packages/pi-coding-agent/dist/modes/interactive/components/footer.js +21 -0
  359. package/packages/pi-coding-agent/dist/modes/interactive/components/footer.js.map +1 -1
  360. package/packages/pi-coding-agent/dist/modes/interactive/theme/theme.d.ts +1 -1
  361. package/packages/pi-coding-agent/dist/modes/interactive/theme/theme.d.ts.map +1 -1
  362. package/packages/pi-coding-agent/dist/modes/interactive/theme/theme.js +8 -15
  363. package/packages/pi-coding-agent/dist/modes/interactive/theme/theme.js.map +1 -1
  364. package/packages/pi-coding-agent/dist/modes/print-mode.d.ts.map +1 -1
  365. package/packages/pi-coding-agent/dist/modes/print-mode.js +45 -34
  366. package/packages/pi-coding-agent/dist/modes/print-mode.js.map +1 -1
  367. package/packages/pi-coding-agent/dist/modes/rpc/rpc-client.d.ts +1 -0
  368. package/packages/pi-coding-agent/dist/modes/rpc/rpc-client.d.ts.map +1 -1
  369. package/packages/pi-coding-agent/dist/modes/rpc/rpc-client.js +7 -2
  370. package/packages/pi-coding-agent/dist/modes/rpc/rpc-client.js.map +1 -1
  371. package/packages/pi-coding-agent/dist/modes/rpc/rpc-mode.d.ts.map +1 -1
  372. package/packages/pi-coding-agent/dist/modes/rpc/rpc-mode.js +2 -1
  373. package/packages/pi-coding-agent/dist/modes/rpc/rpc-mode.js.map +1 -1
  374. package/packages/pi-coding-agent/dist/resources/extensions/memory/storage.test.js +43 -47
  375. package/packages/pi-coding-agent/dist/resources/extensions/memory/storage.test.js.map +1 -1
  376. package/packages/pi-coding-agent/package.json +1 -1
  377. package/packages/pi-coding-agent/src/core/agent-session.ts +26 -37
  378. package/packages/pi-coding-agent/src/core/auth-storage.test.ts +7 -7
  379. package/packages/pi-coding-agent/src/core/compaction/branch-summarization.ts +2 -2
  380. package/packages/pi-coding-agent/src/core/compaction/compaction.ts +3 -3
  381. package/packages/pi-coding-agent/src/core/compaction-orchestrator.ts +4 -4
  382. package/packages/pi-coding-agent/src/core/extensions/index.ts +5 -0
  383. package/packages/pi-coding-agent/src/core/extensions/loader.test.ts +96 -0
  384. package/packages/pi-coding-agent/src/core/extensions/loader.ts +89 -0
  385. package/packages/pi-coding-agent/src/core/extensions/runner.test.ts +26 -26
  386. package/packages/pi-coding-agent/src/core/extensions/types.ts +44 -0
  387. package/packages/pi-coding-agent/src/core/fallback-resolver.test.ts +15 -2
  388. package/packages/pi-coding-agent/src/core/fallback-resolver.ts +2 -3
  389. package/packages/pi-coding-agent/src/core/fs-utils.test.ts +31 -43
  390. package/packages/pi-coding-agent/src/core/lifecycle-hooks.ts +274 -0
  391. package/packages/pi-coding-agent/src/core/lsp/client.ts +83 -21
  392. package/packages/pi-coding-agent/src/core/model-registry-auth-mode.test.ts +288 -0
  393. package/packages/pi-coding-agent/src/core/model-registry.ts +39 -3
  394. package/packages/pi-coding-agent/src/core/package-commands.test.ts +240 -0
  395. package/packages/pi-coding-agent/src/core/package-commands.ts +310 -0
  396. package/packages/pi-coding-agent/src/core/resolve-config-value.test.ts +40 -45
  397. package/packages/pi-coding-agent/src/core/sdk.ts +4 -0
  398. package/packages/pi-coding-agent/src/core/session-manager.test.ts +33 -33
  399. package/packages/pi-coding-agent/src/core/tools/edit-diff.test.ts +17 -17
  400. package/packages/pi-coding-agent/src/index.ts +7 -0
  401. package/packages/pi-coding-agent/src/main.ts +11 -232
  402. package/packages/pi-coding-agent/src/modes/interactive/components/footer.ts +20 -0
  403. package/packages/pi-coding-agent/src/modes/interactive/theme/theme.ts +9 -16
  404. package/packages/pi-coding-agent/src/modes/print-mode.ts +42 -32
  405. package/packages/pi-coding-agent/src/modes/rpc/rpc-client.ts +8 -2
  406. package/packages/pi-coding-agent/src/modes/rpc/rpc-mode.ts +2 -1
  407. package/packages/pi-coding-agent/src/resources/extensions/memory/storage.test.ts +74 -74
  408. package/pkg/dist/modes/interactive/theme/theme.d.ts +1 -1
  409. package/pkg/dist/modes/interactive/theme/theme.d.ts.map +1 -1
  410. package/pkg/dist/modes/interactive/theme/theme.js +8 -15
  411. package/pkg/dist/modes/interactive/theme/theme.js.map +1 -1
  412. package/pkg/package.json +1 -1
  413. package/src/resources/extensions/bg-shell/overlay.ts +4 -0
  414. package/src/resources/extensions/github-sync/sync.ts +2 -1
  415. package/src/resources/extensions/gsd/auto/loop-deps.ts +0 -8
  416. package/src/resources/extensions/gsd/auto/loop.ts +0 -2
  417. package/src/resources/extensions/gsd/auto/phases.ts +7 -20
  418. package/src/resources/extensions/gsd/auto/types.ts +0 -1
  419. package/src/resources/extensions/gsd/auto-dashboard.ts +20 -16
  420. package/src/resources/extensions/gsd/auto-direct-dispatch.ts +34 -19
  421. package/src/resources/extensions/gsd/auto-dispatch.ts +38 -21
  422. package/src/resources/extensions/gsd/auto-post-unit.ts +150 -15
  423. package/src/resources/extensions/gsd/auto-prompts.ts +186 -103
  424. package/src/resources/extensions/gsd/auto-recovery.ts +77 -142
  425. package/src/resources/extensions/gsd/auto-start.ts +14 -0
  426. package/src/resources/extensions/gsd/auto-supervisor.ts +14 -0
  427. package/src/resources/extensions/gsd/auto-timeout-recovery.ts +6 -7
  428. package/src/resources/extensions/gsd/auto-verification.ts +4 -9
  429. package/src/resources/extensions/gsd/auto-worktree.ts +126 -30
  430. package/src/resources/extensions/gsd/auto.ts +0 -9
  431. package/src/resources/extensions/gsd/bootstrap/db-tools.ts +675 -4
  432. package/src/resources/extensions/gsd/bootstrap/dynamic-tools.ts +31 -3
  433. package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +7 -0
  434. package/src/resources/extensions/gsd/commands/catalog.ts +3 -1
  435. package/src/resources/extensions/gsd/commands/handlers/ops.ts +15 -1
  436. package/src/resources/extensions/gsd/commands/handlers/workflow.ts +8 -0
  437. package/src/resources/extensions/gsd/commands-handlers.ts +1 -1
  438. package/src/resources/extensions/gsd/commands-maintenance.ts +86 -3
  439. package/src/resources/extensions/gsd/dashboard-overlay.ts +17 -13
  440. package/src/resources/extensions/gsd/db-writer.ts +105 -4
  441. package/src/resources/extensions/gsd/dispatch-guard.ts +32 -30
  442. package/src/resources/extensions/gsd/doctor-checks.ts +25 -11
  443. package/src/resources/extensions/gsd/doctor-environment.ts +31 -0
  444. package/src/resources/extensions/gsd/doctor-types.ts +0 -23
  445. package/src/resources/extensions/gsd/doctor.ts +45 -295
  446. package/src/resources/extensions/gsd/file-watcher.ts +4 -1
  447. package/src/resources/extensions/gsd/files.ts +16 -220
  448. package/src/resources/extensions/gsd/git-service.ts +4 -0
  449. package/src/resources/extensions/gsd/gitignore.ts +4 -0
  450. package/src/resources/extensions/gsd/gsd-db.ts +1157 -370
  451. package/src/resources/extensions/gsd/guided-flow.ts +20 -8
  452. package/src/resources/extensions/gsd/markdown-renderer.ts +1098 -0
  453. package/src/resources/extensions/gsd/md-importer.ts +211 -2
  454. package/src/resources/extensions/gsd/native-git-bridge.ts +12 -1
  455. package/src/resources/extensions/gsd/parallel-eligibility.ts +14 -18
  456. package/src/resources/extensions/gsd/parallel-orchestrator.ts +43 -0
  457. package/src/resources/extensions/gsd/parsers-legacy.ts +271 -0
  458. package/src/resources/extensions/gsd/preferences-types.ts +3 -0
  459. package/src/resources/extensions/gsd/preferences-validation.ts +9 -0
  460. package/src/resources/extensions/gsd/preferences.ts +1 -0
  461. package/src/resources/extensions/gsd/prompts/complete-slice.md +22 -9
  462. package/src/resources/extensions/gsd/prompts/discuss.md +2 -2
  463. package/src/resources/extensions/gsd/prompts/execute-task.md +15 -5
  464. package/src/resources/extensions/gsd/prompts/guided-complete-slice.md +1 -1
  465. package/src/resources/extensions/gsd/prompts/guided-execute-task.md +1 -1
  466. package/src/resources/extensions/gsd/prompts/guided-plan-milestone.md +1 -1
  467. package/src/resources/extensions/gsd/prompts/plan-milestone.md +6 -10
  468. package/src/resources/extensions/gsd/prompts/plan-slice.md +4 -7
  469. package/src/resources/extensions/gsd/prompts/reactive-execute.md +3 -3
  470. package/src/resources/extensions/gsd/prompts/reassess-roadmap.md +6 -7
  471. package/src/resources/extensions/gsd/prompts/replan-slice.md +6 -6
  472. package/src/resources/extensions/gsd/reactive-graph.ts +33 -3
  473. package/src/resources/extensions/gsd/skill-health.ts +2 -1
  474. package/src/resources/extensions/gsd/state.ts +547 -29
  475. package/src/resources/extensions/gsd/tests/all-milestones-complete-merge.test.ts +99 -99
  476. package/src/resources/extensions/gsd/tests/atomic-task-closeout.test.ts +8 -120
  477. package/src/resources/extensions/gsd/tests/auto-lock-creation.test.ts +14 -16
  478. package/src/resources/extensions/gsd/tests/auto-loop.test.ts +20 -11
  479. package/src/resources/extensions/gsd/tests/auto-paused-session-validation.test.ts +43 -57
  480. package/src/resources/extensions/gsd/tests/auto-preflight.test.ts +11 -13
  481. package/src/resources/extensions/gsd/tests/auto-recovery.test.ts +600 -513
  482. package/src/resources/extensions/gsd/tests/auto-secrets-gate.test.ts +73 -75
  483. package/src/resources/extensions/gsd/tests/auto-start-needs-discussion.test.ts +34 -56
  484. package/src/resources/extensions/gsd/tests/auto-stash-merge.test.ts +121 -0
  485. package/src/resources/extensions/gsd/tests/auto-worktree-milestone-merge.test.ts +540 -668
  486. package/src/resources/extensions/gsd/tests/auto-worktree.test.ts +165 -143
  487. package/src/resources/extensions/gsd/tests/cache-staleness-regression.test.ts +29 -52
  488. package/src/resources/extensions/gsd/tests/captures.test.ts +148 -176
  489. package/src/resources/extensions/gsd/tests/claude-import-tui.test.ts +32 -33
  490. package/src/resources/extensions/gsd/tests/collect-from-manifest.test.ts +141 -143
  491. package/src/resources/extensions/gsd/tests/commands-inspect-open-db.test.ts +25 -25
  492. package/src/resources/extensions/gsd/tests/commands-logs.test.ts +81 -81
  493. package/src/resources/extensions/gsd/tests/complete-milestone.test.ts +39 -60
  494. package/src/resources/extensions/gsd/tests/complete-slice.test.ts +375 -0
  495. package/src/resources/extensions/gsd/tests/complete-task.test.ts +387 -0
  496. package/src/resources/extensions/gsd/tests/context-store.test.ts +354 -367
  497. package/src/resources/extensions/gsd/tests/continue-here.test.ts +68 -72
  498. package/src/resources/extensions/gsd/tests/cost-projection.test.ts +92 -106
  499. package/src/resources/extensions/gsd/tests/crash-recovery.test.ts +27 -35
  500. package/src/resources/extensions/gsd/tests/custom-engine-loop-integration.test.ts +0 -2
  501. package/src/resources/extensions/gsd/tests/dashboard-budget.test.ts +220 -237
  502. package/src/resources/extensions/gsd/tests/db-writer.test.ts +390 -420
  503. package/src/resources/extensions/gsd/tests/definition-loader.test.ts +76 -92
  504. package/src/resources/extensions/gsd/tests/derive-state-crossval.test.ts +512 -0
  505. package/src/resources/extensions/gsd/tests/derive-state-db.test.ts +644 -84
  506. package/src/resources/extensions/gsd/tests/derive-state-deps.test.ts +78 -101
  507. package/src/resources/extensions/gsd/tests/derive-state.test.ts +192 -227
  508. package/src/resources/extensions/gsd/tests/detection.test.ts +232 -278
  509. package/src/resources/extensions/gsd/tests/dev-engine-wrapper.test.ts +30 -34
  510. package/src/resources/extensions/gsd/tests/dispatch-guard.test.ts +192 -161
  511. package/src/resources/extensions/gsd/tests/dispatch-missing-task-plans.test.ts +43 -49
  512. package/src/resources/extensions/gsd/tests/dispatch-uat-last-completed.test.ts +28 -32
  513. package/src/resources/extensions/gsd/tests/doctor-completion-deferral.test.ts +30 -90
  514. package/src/resources/extensions/gsd/tests/doctor-delimiter-fix.test.ts +34 -38
  515. package/src/resources/extensions/gsd/tests/doctor-enhancements.test.ts +57 -80
  516. package/src/resources/extensions/gsd/tests/doctor-environment-worktree.test.ts +164 -0
  517. package/src/resources/extensions/gsd/tests/doctor-environment.test.ts +72 -97
  518. package/src/resources/extensions/gsd/tests/doctor-fixlevel.test.ts +55 -153
  519. package/src/resources/extensions/gsd/tests/doctor-git.test.ts +104 -145
  520. package/src/resources/extensions/gsd/tests/doctor-proactive.test.ts +84 -106
  521. package/src/resources/extensions/gsd/tests/doctor-roadmap-summary-atomicity.test.ts +53 -97
  522. package/src/resources/extensions/gsd/tests/doctor-runtime.test.ts +72 -93
  523. package/src/resources/extensions/gsd/tests/doctor.test.ts +109 -149
  524. package/src/resources/extensions/gsd/tests/ensure-db-open.test.ts +123 -131
  525. package/src/resources/extensions/gsd/tests/exit-command.test.ts +20 -24
  526. package/src/resources/extensions/gsd/tests/feature-branch-lifecycle-integration.test.ts +48 -57
  527. package/src/resources/extensions/gsd/tests/files-loadfile-eisdir.test.ts +5 -7
  528. package/src/resources/extensions/gsd/tests/flag-file-db.test.ts +278 -0
  529. package/src/resources/extensions/gsd/tests/freeform-decisions.test.ts +232 -0
  530. package/src/resources/extensions/gsd/tests/git-locale.test.ts +13 -27
  531. package/src/resources/extensions/gsd/tests/git-service.test.ts +291 -390
  532. package/src/resources/extensions/gsd/tests/gitignore-tracked-gsd.test.ts +31 -39
  533. package/src/resources/extensions/gsd/tests/graph-operations.test.ts +63 -69
  534. package/src/resources/extensions/gsd/tests/gsd-db.test.ts +255 -264
  535. package/src/resources/extensions/gsd/tests/gsd-inspect.test.ts +108 -119
  536. package/src/resources/extensions/gsd/tests/gsd-recover.test.ts +440 -0
  537. package/src/resources/extensions/gsd/tests/gsd-tools.test.ts +229 -262
  538. package/src/resources/extensions/gsd/tests/headless-answers.test.ts +13 -13
  539. package/src/resources/extensions/gsd/tests/health-widget.test.ts +29 -37
  540. package/src/resources/extensions/gsd/tests/idle-recovery.test.ts +81 -270
  541. package/src/resources/extensions/gsd/tests/init-wizard.test.ts +16 -18
  542. package/src/resources/extensions/gsd/tests/integration-edge.test.ts +41 -46
  543. package/src/resources/extensions/gsd/tests/integration-lifecycle.test.ts +42 -53
  544. package/src/resources/extensions/gsd/tests/integration-mixed-milestones.test.ts +75 -91
  545. package/src/resources/extensions/gsd/tests/integration-proof.test.ts +643 -0
  546. package/src/resources/extensions/gsd/tests/journal-integration.test.ts +0 -3
  547. package/src/resources/extensions/gsd/tests/markdown-renderer.test.ts +1161 -0
  548. package/src/resources/extensions/gsd/tests/md-importer.test.ts +101 -125
  549. package/src/resources/extensions/gsd/tests/memory-extractor.test.ts +45 -54
  550. package/src/resources/extensions/gsd/tests/memory-store.test.ts +81 -94
  551. package/src/resources/extensions/gsd/tests/migrate-command.test.ts +57 -66
  552. package/src/resources/extensions/gsd/tests/migrate-hierarchy.test.ts +429 -0
  553. package/src/resources/extensions/gsd/tests/migrate-parser.test.ts +161 -170
  554. package/src/resources/extensions/gsd/tests/migrate-transformer.test.ts +125 -141
  555. package/src/resources/extensions/gsd/tests/migrate-validator-parsers.test.ts +107 -131
  556. package/src/resources/extensions/gsd/tests/migrate-writer-integration.test.ts +89 -97
  557. package/src/resources/extensions/gsd/tests/migrate-writer.test.ts +127 -164
  558. package/src/resources/extensions/gsd/tests/must-have-parser.test.ts +81 -94
  559. package/src/resources/extensions/gsd/tests/none-mode-gates.test.ts +35 -36
  560. package/src/resources/extensions/gsd/tests/overrides.test.ts +99 -106
  561. package/src/resources/extensions/gsd/tests/parallel-crash-recovery.test.ts +40 -47
  562. package/src/resources/extensions/gsd/tests/parallel-worker-monitoring.test.ts +25 -28
  563. package/src/resources/extensions/gsd/tests/parallel-workers-multi-milestone-e2e.test.ts +66 -83
  564. package/src/resources/extensions/gsd/tests/park-edge-cases.test.ts +54 -77
  565. package/src/resources/extensions/gsd/tests/park-milestone.test.ts +68 -115
  566. package/src/resources/extensions/gsd/tests/parsers.test.ts +548 -612
  567. package/src/resources/extensions/gsd/tests/paths.test.ts +72 -87
  568. package/src/resources/extensions/gsd/tests/plan-milestone.test.ts +176 -113
  569. package/src/resources/extensions/gsd/tests/plan-slice-prompt.test.ts +7 -0
  570. package/src/resources/extensions/gsd/tests/plan-slice.test.ts +179 -0
  571. package/src/resources/extensions/gsd/tests/plan-task.test.ts +145 -0
  572. package/src/resources/extensions/gsd/tests/planning-crossval.test.ts +305 -0
  573. package/src/resources/extensions/gsd/tests/post-unit-hooks.test.ts +77 -117
  574. package/src/resources/extensions/gsd/tests/prompt-contracts.test.ts +139 -0
  575. package/src/resources/extensions/gsd/tests/prompt-db.test.ts +56 -56
  576. package/src/resources/extensions/gsd/tests/queue-draft-detection.test.ts +93 -119
  577. package/src/resources/extensions/gsd/tests/queue-order.test.ts +70 -82
  578. package/src/resources/extensions/gsd/tests/queue-reorder-e2e.test.ts +42 -55
  579. package/src/resources/extensions/gsd/tests/quick-auto-guard.test.ts +100 -0
  580. package/src/resources/extensions/gsd/tests/quick-branch-lifecycle.test.ts +45 -73
  581. package/src/resources/extensions/gsd/tests/reassess-handler.test.ts +325 -0
  582. package/src/resources/extensions/gsd/tests/reassess-prompt.test.ts +28 -38
  583. package/src/resources/extensions/gsd/tests/replan-handler.test.ts +410 -0
  584. package/src/resources/extensions/gsd/tests/replan-slice.test.ts +73 -80
  585. package/src/resources/extensions/gsd/tests/repo-identity-worktree.test.ts +71 -74
  586. package/src/resources/extensions/gsd/tests/requirements.test.ts +70 -75
  587. package/src/resources/extensions/gsd/tests/retry-state-reset.test.ts +44 -66
  588. package/src/resources/extensions/gsd/tests/roadmap-parse-regression.test.ts +114 -181
  589. package/src/resources/extensions/gsd/tests/roadmap-slices.test.ts +1 -1
  590. package/src/resources/extensions/gsd/tests/rogue-file-detection.test.ts +296 -0
  591. package/src/resources/extensions/gsd/tests/rule-registry.test.ts +63 -65
  592. package/src/resources/extensions/gsd/tests/run-uat.test.ts +66 -128
  593. package/src/resources/extensions/gsd/tests/schema-v9-sequence.test.ts +176 -0
  594. package/src/resources/extensions/gsd/tests/session-lock-multipath.test.ts +18 -25
  595. package/src/resources/extensions/gsd/tests/session-lock-regression.test.ts +37 -44
  596. package/src/resources/extensions/gsd/tests/shared-wal.test.ts +209 -0
  597. package/src/resources/extensions/gsd/tests/sqlite-unavailable-gate.test.ts +63 -0
  598. package/src/resources/extensions/gsd/tests/stalled-tool-recovery.test.ts +6 -8
  599. package/src/resources/extensions/gsd/tests/symlink-numbered-variants.test.ts +22 -28
  600. package/src/resources/extensions/gsd/tests/token-cost-display.test.ts +118 -0
  601. package/src/resources/extensions/gsd/tests/token-savings.test.ts +54 -56
  602. package/src/resources/extensions/gsd/tests/tool-call-loop-guard.test.ts +23 -25
  603. package/src/resources/extensions/gsd/tests/tool-naming.test.ts +19 -13
  604. package/src/resources/extensions/gsd/tests/undo.test.ts +321 -1
  605. package/src/resources/extensions/gsd/tests/unique-milestone-ids.test.ts +66 -82
  606. package/src/resources/extensions/gsd/tests/unit-runtime.test.ts +46 -47
  607. package/src/resources/extensions/gsd/tests/validate-milestone.test.ts +1 -1
  608. package/src/resources/extensions/gsd/tests/verification-evidence.test.ts +0 -142
  609. package/src/resources/extensions/gsd/tests/visualizer-critical-path.test.ts +20 -22
  610. package/src/resources/extensions/gsd/tests/visualizer-data.test.ts +84 -86
  611. package/src/resources/extensions/gsd/tests/visualizer-overlay.test.ts +41 -43
  612. package/src/resources/extensions/gsd/tests/visualizer-views.test.ts +94 -96
  613. package/src/resources/extensions/gsd/tests/windows-path-normalization.test.ts +11 -13
  614. package/src/resources/extensions/gsd/tests/worker-registry.test.ts +27 -29
  615. package/src/resources/extensions/gsd/tests/workflow-templates.test.ts +50 -52
  616. package/src/resources/extensions/gsd/tests/worktree-bugfix.test.ts +10 -13
  617. package/src/resources/extensions/gsd/tests/worktree-db-integration.test.ts +14 -18
  618. package/src/resources/extensions/gsd/tests/worktree-db.test.ts +38 -39
  619. package/src/resources/extensions/gsd/tests/worktree-e2e.test.ts +17 -21
  620. package/src/resources/extensions/gsd/tests/worktree-health-dispatch.test.ts +12 -5
  621. package/src/resources/extensions/gsd/tests/worktree-health.test.ts +25 -30
  622. package/src/resources/extensions/gsd/tests/worktree-integration.test.ts +30 -37
  623. package/src/resources/extensions/gsd/tests/worktree-symlink-removal.test.ts +15 -22
  624. package/src/resources/extensions/gsd/tests/worktree-sync-milestones.test.ts +59 -66
  625. package/src/resources/extensions/gsd/tests/worktree.test.ts +44 -50
  626. package/src/resources/extensions/gsd/tools/complete-milestone.ts +176 -0
  627. package/src/resources/extensions/gsd/tools/complete-slice.ts +300 -0
  628. package/src/resources/extensions/gsd/tools/complete-task.ts +245 -0
  629. package/src/resources/extensions/gsd/tools/plan-milestone.ts +249 -0
  630. package/src/resources/extensions/gsd/tools/plan-slice.ts +194 -0
  631. package/src/resources/extensions/gsd/tools/plan-task.ts +116 -0
  632. package/src/resources/extensions/gsd/tools/reassess-roadmap.ts +203 -0
  633. package/src/resources/extensions/gsd/tools/replan-slice.ts +192 -0
  634. package/src/resources/extensions/gsd/triage-resolution.ts +20 -1
  635. package/src/resources/extensions/gsd/types.ts +50 -0
  636. package/src/resources/extensions/gsd/undo.ts +247 -3
  637. package/src/resources/extensions/gsd/visualizer-data.ts +54 -17
  638. package/src/resources/extensions/gsd/workspace-index.ts +64 -46
  639. package/dist/resources/extensions/gsd/auto-observability.js +0 -56
  640. package/dist/resources/extensions/gsd/observability-validator.js +0 -422
  641. package/dist/resources/extensions/gsd/roadmap-mutations.js +0 -110
  642. package/dist/web/standalone/.next/static/VvclDCW6TAWjEyLU-EYL1/_buildManifest.js +0 -1
  643. package/dist/web/standalone/.next/static/chunks/app/_not-found/page-e07acdb7dd069836.js +0 -1
  644. package/dist/web/standalone/.next/static/chunks/app/api/bridge-terminal/stream/route-d07a2c023f1aef1e.js +0 -1
  645. package/dist/web/standalone/.next/static/chunks/app/api/browse-directories/route-d07a2c023f1aef1e.js +0 -1
  646. package/dist/web/standalone/.next/static/chunks/app/api/captures/route-d07a2c023f1aef1e.js +0 -1
  647. package/dist/web/standalone/.next/static/chunks/app/api/cleanup/route-d07a2c023f1aef1e.js +0 -1
  648. package/dist/web/standalone/.next/static/chunks/app/api/dev-mode/route-d07a2c023f1aef1e.js +0 -1
  649. package/dist/web/standalone/.next/static/chunks/app/api/doctor/route-d07a2c023f1aef1e.js +0 -1
  650. package/dist/web/standalone/.next/static/chunks/app/api/export-data/route-d07a2c023f1aef1e.js +0 -1
  651. package/dist/web/standalone/.next/static/chunks/app/api/files/route-d07a2c023f1aef1e.js +0 -1
  652. package/dist/web/standalone/.next/static/chunks/app/api/forensics/route-d07a2c023f1aef1e.js +0 -1
  653. package/dist/web/standalone/.next/static/chunks/app/api/git/route-d07a2c023f1aef1e.js +0 -1
  654. package/dist/web/standalone/.next/static/chunks/app/api/history/route-d07a2c023f1aef1e.js +0 -1
  655. package/dist/web/standalone/.next/static/chunks/app/api/hooks/route-d07a2c023f1aef1e.js +0 -1
  656. package/dist/web/standalone/.next/static/chunks/app/api/inspect/route-d07a2c023f1aef1e.js +0 -1
  657. package/dist/web/standalone/.next/static/chunks/app/api/knowledge/route-d07a2c023f1aef1e.js +0 -1
  658. package/dist/web/standalone/.next/static/chunks/app/api/live-state/route-d07a2c023f1aef1e.js +0 -1
  659. package/dist/web/standalone/.next/static/chunks/app/api/onboarding/route-d07a2c023f1aef1e.js +0 -1
  660. package/dist/web/standalone/.next/static/chunks/app/api/preferences/route-d07a2c023f1aef1e.js +0 -1
  661. package/dist/web/standalone/.next/static/chunks/app/api/projects/route-d07a2c023f1aef1e.js +0 -1
  662. package/dist/web/standalone/.next/static/chunks/app/api/recovery/route-d07a2c023f1aef1e.js +0 -1
  663. package/dist/web/standalone/.next/static/chunks/app/api/remote-questions/route-d07a2c023f1aef1e.js +0 -1
  664. package/dist/web/standalone/.next/static/chunks/app/api/session/browser/route-d07a2c023f1aef1e.js +0 -1
  665. package/dist/web/standalone/.next/static/chunks/app/api/session/command/route-d07a2c023f1aef1e.js +0 -1
  666. package/dist/web/standalone/.next/static/chunks/app/api/session/events/route-d07a2c023f1aef1e.js +0 -1
  667. package/dist/web/standalone/.next/static/chunks/app/api/session/manage/route-d07a2c023f1aef1e.js +0 -1
  668. package/dist/web/standalone/.next/static/chunks/app/api/settings-data/route-d07a2c023f1aef1e.js +0 -1
  669. package/dist/web/standalone/.next/static/chunks/app/api/shutdown/route-d07a2c023f1aef1e.js +0 -1
  670. package/dist/web/standalone/.next/static/chunks/app/api/skill-health/route-d07a2c023f1aef1e.js +0 -1
  671. package/dist/web/standalone/.next/static/chunks/app/api/steer/route-d07a2c023f1aef1e.js +0 -1
  672. package/dist/web/standalone/.next/static/chunks/app/api/terminal/input/route-d07a2c023f1aef1e.js +0 -1
  673. package/dist/web/standalone/.next/static/chunks/app/api/terminal/resize/route-d07a2c023f1aef1e.js +0 -1
  674. package/dist/web/standalone/.next/static/chunks/app/api/terminal/sessions/route-d07a2c023f1aef1e.js +0 -1
  675. package/dist/web/standalone/.next/static/chunks/app/api/terminal/stream/route-d07a2c023f1aef1e.js +0 -1
  676. package/dist/web/standalone/.next/static/chunks/app/api/terminal/upload/route-d07a2c023f1aef1e.js +0 -1
  677. package/dist/web/standalone/.next/static/chunks/app/api/undo/route-d07a2c023f1aef1e.js +0 -1
  678. package/dist/web/standalone/.next/static/chunks/app/api/update/route-d07a2c023f1aef1e.js +0 -1
  679. package/dist/web/standalone/.next/static/chunks/app/api/visualizer/route-d07a2c023f1aef1e.js +0 -1
  680. package/dist/web/standalone/.next/static/chunks/app/layout-745c6ed5fea5fb06.js +0 -1
  681. package/dist/web/standalone/.next/static/chunks/app/page-801b53eff6e83579.js +0 -1
  682. package/dist/web/standalone/.next/static/chunks/next/dist/client/components/builtin/app-error-d07a2c023f1aef1e.js +0 -1
  683. package/dist/web/standalone/.next/static/chunks/next/dist/client/components/builtin/forbidden-d07a2c023f1aef1e.js +0 -1
  684. package/dist/web/standalone/.next/static/chunks/next/dist/client/components/builtin/global-error-e6255954dccfcf0a.js +0 -1
  685. package/dist/web/standalone/.next/static/chunks/next/dist/client/components/builtin/not-found-d07a2c023f1aef1e.js +0 -1
  686. package/dist/web/standalone/.next/static/chunks/next/dist/client/components/builtin/unauthorized-d07a2c023f1aef1e.js +0 -1
  687. package/dist/web/standalone/.next/static/css/123c0bb039697968.css +0 -1
  688. package/src/resources/extensions/gsd/auto-observability.ts +0 -74
  689. package/src/resources/extensions/gsd/observability-validator.ts +0 -456
  690. package/src/resources/extensions/gsd/roadmap-mutations.ts +0 -134
  691. package/src/resources/extensions/gsd/tests/doctor-task-done-missing-summary-slice-loop.test.ts +0 -174
  692. package/src/resources/extensions/gsd/tests/plan-quality-validator.test.ts +0 -474
  693. /package/dist/web/standalone/.next/static/{VvclDCW6TAWjEyLU-EYL1 → alS4hoANx0TK4UVZY27da}/_ssgManifest.js +0 -0
@@ -13,9 +13,18 @@ import {
13
13
  selfHealRuntimeRecords,
14
14
  hasImplementationArtifacts,
15
15
  } from "../auto-recovery.ts";
16
- import { parseRoadmap, clearParseCache } from "../files.ts";
16
+ import { parseRoadmap, parsePlan } from "../parsers-legacy.ts";
17
+ import { parseTaskPlanFile, clearParseCache } from "../files.ts";
17
18
  import { invalidateAllCaches } from "../cache.ts";
18
19
  import { deriveState, invalidateStateCache } from "../state.ts";
20
+ import {
21
+ openDatabase,
22
+ closeDatabase,
23
+ insertMilestone,
24
+ insertSlice,
25
+ insertTask,
26
+ } from "../gsd-db.ts";
27
+ import { renderPlanFromDb } from "../markdown-renderer.ts";
19
28
 
20
29
  function makeTmpBase(): string {
21
30
  const base = join(tmpdir(), `gsd-test-${randomUUID()}`);
@@ -30,526 +39,616 @@ function cleanup(base: string): void {
30
39
 
31
40
  // ─── resolveExpectedArtifactPath ──────────────────────────────────────────
32
41
 
33
- test("resolveExpectedArtifactPath returns correct path for research-milestone", () => {
42
+ test("resolveExpectedArtifactPath returns correct path for research-milestone", (t) => {
34
43
  const base = makeTmpBase();
35
- try {
36
- const result = resolveExpectedArtifactPath("research-milestone", "M001", base);
37
- assert.ok(result);
38
- assert.ok(result!.includes("M001"));
39
- assert.ok(result!.includes("RESEARCH"));
40
- } finally {
41
- cleanup(base);
42
- }
44
+ t.after(() => cleanup(base));
45
+
46
+ const result = resolveExpectedArtifactPath("research-milestone", "M001", base);
47
+ assert.ok(result);
48
+ assert.ok(result!.includes("M001"));
49
+ assert.ok(result!.includes("RESEARCH"));
43
50
  });
44
51
 
45
- test("resolveExpectedArtifactPath returns correct path for execute-task", () => {
52
+ test("resolveExpectedArtifactPath returns correct path for execute-task", (t) => {
46
53
  const base = makeTmpBase();
47
- try {
48
- const result = resolveExpectedArtifactPath("execute-task", "M001/S01/T01", base);
49
- assert.ok(result);
50
- assert.ok(result!.includes("tasks"));
51
- assert.ok(result!.includes("SUMMARY"));
52
- } finally {
53
- cleanup(base);
54
- }
54
+ t.after(() => cleanup(base));
55
+
56
+ const result = resolveExpectedArtifactPath("execute-task", "M001/S01/T01", base);
57
+ assert.ok(result);
58
+ assert.ok(result!.includes("tasks"));
59
+ assert.ok(result!.includes("SUMMARY"));
55
60
  });
56
61
 
57
- test("resolveExpectedArtifactPath returns correct path for complete-slice", () => {
62
+ test("resolveExpectedArtifactPath returns correct path for complete-slice", (t) => {
58
63
  const base = makeTmpBase();
59
- try {
60
- const result = resolveExpectedArtifactPath("complete-slice", "M001/S01", base);
61
- assert.ok(result);
62
- assert.ok(result!.includes("SUMMARY"));
63
- } finally {
64
- cleanup(base);
65
- }
64
+ t.after(() => cleanup(base));
65
+
66
+ const result = resolveExpectedArtifactPath("complete-slice", "M001/S01", base);
67
+ assert.ok(result);
68
+ assert.ok(result!.includes("SUMMARY"));
66
69
  });
67
70
 
68
- test("resolveExpectedArtifactPath returns correct path for plan-slice", () => {
71
+ test("resolveExpectedArtifactPath returns correct path for plan-slice", (t) => {
69
72
  const base = makeTmpBase();
70
- try {
71
- const result = resolveExpectedArtifactPath("plan-slice", "M001/S01", base);
72
- assert.ok(result);
73
- assert.ok(result!.includes("PLAN"));
74
- } finally {
75
- cleanup(base);
76
- }
73
+ t.after(() => cleanup(base));
74
+
75
+ const result = resolveExpectedArtifactPath("plan-slice", "M001/S01", base);
76
+ assert.ok(result);
77
+ assert.ok(result!.includes("PLAN"));
77
78
  });
78
79
 
79
- test("resolveExpectedArtifactPath returns null for unknown type", () => {
80
+ test("resolveExpectedArtifactPath returns null for unknown type", (t) => {
80
81
  const base = makeTmpBase();
81
- try {
82
- const result = resolveExpectedArtifactPath("unknown-type", "M001", base);
83
- assert.equal(result, null);
84
- } finally {
85
- cleanup(base);
86
- }
82
+ t.after(() => cleanup(base));
83
+
84
+ const result = resolveExpectedArtifactPath("unknown-type", "M001", base);
85
+ assert.equal(result, null);
87
86
  });
88
87
 
89
- test("resolveExpectedArtifactPath returns correct path for all milestone-level types", () => {
88
+ test("resolveExpectedArtifactPath returns correct path for all milestone-level types", (t) => {
90
89
  const base = makeTmpBase();
91
- try {
92
- const planResult = resolveExpectedArtifactPath("plan-milestone", "M001", base);
93
- assert.ok(planResult);
94
- assert.ok(planResult!.includes("ROADMAP"));
90
+ t.after(() => cleanup(base));
95
91
 
96
- const completeResult = resolveExpectedArtifactPath("complete-milestone", "M001", base);
97
- assert.ok(completeResult);
98
- assert.ok(completeResult!.includes("SUMMARY"));
99
- } finally {
100
- cleanup(base);
101
- }
92
+ const planResult = resolveExpectedArtifactPath("plan-milestone", "M001", base);
93
+ assert.ok(planResult);
94
+ assert.ok(planResult!.includes("ROADMAP"));
95
+
96
+ const completeResult = resolveExpectedArtifactPath("complete-milestone", "M001", base);
97
+ assert.ok(completeResult);
98
+ assert.ok(completeResult!.includes("SUMMARY"));
102
99
  });
103
100
 
104
- test("resolveExpectedArtifactPath returns correct path for all slice-level types", () => {
101
+ test("resolveExpectedArtifactPath returns correct path for all slice-level types", (t) => {
105
102
  const base = makeTmpBase();
106
- try {
107
- const researchResult = resolveExpectedArtifactPath("research-slice", "M001/S01", base);
108
- assert.ok(researchResult);
109
- assert.ok(researchResult!.includes("RESEARCH"));
103
+ t.after(() => cleanup(base));
110
104
 
111
- const assessResult = resolveExpectedArtifactPath("reassess-roadmap", "M001/S01", base);
112
- assert.ok(assessResult);
113
- assert.ok(assessResult!.includes("ASSESSMENT"));
105
+ const researchResult = resolveExpectedArtifactPath("research-slice", "M001/S01", base);
106
+ assert.ok(researchResult);
107
+ assert.ok(researchResult!.includes("RESEARCH"));
114
108
 
115
- const uatResult = resolveExpectedArtifactPath("run-uat", "M001/S01", base);
116
- assert.ok(uatResult);
117
- assert.ok(uatResult!.includes("UAT-RESULT"));
118
- } finally {
119
- cleanup(base);
120
- }
109
+ const assessResult = resolveExpectedArtifactPath("reassess-roadmap", "M001/S01", base);
110
+ assert.ok(assessResult);
111
+ assert.ok(assessResult!.includes("ASSESSMENT"));
112
+
113
+ const uatResult = resolveExpectedArtifactPath("run-uat", "M001/S01", base);
114
+ assert.ok(uatResult);
115
+ assert.ok(uatResult!.includes("UAT-RESULT"));
121
116
  });
122
117
 
123
118
  // ─── diagnoseExpectedArtifact ─────────────────────────────────────────────
124
119
 
125
- test("diagnoseExpectedArtifact returns description for known types", () => {
120
+ test("diagnoseExpectedArtifact returns description for known types", (t) => {
126
121
  const base = makeTmpBase();
127
- try {
128
- const research = diagnoseExpectedArtifact("research-milestone", "M001", base);
129
- assert.ok(research);
130
- assert.ok(research!.includes("research"));
122
+ t.after(() => cleanup(base));
131
123
 
132
- const plan = diagnoseExpectedArtifact("plan-slice", "M001/S01", base);
133
- assert.ok(plan);
134
- assert.ok(plan!.includes("plan"));
124
+ const research = diagnoseExpectedArtifact("research-milestone", "M001", base);
125
+ assert.ok(research);
126
+ assert.ok(research!.includes("research"));
135
127
 
136
- const task = diagnoseExpectedArtifact("execute-task", "M001/S01/T01", base);
137
- assert.ok(task);
138
- assert.ok(task!.includes("T01"));
139
- } finally {
140
- cleanup(base);
141
- }
128
+ const plan = diagnoseExpectedArtifact("plan-slice", "M001/S01", base);
129
+ assert.ok(plan);
130
+ assert.ok(plan!.includes("plan"));
131
+
132
+ const task = diagnoseExpectedArtifact("execute-task", "M001/S01/T01", base);
133
+ assert.ok(task);
134
+ assert.ok(task!.includes("T01"));
142
135
  });
143
136
 
144
- test("diagnoseExpectedArtifact returns null for unknown type", () => {
137
+ test("diagnoseExpectedArtifact returns null for unknown type", (t) => {
145
138
  const base = makeTmpBase();
146
- try {
147
- assert.equal(diagnoseExpectedArtifact("unknown", "M001", base), null);
148
- } finally {
149
- cleanup(base);
150
- }
139
+ t.after(() => cleanup(base));
140
+
141
+ assert.equal(diagnoseExpectedArtifact("unknown", "M001", base), null);
151
142
  });
152
143
 
153
144
  // ─── buildLoopRemediationSteps ────────────────────────────────────────────
154
145
 
155
- test("buildLoopRemediationSteps returns steps for execute-task", () => {
146
+ test("buildLoopRemediationSteps returns steps for execute-task", (t) => {
156
147
  const base = makeTmpBase();
157
- try {
158
- const steps = buildLoopRemediationSteps("execute-task", "M001/S01/T01", base);
159
- assert.ok(steps);
160
- assert.ok(steps!.includes("T01"));
161
- assert.ok(steps!.includes("gsd doctor"));
162
- assert.ok(steps!.includes("[x]"));
163
- } finally {
164
- cleanup(base);
165
- }
148
+ t.after(() => cleanup(base));
149
+
150
+ const steps = buildLoopRemediationSteps("execute-task", "M001/S01/T01", base);
151
+ assert.ok(steps);
152
+ assert.ok(steps!.includes("T01"));
153
+ assert.ok(steps!.includes("gsd undo-task"));
166
154
  });
167
155
 
168
- test("buildLoopRemediationSteps returns steps for plan-slice", () => {
156
+ test("buildLoopRemediationSteps returns steps for plan-slice", (t) => {
169
157
  const base = makeTmpBase();
170
- try {
171
- const steps = buildLoopRemediationSteps("plan-slice", "M001/S01", base);
172
- assert.ok(steps);
173
- assert.ok(steps!.includes("PLAN"));
174
- assert.ok(steps!.includes("gsd doctor"));
175
- } finally {
176
- cleanup(base);
177
- }
158
+ t.after(() => cleanup(base));
159
+
160
+ const steps = buildLoopRemediationSteps("plan-slice", "M001/S01", base);
161
+ assert.ok(steps);
162
+ assert.ok(steps!.includes("PLAN"));
163
+ assert.ok(steps!.includes("gsd recover"));
178
164
  });
179
165
 
180
- test("buildLoopRemediationSteps returns steps for complete-slice", () => {
166
+ test("buildLoopRemediationSteps returns steps for complete-slice", (t) => {
181
167
  const base = makeTmpBase();
182
- try {
183
- const steps = buildLoopRemediationSteps("complete-slice", "M001/S01", base);
184
- assert.ok(steps);
185
- assert.ok(steps!.includes("S01"));
186
- assert.ok(steps!.includes("ROADMAP"));
187
- } finally {
188
- cleanup(base);
189
- }
168
+ t.after(() => cleanup(base));
169
+
170
+ const steps = buildLoopRemediationSteps("complete-slice", "M001/S01", base);
171
+ assert.ok(steps);
172
+ assert.ok(steps!.includes("S01"));
173
+ assert.ok(steps!.includes("gsd reset-slice"));
190
174
  });
191
175
 
192
- test("buildLoopRemediationSteps returns null for unknown type", () => {
176
+ test("buildLoopRemediationSteps returns null for unknown type", (t) => {
193
177
  const base = makeTmpBase();
194
- try {
195
- assert.equal(buildLoopRemediationSteps("unknown", "M001", base), null);
196
- } finally {
197
- cleanup(base);
198
- }
178
+ t.after(() => cleanup(base));
179
+
180
+ assert.equal(buildLoopRemediationSteps("unknown", "M001", base), null);
199
181
  });
200
182
 
201
183
  // ─── verifyExpectedArtifact: parse cache collision regression ─────────────
202
184
 
203
- test("verifyExpectedArtifact detects roadmap [x] change despite parse cache", () => {
185
+ test("verifyExpectedArtifact detects roadmap [x] change despite parse cache", (t) => {
204
186
  // Regression test: cacheKey collision when [ ] → [x] doesn't change
205
187
  // file length or first/last 100 chars. Without the fix, parseRoadmap
206
188
  // returns stale cached data with done=false even though the file has [x].
207
189
  const base = makeTmpBase();
208
- try {
209
- // Build a roadmap long enough that the [x] change is outside the first/last 100 chars
210
- const padding = "A".repeat(200);
211
- const roadmapBefore = [
212
- `# M001: Test Milestone ${padding}`,
213
- "",
214
- "## Slices",
215
- "",
216
- "- [ ] **S01: First slice** `risk:low`",
217
- "",
218
- `## Footer ${padding}`,
219
- ].join("\n");
220
- const roadmapAfter = roadmapBefore.replace("- [ ] **S01:", "- [x] **S01:");
221
-
222
- // Verify lengths are identical (the key collision condition)
223
- assert.equal(roadmapBefore.length, roadmapAfter.length);
224
-
225
- // Populate parse cache with the pre-edit roadmap
226
- const before = parseRoadmap(roadmapBefore);
227
- const sliceBefore = before.slices.find(s => s.id === "S01");
228
- assert.ok(sliceBefore);
229
- assert.equal(sliceBefore!.done, false);
230
-
231
- // Now write the post-edit roadmap to disk and create required artifacts
232
- const roadmapPath = join(base, ".gsd", "milestones", "M001", "M001-ROADMAP.md");
233
- writeFileSync(roadmapPath, roadmapAfter);
234
- const summaryPath = join(base, ".gsd", "milestones", "M001", "slices", "S01", "S01-SUMMARY.md");
235
- writeFileSync(summaryPath, "# Summary\nDone.");
236
- const uatPath = join(base, ".gsd", "milestones", "M001", "slices", "S01", "S01-UAT.md");
237
- writeFileSync(uatPath, "# UAT\nPassed.");
238
-
239
- // verifyExpectedArtifact should see the [x] despite the parse cache
240
- // having the [ ] version. The fix clears the parse cache inside verify.
241
- const verified = verifyExpectedArtifact("complete-slice", "M001/S01", base);
242
- assert.equal(verified, true, "verifyExpectedArtifact should return true when roadmap has [x]");
243
- } finally {
190
+ t.after(() => {
244
191
  clearParseCache();
245
192
  cleanup(base);
246
- }
193
+ });
194
+
195
+ // Build a roadmap long enough that the [x] change is outside the first/last 100 chars
196
+ const padding = "A".repeat(200);
197
+ const roadmapBefore = [
198
+ `# M001: Test Milestone ${padding}`,
199
+ "",
200
+ "## Slices",
201
+ "",
202
+ "- [ ] **S01: First slice** `risk:low`",
203
+ "",
204
+ `## Footer ${padding}`,
205
+ ].join("\n");
206
+ const roadmapAfter = roadmapBefore.replace("- [ ] **S01:", "- [x] **S01:");
207
+
208
+ // Verify lengths are identical (the key collision condition)
209
+ assert.equal(roadmapBefore.length, roadmapAfter.length);
210
+
211
+ // Populate parse cache with the pre-edit roadmap
212
+ const before = parseRoadmap(roadmapBefore);
213
+ const sliceBefore = before.slices.find(s => s.id === "S01");
214
+ assert.ok(sliceBefore);
215
+ assert.equal(sliceBefore!.done, false);
216
+
217
+ // Now write the post-edit roadmap to disk and create required artifacts
218
+ const roadmapPath = join(base, ".gsd", "milestones", "M001", "M001-ROADMAP.md");
219
+ writeFileSync(roadmapPath, roadmapAfter);
220
+ const summaryPath = join(base, ".gsd", "milestones", "M001", "slices", "S01", "S01-SUMMARY.md");
221
+ writeFileSync(summaryPath, "# Summary\nDone.");
222
+ const uatPath = join(base, ".gsd", "milestones", "M001", "slices", "S01", "S01-UAT.md");
223
+ writeFileSync(uatPath, "# UAT\nPassed.");
224
+
225
+ // verifyExpectedArtifact should see the [x] despite the parse cache
226
+ // having the [ ] version. The fix clears the parse cache inside verify.
227
+ const verified = verifyExpectedArtifact("complete-slice", "M001/S01", base);
228
+ assert.equal(verified, true, "verifyExpectedArtifact should return true when roadmap has [x]");
247
229
  });
248
230
 
249
231
  // ─── verifyExpectedArtifact: plan-slice empty scaffold regression (#699) ──
250
232
 
251
- test("verifyExpectedArtifact rejects plan-slice with empty scaffold", () => {
233
+ test("verifyExpectedArtifact rejects plan-slice with empty scaffold", (t) => {
252
234
  const base = makeTmpBase();
253
- try {
254
- const sliceDir = join(base, ".gsd", "milestones", "M001", "slices", "S01");
255
- mkdirSync(sliceDir, { recursive: true });
256
- writeFileSync(join(sliceDir, "S01-PLAN.md"), "# S01: Test Slice\n\n## Tasks\n\n");
257
- assert.strictEqual(
258
- verifyExpectedArtifact("plan-slice", "M001/S01", base),
259
- false,
260
- "Empty scaffold should not be treated as completed artifact",
261
- );
262
- } finally {
263
- cleanup(base);
264
- }
235
+ t.after(() => cleanup(base));
236
+
237
+ const sliceDir = join(base, ".gsd", "milestones", "M001", "slices", "S01");
238
+ mkdirSync(sliceDir, { recursive: true });
239
+ writeFileSync(join(sliceDir, "S01-PLAN.md"), "# S01: Test Slice\n\n## Tasks\n\n");
240
+ assert.strictEqual(
241
+ verifyExpectedArtifact("plan-slice", "M001/S01", base),
242
+ false,
243
+ "Empty scaffold should not be treated as completed artifact",
244
+ );
265
245
  });
266
246
 
267
- test("verifyExpectedArtifact accepts plan-slice with actual tasks", () => {
247
+ test("verifyExpectedArtifact accepts plan-slice with actual tasks", (t) => {
268
248
  const base = makeTmpBase();
269
- try {
270
- const sliceDir = join(base, ".gsd", "milestones", "M001", "slices", "S01");
271
- const tasksDir = join(sliceDir, "tasks");
272
- mkdirSync(tasksDir, { recursive: true });
273
- writeFileSync(join(sliceDir, "S01-PLAN.md"), [
274
- "# S01: Test Slice",
275
- "",
276
- "## Tasks",
277
- "",
278
- "- [ ] **T01: Implement feature** `est:2h`",
279
- "- [ ] **T02: Write tests** `est:1h`",
280
- ].join("\n"));
281
- writeFileSync(join(tasksDir, "T01-PLAN.md"), "# T01 Plan");
282
- writeFileSync(join(tasksDir, "T02-PLAN.md"), "# T02 Plan");
283
- assert.strictEqual(
284
- verifyExpectedArtifact("plan-slice", "M001/S01", base),
285
- true,
286
- "Plan with task entries should be treated as completed artifact",
287
- );
288
- } finally {
289
- cleanup(base);
290
- }
249
+ t.after(() => cleanup(base));
250
+
251
+ const sliceDir = join(base, ".gsd", "milestones", "M001", "slices", "S01");
252
+ const tasksDir = join(sliceDir, "tasks");
253
+ mkdirSync(tasksDir, { recursive: true });
254
+ writeFileSync(join(sliceDir, "S01-PLAN.md"), [
255
+ "# S01: Test Slice",
256
+ "",
257
+ "## Tasks",
258
+ "",
259
+ "- [ ] **T01: Implement feature** `est:2h`",
260
+ "- [ ] **T02: Write tests** `est:1h`",
261
+ ].join("\n"));
262
+ writeFileSync(join(tasksDir, "T01-PLAN.md"), "# T01 Plan");
263
+ writeFileSync(join(tasksDir, "T02-PLAN.md"), "# T02 Plan");
264
+ assert.strictEqual(
265
+ verifyExpectedArtifact("plan-slice", "M001/S01", base),
266
+ true,
267
+ "Plan with task entries should be treated as completed artifact",
268
+ );
291
269
  });
292
270
 
293
- test("verifyExpectedArtifact accepts plan-slice with completed tasks", () => {
271
+ test("verifyExpectedArtifact accepts plan-slice with completed tasks", (t) => {
294
272
  const base = makeTmpBase();
295
- try {
296
- const sliceDir = join(base, ".gsd", "milestones", "M001", "slices", "S01");
297
- const tasksDir = join(sliceDir, "tasks");
298
- mkdirSync(tasksDir, { recursive: true });
299
- writeFileSync(join(sliceDir, "S01-PLAN.md"), [
300
- "# S01: Test Slice",
301
- "",
302
- "## Tasks",
303
- "",
304
- "- [x] **T01: Implement feature** `est:2h`",
305
- "- [ ] **T02: Write tests** `est:1h`",
306
- ].join("\n"));
307
- writeFileSync(join(tasksDir, "T01-PLAN.md"), "# T01 Plan");
308
- writeFileSync(join(tasksDir, "T02-PLAN.md"), "# T02 Plan");
309
- assert.strictEqual(
310
- verifyExpectedArtifact("plan-slice", "M001/S01", base),
311
- true,
312
- "Plan with completed task entries should be treated as completed artifact",
313
- );
314
- } finally {
315
- cleanup(base);
316
- }
273
+ t.after(() => cleanup(base));
274
+
275
+ const sliceDir = join(base, ".gsd", "milestones", "M001", "slices", "S01");
276
+ const tasksDir = join(sliceDir, "tasks");
277
+ mkdirSync(tasksDir, { recursive: true });
278
+ writeFileSync(join(sliceDir, "S01-PLAN.md"), [
279
+ "# S01: Test Slice",
280
+ "",
281
+ "## Tasks",
282
+ "",
283
+ "- [x] **T01: Implement feature** `est:2h`",
284
+ "- [ ] **T02: Write tests** `est:1h`",
285
+ ].join("\n"));
286
+ writeFileSync(join(tasksDir, "T01-PLAN.md"), "# T01 Plan");
287
+ writeFileSync(join(tasksDir, "T02-PLAN.md"), "# T02 Plan");
288
+ assert.strictEqual(
289
+ verifyExpectedArtifact("plan-slice", "M001/S01", base),
290
+ true,
291
+ "Plan with completed task entries should be treated as completed artifact",
292
+ );
317
293
  });
318
294
 
319
295
  // ─── verifyExpectedArtifact: plan-slice task plan check (#739) ────────────
320
296
 
321
- test("verifyExpectedArtifact plan-slice passes when all task plan files exist", () => {
297
+ test("verifyExpectedArtifact plan-slice passes when all task plan files exist", (t) => {
322
298
  const base = makeTmpBase();
323
- try {
324
- const tasksDir = join(base, ".gsd", "milestones", "M001", "slices", "S01", "tasks");
325
- const planPath = join(base, ".gsd", "milestones", "M001", "slices", "S01", "S01-PLAN.md");
326
- const planContent = [
327
- "# S01: Test Slice",
328
- "",
329
- "## Tasks",
330
- "",
331
- "- [ ] **T01: First task** `est:1h`",
332
- "- [ ] **T02: Second task** `est:2h`",
333
- ].join("\n");
334
- writeFileSync(planPath, planContent);
335
- writeFileSync(join(tasksDir, "T01-PLAN.md"), "# T01 Plan\n\nDo the thing.");
336
- writeFileSync(join(tasksDir, "T02-PLAN.md"), "# T02 Plan\n\nDo the other thing.");
337
-
338
- const result = verifyExpectedArtifact("plan-slice", "M001/S01", base);
339
- assert.equal(result, true, "should pass when all task plan files exist");
340
- } finally {
341
- cleanup(base);
342
- }
299
+ t.after(() => cleanup(base));
300
+
301
+ const tasksDir = join(base, ".gsd", "milestones", "M001", "slices", "S01", "tasks");
302
+ const planPath = join(base, ".gsd", "milestones", "M001", "slices", "S01", "S01-PLAN.md");
303
+ const planContent = [
304
+ "# S01: Test Slice",
305
+ "",
306
+ "## Tasks",
307
+ "",
308
+ "- [ ] **T01: First task** `est:1h`",
309
+ "- [ ] **T02: Second task** `est:2h`",
310
+ ].join("\n");
311
+ writeFileSync(planPath, planContent);
312
+ writeFileSync(join(tasksDir, "T01-PLAN.md"), "# T01 Plan\n\nDo the thing.");
313
+ writeFileSync(join(tasksDir, "T02-PLAN.md"), "# T02 Plan\n\nDo the other thing.");
314
+
315
+ const result = verifyExpectedArtifact("plan-slice", "M001/S01", base);
316
+ assert.equal(result, true, "should pass when all task plan files exist");
343
317
  });
344
318
 
345
- test("verifyExpectedArtifact plan-slice fails when a task plan file is missing (#739)", () => {
319
+ test("verifyExpectedArtifact plan-slice fails when a task plan file is missing (#739)", (t) => {
346
320
  const base = makeTmpBase();
347
- try {
348
- const tasksDir = join(base, ".gsd", "milestones", "M001", "slices", "S01", "tasks");
349
- const planPath = join(base, ".gsd", "milestones", "M001", "slices", "S01", "S01-PLAN.md");
350
- const planContent = [
351
- "# S01: Test Slice",
352
- "",
353
- "## Tasks",
354
- "",
355
- "- [ ] **T01: First task** `est:1h`",
356
- "- [ ] **T02: Second task** `est:2h`",
357
- ].join("\n");
358
- writeFileSync(planPath, planContent);
359
- // Only write T01-PLAN.md — T02 is missing
360
- writeFileSync(join(tasksDir, "T01-PLAN.md"), "# T01 Plan\n\nDo the thing.");
361
-
362
- const result = verifyExpectedArtifact("plan-slice", "M001/S01", base);
363
- assert.equal(result, false, "should fail when T02-PLAN.md is missing");
364
- } finally {
365
- cleanup(base);
366
- }
321
+ t.after(() => cleanup(base));
322
+
323
+ const tasksDir = join(base, ".gsd", "milestones", "M001", "slices", "S01", "tasks");
324
+ const planPath = join(base, ".gsd", "milestones", "M001", "slices", "S01", "S01-PLAN.md");
325
+ const planContent = [
326
+ "# S01: Test Slice",
327
+ "",
328
+ "## Tasks",
329
+ "",
330
+ "- [ ] **T01: First task** `est:1h`",
331
+ "- [ ] **T02: Second task** `est:2h`",
332
+ ].join("\n");
333
+ writeFileSync(planPath, planContent);
334
+ // Only write T01-PLAN.md T02 is missing
335
+ writeFileSync(join(tasksDir, "T01-PLAN.md"), "# T01 Plan\n\nDo the thing.");
336
+
337
+ const result = verifyExpectedArtifact("plan-slice", "M001/S01", base);
338
+ assert.equal(result, false, "should fail when T02-PLAN.md is missing");
367
339
  });
368
340
 
369
- test("verifyExpectedArtifact plan-slice fails for plan with no tasks (#699)", () => {
341
+ test("verifyExpectedArtifact plan-slice fails for plan with no tasks (#699)", (t) => {
370
342
  const base = makeTmpBase();
371
- try {
372
- const planPath = join(base, ".gsd", "milestones", "M001", "slices", "S01", "S01-PLAN.md");
373
- const planContent = [
374
- "# S01: Test Slice",
375
- "",
376
- "## Goal",
377
- "",
378
- "Just some documentation updates, no tasks.",
379
- ].join("\n");
380
- writeFileSync(planPath, planContent);
381
-
382
- const result = verifyExpectedArtifact("plan-slice", "M001/S01", base);
383
- assert.equal(result, false, "should fail when plan has no task entries (empty scaffold, #699)");
384
- } finally {
385
- cleanup(base);
386
- }
343
+ t.after(() => cleanup(base));
344
+
345
+ const planPath = join(base, ".gsd", "milestones", "M001", "slices", "S01", "S01-PLAN.md");
346
+ const planContent = [
347
+ "# S01: Test Slice",
348
+ "",
349
+ "## Goal",
350
+ "",
351
+ "Just some documentation updates, no tasks.",
352
+ ].join("\n");
353
+ writeFileSync(planPath, planContent);
354
+
355
+ const result = verifyExpectedArtifact("plan-slice", "M001/S01", base);
356
+ assert.equal(result, false, "should fail when plan has no task entries (empty scaffold, #699)");
387
357
  });
388
358
 
389
359
  // ─── verifyExpectedArtifact: heading-style plan tasks (#1691) ─────────────
390
360
 
391
- test("verifyExpectedArtifact accepts plan-slice with heading-style tasks (### T01 --)", () => {
361
+ test("verifyExpectedArtifact accepts plan-slice with heading-style tasks (### T01 --)", (t) => {
392
362
  const base = makeTmpBase();
393
- try {
394
- const sliceDir = join(base, ".gsd", "milestones", "M001", "slices", "S01");
395
- const tasksDir = join(sliceDir, "tasks");
396
- mkdirSync(tasksDir, { recursive: true });
397
- writeFileSync(join(sliceDir, "S01-PLAN.md"), [
398
- "# S01: Test Slice",
399
- "",
400
- "## Tasks",
401
- "",
402
- "### T01 -- Implement feature",
403
- "",
404
- "Feature description.",
405
- "",
406
- "### T02 -- Write tests",
407
- "",
408
- "Test description.",
409
- ].join("\n"));
410
- writeFileSync(join(tasksDir, "T01-PLAN.md"), "# T01 Plan");
411
- writeFileSync(join(tasksDir, "T02-PLAN.md"), "# T02 Plan");
412
- assert.strictEqual(
413
- verifyExpectedArtifact("plan-slice", "M001/S01", base),
414
- true,
415
- "Heading-style plan with task entries should be treated as completed artifact",
416
- );
417
- } finally {
418
- cleanup(base);
419
- }
363
+ t.after(() => cleanup(base));
364
+
365
+ const sliceDir = join(base, ".gsd", "milestones", "M001", "slices", "S01");
366
+ const tasksDir = join(sliceDir, "tasks");
367
+ mkdirSync(tasksDir, { recursive: true });
368
+ writeFileSync(join(sliceDir, "S01-PLAN.md"), [
369
+ "# S01: Test Slice",
370
+ "",
371
+ "## Tasks",
372
+ "",
373
+ "### T01 -- Implement feature",
374
+ "",
375
+ "Feature description.",
376
+ "",
377
+ "### T02 -- Write tests",
378
+ "",
379
+ "Test description.",
380
+ ].join("\n"));
381
+ writeFileSync(join(tasksDir, "T01-PLAN.md"), "# T01 Plan");
382
+ writeFileSync(join(tasksDir, "T02-PLAN.md"), "# T02 Plan");
383
+ assert.strictEqual(
384
+ verifyExpectedArtifact("plan-slice", "M001/S01", base),
385
+ true,
386
+ "Heading-style plan with task entries should be treated as completed artifact",
387
+ );
420
388
  });
421
389
 
422
- test("verifyExpectedArtifact accepts plan-slice with colon-style heading tasks (### T01:)", () => {
390
+ test("verifyExpectedArtifact accepts plan-slice with colon-style heading tasks (### T01:)", (t) => {
423
391
  const base = makeTmpBase();
392
+ t.after(() => cleanup(base));
393
+
394
+ const sliceDir = join(base, ".gsd", "milestones", "M001", "slices", "S01");
395
+ const tasksDir = join(sliceDir, "tasks");
396
+ mkdirSync(tasksDir, { recursive: true });
397
+ writeFileSync(join(sliceDir, "S01-PLAN.md"), [
398
+ "# S01: Test Slice",
399
+ "",
400
+ "## Tasks",
401
+ "",
402
+ "### T01: Implement feature",
403
+ "",
404
+ "Feature description.",
405
+ ].join("\n"));
406
+ writeFileSync(join(tasksDir, "T01-PLAN.md"), "# T01 Plan");
407
+ assert.strictEqual(
408
+ verifyExpectedArtifact("plan-slice", "M001/S01", base),
409
+ true,
410
+ "Colon heading-style plan should be treated as completed artifact",
411
+ );
412
+ });
413
+
414
+ test("verifyExpectedArtifact execute-task passes for heading-style plan entry (#1691)", (t) => {
415
+ const base = makeTmpBase();
416
+ t.after(() => cleanup(base));
417
+
418
+ const sliceDir = join(base, ".gsd", "milestones", "M001", "slices", "S01");
419
+ const tasksDir = join(sliceDir, "tasks");
420
+ mkdirSync(tasksDir, { recursive: true });
421
+ writeFileSync(join(sliceDir, "S01-PLAN.md"), [
422
+ "# S01: Test Slice",
423
+ "",
424
+ "## Tasks",
425
+ "",
426
+ "### T01 -- Implement feature",
427
+ "",
428
+ "Feature description.",
429
+ ].join("\n"));
430
+ writeFileSync(join(tasksDir, "T01-SUMMARY.md"), "# T01 Summary\n\nDone.");
431
+ assert.strictEqual(
432
+ verifyExpectedArtifact("execute-task", "M001/S01/T01", base),
433
+ true,
434
+ "execute-task should pass for heading-style plan entry when summary exists",
435
+ );
436
+ });
437
+
438
+ test("verifyExpectedArtifact plan-slice passes for rendered slice/task plan artifacts from DB", async () => {
439
+ const base = makeTmpBase();
440
+ const dbPath = join(base, ".gsd", "gsd.db");
441
+ openDatabase(dbPath);
424
442
  try {
425
- const sliceDir = join(base, ".gsd", "milestones", "M001", "slices", "S01");
426
- const tasksDir = join(sliceDir, "tasks");
427
- mkdirSync(tasksDir, { recursive: true });
428
- writeFileSync(join(sliceDir, "S01-PLAN.md"), [
429
- "# S01: Test Slice",
430
- "",
431
- "## Tasks",
432
- "",
433
- "### T01: Implement feature",
434
- "",
435
- "Feature description.",
436
- ].join("\n"));
437
- writeFileSync(join(tasksDir, "T01-PLAN.md"), "# T01 Plan");
438
- assert.strictEqual(
439
- verifyExpectedArtifact("plan-slice", "M001/S01", base),
440
- true,
441
- "Colon heading-style plan should be treated as completed artifact",
442
- );
443
+ insertMilestone({ id: "M001", title: "Milestone", status: "active" });
444
+ insertSlice({
445
+ id: "S01",
446
+ milestoneId: "M001",
447
+ title: "Rendered slice",
448
+ status: "pending",
449
+ demo: "Rendered plan artifacts exist.",
450
+ planning: {
451
+ goal: "Render plans from DB rows.",
452
+ successCriteria: "- Slice plan parses\n- Task plan files exist on disk",
453
+ proofLevel: "integration",
454
+ integrationClosure: "DB rows are the source of truth for PLAN artifacts.",
455
+ observabilityImpact: "- Recovery verification fails if a task plan file is missing",
456
+ },
457
+ });
458
+ insertTask({
459
+ id: "T01",
460
+ sliceId: "S01",
461
+ milestoneId: "M001",
462
+ title: "Render plan",
463
+ status: "pending",
464
+ planning: {
465
+ description: "Create the slice plan from DB state.",
466
+ estimate: "30m",
467
+ files: ["src/resources/extensions/gsd/markdown-renderer.ts"],
468
+ verify: "node --test markdown-renderer.test.ts",
469
+ inputs: ["src/resources/extensions/gsd/gsd-db.ts"],
470
+ expectedOutput: ["src/resources/extensions/gsd/tests/markdown-renderer.test.ts"],
471
+ observabilityImpact: "Renderer tests cover the failure mode.",
472
+ },
473
+ });
474
+ insertTask({
475
+ id: "T02",
476
+ sliceId: "S01",
477
+ milestoneId: "M001",
478
+ title: "Verify recovery",
479
+ status: "pending",
480
+ planning: {
481
+ description: "Prove task plan files remain present for recovery.",
482
+ estimate: "20m",
483
+ files: ["src/resources/extensions/gsd/auto-recovery.ts"],
484
+ verify: "node --test auto-recovery.test.ts",
485
+ inputs: ["src/resources/extensions/gsd/auto-recovery.ts"],
486
+ expectedOutput: ["src/resources/extensions/gsd/tests/auto-recovery.test.ts"],
487
+ observabilityImpact: "Missing plan files surface as explicit verification failures.",
488
+ },
489
+ });
490
+
491
+ const rendered = await renderPlanFromDb(base, "M001", "S01");
492
+ assert.ok(existsSync(rendered.planPath), "renderPlanFromDb should write the slice plan");
493
+ assert.equal(rendered.taskPlanPaths.length, 2, "renderPlanFromDb should render one task plan per task");
494
+
495
+ const planContent = readFileSync(rendered.planPath, "utf-8");
496
+ const parsedPlan = parsePlan(planContent);
497
+ assert.equal(parsedPlan.tasks.length, 2, "rendered slice plan should parse into task entries");
498
+
499
+ const taskPlanContent = readFileSync(rendered.taskPlanPaths[0], "utf-8");
500
+ const taskPlan = parseTaskPlanFile(taskPlanContent);
501
+ assert.deepEqual(taskPlan.frontmatter.skills_used, [], "rendered task plans should use conservative empty skills_used");
502
+
503
+ const result = verifyExpectedArtifact("plan-slice", "M001/S01", base);
504
+ assert.equal(result, true, "plan-slice verification should pass when rendered task plan files exist");
443
505
  } finally {
506
+ closeDatabase();
444
507
  cleanup(base);
445
508
  }
446
509
  });
447
510
 
448
- test("verifyExpectedArtifact execute-task passes for heading-style plan entry (#1691)", () => {
511
+ test("verifyExpectedArtifact plan-slice fails after deleting a rendered task plan file", async () => {
449
512
  const base = makeTmpBase();
513
+ const dbPath = join(base, ".gsd", "gsd.db");
514
+ openDatabase(dbPath);
450
515
  try {
451
- const sliceDir = join(base, ".gsd", "milestones", "M001", "slices", "S01");
452
- const tasksDir = join(sliceDir, "tasks");
453
- mkdirSync(tasksDir, { recursive: true });
454
- writeFileSync(join(sliceDir, "S01-PLAN.md"), [
455
- "# S01: Test Slice",
456
- "",
457
- "## Tasks",
458
- "",
459
- "### T01 -- Implement feature",
460
- "",
461
- "Feature description.",
462
- ].join("\n"));
463
- writeFileSync(join(tasksDir, "T01-SUMMARY.md"), "# T01 Summary\n\nDone.");
464
- assert.strictEqual(
465
- verifyExpectedArtifact("execute-task", "M001/S01/T01", base),
466
- true,
467
- "execute-task should pass for heading-style plan entry when summary exists",
468
- );
516
+ insertMilestone({ id: "M001", title: "Milestone", status: "active" });
517
+ insertSlice({
518
+ id: "S01",
519
+ milestoneId: "M001",
520
+ title: "Rendered slice",
521
+ status: "pending",
522
+ demo: "Rendered plan artifacts exist.",
523
+ planning: {
524
+ goal: "Render plans from DB rows.",
525
+ successCriteria: "- Slice plan parses\n- Task plan files exist on disk",
526
+ proofLevel: "integration",
527
+ integrationClosure: "DB rows are the source of truth for PLAN artifacts.",
528
+ observabilityImpact: "- Recovery verification fails if a task plan file is missing",
529
+ },
530
+ });
531
+ insertTask({
532
+ id: "T01",
533
+ sliceId: "S01",
534
+ milestoneId: "M001",
535
+ title: "Render plan",
536
+ status: "pending",
537
+ planning: {
538
+ description: "Create the slice plan from DB state.",
539
+ estimate: "30m",
540
+ files: ["src/resources/extensions/gsd/markdown-renderer.ts"],
541
+ verify: "node --test markdown-renderer.test.ts",
542
+ inputs: ["src/resources/extensions/gsd/gsd-db.ts"],
543
+ expectedOutput: ["src/resources/extensions/gsd/tests/markdown-renderer.test.ts"],
544
+ observabilityImpact: "Renderer tests cover the failure mode.",
545
+ },
546
+ });
547
+ insertTask({
548
+ id: "T02",
549
+ sliceId: "S01",
550
+ milestoneId: "M001",
551
+ title: "Verify recovery",
552
+ status: "pending",
553
+ planning: {
554
+ description: "Prove task plan files remain present for recovery.",
555
+ estimate: "20m",
556
+ files: ["src/resources/extensions/gsd/auto-recovery.ts"],
557
+ verify: "node --test auto-recovery.test.ts",
558
+ inputs: ["src/resources/extensions/gsd/auto-recovery.ts"],
559
+ expectedOutput: ["src/resources/extensions/gsd/tests/auto-recovery.test.ts"],
560
+ observabilityImpact: "Missing plan files surface as explicit verification failures.",
561
+ },
562
+ });
563
+
564
+ const rendered = await renderPlanFromDb(base, "M001", "S01");
565
+ rmSync(rendered.taskPlanPaths[1]);
566
+
567
+ const result = verifyExpectedArtifact("plan-slice", "M001/S01", base);
568
+ assert.equal(result, false, "plan-slice verification should fail when a rendered task plan file is removed");
469
569
  } finally {
570
+ closeDatabase();
470
571
  cleanup(base);
471
572
  }
472
573
  });
473
574
 
474
575
  // ─── selfHealRuntimeRecords — worktree base path (#769) ──────────────────
475
576
 
476
- test("selfHealRuntimeRecords clears stale dispatched records (#769)", async () => {
577
+ test("selfHealRuntimeRecords clears stale dispatched records (#769)", async (t) => {
477
578
  // selfHealRuntimeRecords now only clears stale dispatched records (>1h).
478
579
  // No completedKeySet parameter — deriveState is sole authority.
479
580
  const worktreeBase = makeTmpBase();
480
581
  const mainBase = makeTmpBase();
481
- try {
482
- const { writeUnitRuntimeRecord, readUnitRuntimeRecord } = await import("../unit-runtime.ts");
483
-
484
- // Write a stale runtime record in the worktree .gsd/runtime/units/
485
- writeUnitRuntimeRecord(worktreeBase, "run-uat", "M001/S01", Date.now() - 7200_000, {
486
- phase: "dispatched",
487
- });
488
-
489
- // Verify the runtime record exists before heal
490
- const before = readUnitRuntimeRecord(worktreeBase, "run-uat", "M001/S01");
491
- assert.ok(before, "runtime record should exist before heal");
492
-
493
- // Mock ExtensionContext with minimal notify
494
- const notifications: string[] = [];
495
- const mockCtx = {
496
- ui: { notify: (msg: string) => { notifications.push(msg); } },
497
- } as any;
498
-
499
- // Call selfHeal with worktreeBase — should clear the stale record
500
- await selfHealRuntimeRecords(worktreeBase, mockCtx);
501
-
502
- // The stale record should be cleared
503
- const after = readUnitRuntimeRecord(worktreeBase, "run-uat", "M001/S01");
504
- assert.equal(after, null, "runtime record should be cleared after heal");
505
- assert.ok(notifications.some(n => n.includes("Self-heal")), "should emit self-heal notification");
506
-
507
- // Write a stale record at mainBase
508
- writeUnitRuntimeRecord(mainBase, "run-uat", "M001/S01", Date.now() - 7200_000, {
509
- phase: "dispatched",
510
- });
511
- await selfHealRuntimeRecords(mainBase, mockCtx);
512
-
513
- // The record at mainBase should also be cleared by the stale timeout (>1h)
514
- const afterMain = readUnitRuntimeRecord(mainBase, "run-uat", "M001/S01");
515
- assert.equal(afterMain, null, "stale record at main base should be cleared by timeout");
516
- } finally {
582
+ t.after(() => {
517
583
  cleanup(worktreeBase);
518
584
  cleanup(mainBase);
519
- }
585
+ });
586
+
587
+ const { writeUnitRuntimeRecord, readUnitRuntimeRecord } = await import("../unit-runtime.ts");
588
+
589
+ // Write a stale runtime record in the worktree .gsd/runtime/units/
590
+ writeUnitRuntimeRecord(worktreeBase, "run-uat", "M001/S01", Date.now() - 7200_000, {
591
+ phase: "dispatched",
592
+ });
593
+
594
+ // Verify the runtime record exists before heal
595
+ const before = readUnitRuntimeRecord(worktreeBase, "run-uat", "M001/S01");
596
+ assert.ok(before, "runtime record should exist before heal");
597
+
598
+ // Mock ExtensionContext with minimal notify
599
+ const notifications: string[] = [];
600
+ const mockCtx = {
601
+ ui: { notify: (msg: string) => { notifications.push(msg); } },
602
+ } as any;
603
+
604
+ // Call selfHeal with worktreeBase — should clear the stale record
605
+ await selfHealRuntimeRecords(worktreeBase, mockCtx);
606
+
607
+ // The stale record should be cleared
608
+ const after = readUnitRuntimeRecord(worktreeBase, "run-uat", "M001/S01");
609
+ assert.equal(after, null, "runtime record should be cleared after heal");
610
+ assert.ok(notifications.some(n => n.includes("Self-heal")), "should emit self-heal notification");
611
+
612
+ // Write a stale record at mainBase
613
+ writeUnitRuntimeRecord(mainBase, "run-uat", "M001/S01", Date.now() - 7200_000, {
614
+ phase: "dispatched",
615
+ });
616
+ await selfHealRuntimeRecords(mainBase, mockCtx);
617
+
618
+ // The record at mainBase should also be cleared by the stale timeout (>1h)
619
+ const afterMain = readUnitRuntimeRecord(mainBase, "run-uat", "M001/S01");
620
+ assert.equal(afterMain, null, "stale record at main base should be cleared by timeout");
520
621
  });
521
622
 
522
623
  // ─── #1625: selfHealRuntimeRecords on resume clears paused-session leftovers ──
523
624
 
524
- test("selfHealRuntimeRecords clears recently-paused dispatched records on resume (#1625)", async () => {
625
+ test("selfHealRuntimeRecords clears recently-paused dispatched records on resume (#1625)", async (t) => {
525
626
  // When pauseAuto closes out a unit but clearUnitRuntimeRecord silently fails
526
627
  // (e.g. permission error), selfHealRuntimeRecords on resume should still
527
628
  // clean up stale dispatched records that are >1h old.
528
629
  const base = makeTmpBase();
529
- try {
530
- const { writeUnitRuntimeRecord, readUnitRuntimeRecord } = await import("../unit-runtime.ts");
630
+ t.after(() => cleanup(base));
531
631
 
532
- // Simulate a record left behind after a pause — aged >1h to be considered stale
533
- writeUnitRuntimeRecord(base, "execute-task", "M001/S01/T01", Date.now() - 3700_000, {
534
- phase: "dispatched",
535
- });
632
+ const { writeUnitRuntimeRecord, readUnitRuntimeRecord } = await import("../unit-runtime.ts");
536
633
 
537
- const before = readUnitRuntimeRecord(base, "execute-task", "M001/S01/T01");
538
- assert.ok(before, "dispatched record should exist before resume heal");
539
- assert.equal(before!.phase, "dispatched");
634
+ // Simulate a record left behind after a pause — aged >1h to be considered stale
635
+ writeUnitRuntimeRecord(base, "execute-task", "M001/S01/T01", Date.now() - 3700_000, {
636
+ phase: "dispatched",
637
+ });
540
638
 
541
- const notifications: string[] = [];
542
- const mockCtx = {
543
- ui: { notify: (msg: string) => { notifications.push(msg); } },
544
- } as any;
639
+ const before = readUnitRuntimeRecord(base, "execute-task", "M001/S01/T01");
640
+ assert.ok(before, "dispatched record should exist before resume heal");
641
+ assert.equal(before!.phase, "dispatched");
545
642
 
546
- await selfHealRuntimeRecords(base, mockCtx);
643
+ const notifications: string[] = [];
644
+ const mockCtx = {
645
+ ui: { notify: (msg: string) => { notifications.push(msg); } },
646
+ } as any;
547
647
 
548
- const after = readUnitRuntimeRecord(base, "execute-task", "M001/S01/T01");
549
- assert.equal(after, null, "stale dispatched record should be cleared on resume (#1625)");
550
- } finally {
551
- cleanup(base);
552
- }
648
+ await selfHealRuntimeRecords(base, mockCtx);
649
+
650
+ const after = readUnitRuntimeRecord(base, "execute-task", "M001/S01/T01");
651
+ assert.equal(after, null, "stale dispatched record should be cleared on resume (#1625)");
553
652
  });
554
653
 
555
654
  // ─── #793: invalidateAllCaches unblocks skip-loop ─────────────────────────
@@ -557,51 +656,49 @@ test("selfHealRuntimeRecords clears recently-paused dispatched records on resume
557
656
  // just invalidateStateCache()) to clear path/parse caches that deriveState
558
657
  // depends on. Without this, even after cache invalidation, deriveState reads
559
658
  // stale directory listings and returns the same unit, looping forever.
560
- test("#793: invalidateAllCaches clears all caches so deriveState sees fresh disk state", async () => {
659
+ test("#793: invalidateAllCaches clears all caches so deriveState sees fresh disk state", async (t) => {
561
660
  const base = makeTmpBase();
562
- try {
563
- const mid = "M001";
564
- const sid = "S01";
565
- const planDir = join(base, ".gsd", "milestones", mid, "slices", sid);
566
- const tasksDir = join(planDir, "tasks");
567
- mkdirSync(tasksDir, { recursive: true });
568
- mkdirSync(join(base, ".gsd", "milestones", mid), { recursive: true });
569
-
570
- writeFileSync(
571
- join(base, ".gsd", "milestones", mid, `${mid}-ROADMAP.md`),
572
- `# M001: Test Milestone\n\n**Vision:** test.\n\n## Slices\n\n- [ ] **${sid}: Slice One** \`risk:low\` \`depends:[]\`\n > After this: done.\n`,
573
- );
574
- const planUnchecked = `# ${sid}: Slice One\n\n**Goal:** test.\n\n## Tasks\n\n- [ ] **T01: Task One** \`est:10m\`\n- [ ] **T02: Task Two** \`est:10m\`\n`;
575
- writeFileSync(join(planDir, `${sid}-PLAN.md`), planUnchecked);
576
- writeFileSync(join(tasksDir, "T01-PLAN.md"), "# T01: Task One\n\n**Goal:** t\n\n## Steps\n- step\n\n## Verification\n- v\n");
577
- writeFileSync(join(tasksDir, "T02-PLAN.md"), "# T02: Task Two\n\n**Goal:** t\n\n## Steps\n- step\n\n## Verification\n- v\n");
578
-
579
- // Warm all caches
580
- const state1 = await deriveState(base);
581
- assert.equal(state1.activeTask?.id, "T01", "initial: T01 is active");
582
-
583
- // Simulate task completion on disk (what the LLM does)
584
- const planChecked = `# ${sid}: Slice One\n\n**Goal:** test.\n\n## Tasks\n\n- [x] **T01: Task One** \`est:10m\`\n- [ ] **T02: Task Two** \`est:10m\`\n`;
585
- writeFileSync(join(planDir, `${sid}-PLAN.md`), planChecked);
586
- writeFileSync(join(tasksDir, "T01-SUMMARY.md"), "---\nid: T01\n---\n# Summary\n");
587
-
588
- // invalidateStateCache alone: _stateCache cleared but path/parse caches warm
589
- invalidateStateCache();
590
-
591
- // invalidateAllCaches: all caches cleared — deriveState must re-read disk
592
- invalidateAllCaches();
593
- const state2 = await deriveState(base);
594
-
595
- // After full invalidation, T01 should be complete and T02 should be next
596
- assert.notEqual(state2.activeTask?.id, "T01", "#793: T01 not re-dispatched after full invalidation");
597
-
598
- // Verify the caches are truly cleared by calling clearParseCache and clearPathCache
599
- // do not throw (they should be no-ops after invalidateAllCaches already cleared them)
600
- clearParseCache(); // no-op, but should not throw
601
- assert.ok(true, "clearParseCache after invalidateAllCaches is safe");
602
- } finally {
603
- cleanup(base);
604
- }
661
+ t.after(() => cleanup(base));
662
+
663
+ const mid = "M001";
664
+ const sid = "S01";
665
+ const planDir = join(base, ".gsd", "milestones", mid, "slices", sid);
666
+ const tasksDir = join(planDir, "tasks");
667
+ mkdirSync(tasksDir, { recursive: true });
668
+ mkdirSync(join(base, ".gsd", "milestones", mid), { recursive: true });
669
+
670
+ writeFileSync(
671
+ join(base, ".gsd", "milestones", mid, `${mid}-ROADMAP.md`),
672
+ `# M001: Test Milestone\n\n**Vision:** test.\n\n## Slices\n\n- [ ] **${sid}: Slice One** \`risk:low\` \`depends:[]\`\n > After this: done.\n`,
673
+ );
674
+ const planUnchecked = `# ${sid}: Slice One\n\n**Goal:** test.\n\n## Tasks\n\n- [ ] **T01: Task One** \`est:10m\`\n- [ ] **T02: Task Two** \`est:10m\`\n`;
675
+ writeFileSync(join(planDir, `${sid}-PLAN.md`), planUnchecked);
676
+ writeFileSync(join(tasksDir, "T01-PLAN.md"), "# T01: Task One\n\n**Goal:** t\n\n## Steps\n- step\n\n## Verification\n- v\n");
677
+ writeFileSync(join(tasksDir, "T02-PLAN.md"), "# T02: Task Two\n\n**Goal:** t\n\n## Steps\n- step\n\n## Verification\n- v\n");
678
+
679
+ // Warm all caches
680
+ const state1 = await deriveState(base);
681
+ assert.equal(state1.activeTask?.id, "T01", "initial: T01 is active");
682
+
683
+ // Simulate task completion on disk (what the LLM does)
684
+ const planChecked = `# ${sid}: Slice One\n\n**Goal:** test.\n\n## Tasks\n\n- [x] **T01: Task One** \`est:10m\`\n- [ ] **T02: Task Two** \`est:10m\`\n`;
685
+ writeFileSync(join(planDir, `${sid}-PLAN.md`), planChecked);
686
+ writeFileSync(join(tasksDir, "T01-SUMMARY.md"), "---\nid: T01\n---\n# Summary\n");
687
+
688
+ // invalidateStateCache alone: _stateCache cleared but path/parse caches warm
689
+ invalidateStateCache();
690
+
691
+ // invalidateAllCaches: all caches cleared — deriveState must re-read disk
692
+ invalidateAllCaches();
693
+ const state2 = await deriveState(base);
694
+
695
+ // After full invalidation, T01 should be complete and T02 should be next
696
+ assert.notEqual(state2.activeTask?.id, "T01", "#793: T01 not re-dispatched after full invalidation");
697
+
698
+ // Verify the caches are truly cleared by calling clearParseCache and clearPathCache
699
+ // do not throw (they should be no-ops after invalidateAllCaches already cleared them)
700
+ clearParseCache(); // no-op, but should not throw
701
+ assert.ok(true, "clearParseCache after invalidateAllCaches is safe");
605
702
  });
606
703
 
607
704
  // ─── hasImplementationArtifacts (#1703) ───────────────────────────────────
@@ -621,88 +718,78 @@ function makeGitBase(): string {
621
718
  return base;
622
719
  }
623
720
 
624
- test("hasImplementationArtifacts returns false when only .gsd/ files committed (#1703)", () => {
721
+ test("hasImplementationArtifacts returns false when only .gsd/ files committed (#1703)", (t) => {
625
722
  const base = makeGitBase();
626
- try {
627
- // Create a feature branch and commit only .gsd/ files
628
- execFileSync("git", ["checkout", "-b", "feat/test-milestone"], { cwd: base, stdio: "ignore" });
629
- mkdirSync(join(base, ".gsd", "milestones", "M001"), { recursive: true });
630
- writeFileSync(join(base, ".gsd", "milestones", "M001", "M001-ROADMAP.md"), "# Roadmap");
631
- writeFileSync(join(base, ".gsd", "milestones", "M001", "M001-SUMMARY.md"), "# Summary");
632
- execFileSync("git", ["add", "."], { cwd: base, stdio: "ignore" });
633
- execFileSync("git", ["commit", "-m", "chore: add plan files"], { cwd: base, stdio: "ignore" });
634
-
635
- const result = hasImplementationArtifacts(base);
636
- assert.equal(result, false, "should return false when only .gsd/ files were committed");
637
- } finally {
638
- cleanup(base);
639
- }
723
+ t.after(() => cleanup(base));
724
+
725
+ // Create a feature branch and commit only .gsd/ files
726
+ execFileSync("git", ["checkout", "-b", "feat/test-milestone"], { cwd: base, stdio: "ignore" });
727
+ mkdirSync(join(base, ".gsd", "milestones", "M001"), { recursive: true });
728
+ writeFileSync(join(base, ".gsd", "milestones", "M001", "M001-ROADMAP.md"), "# Roadmap");
729
+ writeFileSync(join(base, ".gsd", "milestones", "M001", "M001-SUMMARY.md"), "# Summary");
730
+ execFileSync("git", ["add", "."], { cwd: base, stdio: "ignore" });
731
+ execFileSync("git", ["commit", "-m", "chore: add plan files"], { cwd: base, stdio: "ignore" });
732
+
733
+ const result = hasImplementationArtifacts(base);
734
+ assert.equal(result, false, "should return false when only .gsd/ files were committed");
640
735
  });
641
736
 
642
- test("hasImplementationArtifacts returns true when implementation files committed (#1703)", () => {
737
+ test("hasImplementationArtifacts returns true when implementation files committed (#1703)", (t) => {
643
738
  const base = makeGitBase();
644
- try {
645
- // Create a feature branch with both .gsd/ and implementation files
646
- execFileSync("git", ["checkout", "-b", "feat/test-impl"], { cwd: base, stdio: "ignore" });
647
- mkdirSync(join(base, ".gsd", "milestones", "M001"), { recursive: true });
648
- writeFileSync(join(base, ".gsd", "milestones", "M001", "M001-ROADMAP.md"), "# Roadmap");
649
- mkdirSync(join(base, "src"), { recursive: true });
650
- writeFileSync(join(base, "src", "feature.ts"), "export function feature() {}");
651
- execFileSync("git", ["add", "."], { cwd: base, stdio: "ignore" });
652
- execFileSync("git", ["commit", "-m", "feat: add feature"], { cwd: base, stdio: "ignore" });
653
-
654
- const result = hasImplementationArtifacts(base);
655
- assert.equal(result, true, "should return true when implementation files are present");
656
- } finally {
657
- cleanup(base);
658
- }
739
+ t.after(() => cleanup(base));
740
+
741
+ // Create a feature branch with both .gsd/ and implementation files
742
+ execFileSync("git", ["checkout", "-b", "feat/test-impl"], { cwd: base, stdio: "ignore" });
743
+ mkdirSync(join(base, ".gsd", "milestones", "M001"), { recursive: true });
744
+ writeFileSync(join(base, ".gsd", "milestones", "M001", "M001-ROADMAP.md"), "# Roadmap");
745
+ mkdirSync(join(base, "src"), { recursive: true });
746
+ writeFileSync(join(base, "src", "feature.ts"), "export function feature() {}");
747
+ execFileSync("git", ["add", "."], { cwd: base, stdio: "ignore" });
748
+ execFileSync("git", ["commit", "-m", "feat: add feature"], { cwd: base, stdio: "ignore" });
749
+
750
+ const result = hasImplementationArtifacts(base);
751
+ assert.equal(result, true, "should return true when implementation files are present");
659
752
  });
660
753
 
661
- test("hasImplementationArtifacts returns true on non-git directory (fail-open)", () => {
754
+ test("hasImplementationArtifacts returns true on non-git directory (fail-open)", (t) => {
662
755
  const base = join(tmpdir(), `gsd-test-nogit-${randomUUID()}`);
663
756
  mkdirSync(base, { recursive: true });
664
- try {
665
- const result = hasImplementationArtifacts(base);
666
- assert.equal(result, true, "should return true (fail-open) in non-git directory");
667
- } finally {
668
- cleanup(base);
669
- }
757
+ t.after(() => cleanup(base));
758
+
759
+ const result = hasImplementationArtifacts(base);
760
+ assert.equal(result, true, "should return true (fail-open) in non-git directory");
670
761
  });
671
762
 
672
763
  // ─── verifyExpectedArtifact: complete-milestone requires impl artifacts (#1703) ──
673
764
 
674
- test("verifyExpectedArtifact complete-milestone fails with only .gsd/ files (#1703)", () => {
765
+ test("verifyExpectedArtifact complete-milestone fails with only .gsd/ files (#1703)", (t) => {
675
766
  const base = makeGitBase();
676
- try {
677
- // Create feature branch with only .gsd/ files
678
- execFileSync("git", ["checkout", "-b", "feat/ms-only-gsd"], { cwd: base, stdio: "ignore" });
679
- mkdirSync(join(base, ".gsd", "milestones", "M001"), { recursive: true });
680
- writeFileSync(join(base, ".gsd", "milestones", "M001", "M001-SUMMARY.md"), "# Milestone Summary\nDone.");
681
- execFileSync("git", ["add", "."], { cwd: base, stdio: "ignore" });
682
- execFileSync("git", ["commit", "-m", "chore: milestone plan files"], { cwd: base, stdio: "ignore" });
683
-
684
- const result = verifyExpectedArtifact("complete-milestone", "M001", base);
685
- assert.equal(result, false, "complete-milestone should fail verification when only .gsd/ files present");
686
- } finally {
687
- cleanup(base);
688
- }
767
+ t.after(() => cleanup(base));
768
+
769
+ // Create feature branch with only .gsd/ files
770
+ execFileSync("git", ["checkout", "-b", "feat/ms-only-gsd"], { cwd: base, stdio: "ignore" });
771
+ mkdirSync(join(base, ".gsd", "milestones", "M001"), { recursive: true });
772
+ writeFileSync(join(base, ".gsd", "milestones", "M001", "M001-SUMMARY.md"), "# Milestone Summary\nDone.");
773
+ execFileSync("git", ["add", "."], { cwd: base, stdio: "ignore" });
774
+ execFileSync("git", ["commit", "-m", "chore: milestone plan files"], { cwd: base, stdio: "ignore" });
775
+
776
+ const result = verifyExpectedArtifact("complete-milestone", "M001", base);
777
+ assert.equal(result, false, "complete-milestone should fail verification when only .gsd/ files present");
689
778
  });
690
779
 
691
- test("verifyExpectedArtifact complete-milestone passes with impl files (#1703)", () => {
780
+ test("verifyExpectedArtifact complete-milestone passes with impl files (#1703)", (t) => {
692
781
  const base = makeGitBase();
693
- try {
694
- // Create feature branch with implementation files AND milestone summary
695
- execFileSync("git", ["checkout", "-b", "feat/ms-with-impl"], { cwd: base, stdio: "ignore" });
696
- mkdirSync(join(base, ".gsd", "milestones", "M001"), { recursive: true });
697
- writeFileSync(join(base, ".gsd", "milestones", "M001", "M001-SUMMARY.md"), "# Milestone Summary\nDone.");
698
- mkdirSync(join(base, "src"), { recursive: true });
699
- writeFileSync(join(base, "src", "app.ts"), "console.log('hello');");
700
- execFileSync("git", ["add", "."], { cwd: base, stdio: "ignore" });
701
- execFileSync("git", ["commit", "-m", "feat: implementation"], { cwd: base, stdio: "ignore" });
702
-
703
- const result = verifyExpectedArtifact("complete-milestone", "M001", base);
704
- assert.equal(result, true, "complete-milestone should pass verification with implementation files");
705
- } finally {
706
- cleanup(base);
707
- }
782
+ t.after(() => cleanup(base));
783
+
784
+ // Create feature branch with implementation files AND milestone summary
785
+ execFileSync("git", ["checkout", "-b", "feat/ms-with-impl"], { cwd: base, stdio: "ignore" });
786
+ mkdirSync(join(base, ".gsd", "milestones", "M001"), { recursive: true });
787
+ writeFileSync(join(base, ".gsd", "milestones", "M001", "M001-SUMMARY.md"), "# Milestone Summary\nDone.");
788
+ mkdirSync(join(base, "src"), { recursive: true });
789
+ writeFileSync(join(base, "src", "app.ts"), "console.log('hello');");
790
+ execFileSync("git", ["add", "."], { cwd: base, stdio: "ignore" });
791
+ execFileSync("git", ["commit", "-m", "feat: implementation"], { cwd: base, stdio: "ignore" });
792
+
793
+ const result = verifyExpectedArtifact("complete-milestone", "M001", base);
794
+ assert.equal(result, true, "complete-milestone should pass verification with implementation files");
708
795
  });