gsd-pi 2.44.0-dev.848dd4c → 2.44.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (298) hide show
  1. package/README.md +12 -30
  2. package/dist/resources/extensions/gsd/auto-start.js +0 -10
  3. package/dist/resources/extensions/gsd/commands/handlers/workflow.js +0 -5
  4. package/dist/web/standalone/.next/BUILD_ID +1 -1
  5. package/dist/web/standalone/.next/app-path-routes-manifest.json +14 -14
  6. package/dist/web/standalone/.next/build-manifest.json +3 -3
  7. package/dist/web/standalone/.next/prerender-manifest.json +3 -3
  8. package/dist/web/standalone/.next/required-server-files.json +3 -3
  9. package/dist/web/standalone/.next/server/app/_global-error/page.js +3 -3
  10. package/dist/web/standalone/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
  11. package/dist/web/standalone/.next/server/app/_global-error.html +2 -2
  12. package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
  13. package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  14. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
  15. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
  16. package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  17. package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  18. package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  19. package/dist/web/standalone/.next/server/app/_not-found/page.js +2 -2
  20. package/dist/web/standalone/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  21. package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
  22. package/dist/web/standalone/.next/server/app/_not-found.rsc +3 -3
  23. package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +3 -3
  24. package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  25. package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +3 -3
  26. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  27. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  28. package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
  29. package/dist/web/standalone/.next/server/app/api/boot/route.js +1 -1
  30. package/dist/web/standalone/.next/server/app/api/boot/route_client-reference-manifest.js +1 -1
  31. package/dist/web/standalone/.next/server/app/api/bridge-terminal/input/route.js +1 -1
  32. package/dist/web/standalone/.next/server/app/api/bridge-terminal/input/route_client-reference-manifest.js +1 -1
  33. package/dist/web/standalone/.next/server/app/api/bridge-terminal/resize/route.js +1 -1
  34. package/dist/web/standalone/.next/server/app/api/bridge-terminal/resize/route_client-reference-manifest.js +1 -1
  35. package/dist/web/standalone/.next/server/app/api/bridge-terminal/stream/route.js +2 -2
  36. package/dist/web/standalone/.next/server/app/api/bridge-terminal/stream/route_client-reference-manifest.js +1 -1
  37. package/dist/web/standalone/.next/server/app/api/browse-directories/route.js +1 -1
  38. package/dist/web/standalone/.next/server/app/api/browse-directories/route_client-reference-manifest.js +1 -1
  39. package/dist/web/standalone/.next/server/app/api/captures/route.js +1 -1
  40. package/dist/web/standalone/.next/server/app/api/captures/route_client-reference-manifest.js +1 -1
  41. package/dist/web/standalone/.next/server/app/api/cleanup/route.js +1 -1
  42. package/dist/web/standalone/.next/server/app/api/cleanup/route_client-reference-manifest.js +1 -1
  43. package/dist/web/standalone/.next/server/app/api/dev-mode/route.js +1 -1
  44. package/dist/web/standalone/.next/server/app/api/dev-mode/route_client-reference-manifest.js +1 -1
  45. package/dist/web/standalone/.next/server/app/api/doctor/route.js +1 -1
  46. package/dist/web/standalone/.next/server/app/api/doctor/route_client-reference-manifest.js +1 -1
  47. package/dist/web/standalone/.next/server/app/api/export-data/route.js +1 -1
  48. package/dist/web/standalone/.next/server/app/api/export-data/route_client-reference-manifest.js +1 -1
  49. package/dist/web/standalone/.next/server/app/api/files/route.js +1 -1
  50. package/dist/web/standalone/.next/server/app/api/files/route_client-reference-manifest.js +1 -1
  51. package/dist/web/standalone/.next/server/app/api/forensics/route.js +1 -1
  52. package/dist/web/standalone/.next/server/app/api/forensics/route_client-reference-manifest.js +1 -1
  53. package/dist/web/standalone/.next/server/app/api/git/route.js +1 -1
  54. package/dist/web/standalone/.next/server/app/api/git/route_client-reference-manifest.js +1 -1
  55. package/dist/web/standalone/.next/server/app/api/history/route.js +1 -1
  56. package/dist/web/standalone/.next/server/app/api/history/route_client-reference-manifest.js +1 -1
  57. package/dist/web/standalone/.next/server/app/api/hooks/route.js +1 -1
  58. package/dist/web/standalone/.next/server/app/api/hooks/route_client-reference-manifest.js +1 -1
  59. package/dist/web/standalone/.next/server/app/api/inspect/route.js +1 -1
  60. package/dist/web/standalone/.next/server/app/api/inspect/route_client-reference-manifest.js +1 -1
  61. package/dist/web/standalone/.next/server/app/api/knowledge/route.js +1 -1
  62. package/dist/web/standalone/.next/server/app/api/knowledge/route_client-reference-manifest.js +1 -1
  63. package/dist/web/standalone/.next/server/app/api/live-state/route.js +1 -1
  64. package/dist/web/standalone/.next/server/app/api/live-state/route_client-reference-manifest.js +1 -1
  65. package/dist/web/standalone/.next/server/app/api/onboarding/route.js +1 -1
  66. package/dist/web/standalone/.next/server/app/api/onboarding/route_client-reference-manifest.js +1 -1
  67. package/dist/web/standalone/.next/server/app/api/preferences/route.js +1 -1
  68. package/dist/web/standalone/.next/server/app/api/preferences/route_client-reference-manifest.js +1 -1
  69. package/dist/web/standalone/.next/server/app/api/projects/route.js +1 -1
  70. package/dist/web/standalone/.next/server/app/api/projects/route_client-reference-manifest.js +1 -1
  71. package/dist/web/standalone/.next/server/app/api/recovery/route.js +1 -1
  72. package/dist/web/standalone/.next/server/app/api/recovery/route_client-reference-manifest.js +1 -1
  73. package/dist/web/standalone/.next/server/app/api/remote-questions/route.js +5 -5
  74. package/dist/web/standalone/.next/server/app/api/remote-questions/route_client-reference-manifest.js +1 -1
  75. package/dist/web/standalone/.next/server/app/api/session/browser/route.js +1 -1
  76. package/dist/web/standalone/.next/server/app/api/session/browser/route_client-reference-manifest.js +1 -1
  77. package/dist/web/standalone/.next/server/app/api/session/command/route.js +1 -1
  78. package/dist/web/standalone/.next/server/app/api/session/command/route_client-reference-manifest.js +1 -1
  79. package/dist/web/standalone/.next/server/app/api/session/events/route.js +2 -2
  80. package/dist/web/standalone/.next/server/app/api/session/events/route_client-reference-manifest.js +1 -1
  81. package/dist/web/standalone/.next/server/app/api/session/manage/route.js +1 -1
  82. package/dist/web/standalone/.next/server/app/api/session/manage/route_client-reference-manifest.js +1 -1
  83. package/dist/web/standalone/.next/server/app/api/settings-data/route.js +1 -1
  84. package/dist/web/standalone/.next/server/app/api/settings-data/route_client-reference-manifest.js +1 -1
  85. package/dist/web/standalone/.next/server/app/api/shutdown/route.js +1 -1
  86. package/dist/web/standalone/.next/server/app/api/shutdown/route_client-reference-manifest.js +1 -1
  87. package/dist/web/standalone/.next/server/app/api/skill-health/route.js +1 -1
  88. package/dist/web/standalone/.next/server/app/api/skill-health/route_client-reference-manifest.js +1 -1
  89. package/dist/web/standalone/.next/server/app/api/steer/route.js +1 -1
  90. package/dist/web/standalone/.next/server/app/api/steer/route_client-reference-manifest.js +1 -1
  91. package/dist/web/standalone/.next/server/app/api/switch-root/route.js +1 -1
  92. package/dist/web/standalone/.next/server/app/api/switch-root/route_client-reference-manifest.js +1 -1
  93. package/dist/web/standalone/.next/server/app/api/terminal/input/route.js +2 -2
  94. package/dist/web/standalone/.next/server/app/api/terminal/input/route_client-reference-manifest.js +1 -1
  95. package/dist/web/standalone/.next/server/app/api/terminal/resize/route.js +2 -2
  96. package/dist/web/standalone/.next/server/app/api/terminal/resize/route_client-reference-manifest.js +1 -1
  97. package/dist/web/standalone/.next/server/app/api/terminal/sessions/route.js +2 -2
  98. package/dist/web/standalone/.next/server/app/api/terminal/sessions/route_client-reference-manifest.js +1 -1
  99. package/dist/web/standalone/.next/server/app/api/terminal/stream/route.js +4 -4
  100. package/dist/web/standalone/.next/server/app/api/terminal/stream/route_client-reference-manifest.js +1 -1
  101. package/dist/web/standalone/.next/server/app/api/terminal/upload/route.js +1 -1
  102. package/dist/web/standalone/.next/server/app/api/terminal/upload/route_client-reference-manifest.js +1 -1
  103. package/dist/web/standalone/.next/server/app/api/undo/route.js +1 -1
  104. package/dist/web/standalone/.next/server/app/api/undo/route_client-reference-manifest.js +1 -1
  105. package/dist/web/standalone/.next/server/app/api/update/route.js +1 -1
  106. package/dist/web/standalone/.next/server/app/api/update/route_client-reference-manifest.js +1 -1
  107. package/dist/web/standalone/.next/server/app/api/visualizer/route.js +1 -1
  108. package/dist/web/standalone/.next/server/app/api/visualizer/route_client-reference-manifest.js +1 -1
  109. package/dist/web/standalone/.next/server/app/index.html +1 -1
  110. package/dist/web/standalone/.next/server/app/index.rsc +4 -4
  111. package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +2 -2
  112. package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +4 -4
  113. package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
  114. package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +3 -3
  115. package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
  116. package/dist/web/standalone/.next/server/app/page.js +2 -2
  117. package/dist/web/standalone/.next/server/app/page_client-reference-manifest.js +1 -1
  118. package/dist/web/standalone/.next/server/app-paths-manifest.json +14 -14
  119. package/dist/web/standalone/.next/server/chunks/229.js +1 -1
  120. package/dist/web/standalone/.next/server/chunks/471.js +3 -3
  121. package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
  122. package/dist/web/standalone/.next/server/middleware.js +2 -2
  123. package/dist/web/standalone/.next/server/next-font-manifest.js +1 -1
  124. package/dist/web/standalone/.next/server/next-font-manifest.json +1 -1
  125. package/dist/web/standalone/.next/server/pages/404.html +1 -1
  126. package/dist/web/standalone/.next/server/pages/500.html +2 -2
  127. package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
  128. package/dist/web/standalone/.next/static/chunks/app/_not-found/{page-f2a7482d42a5614b.js → page-2f24283c162b6ab3.js} +1 -1
  129. package/dist/web/standalone/.next/static/chunks/app/{layout-a16c7a7ecdf0c2cf.js → layout-9ecfd95f343793f0.js} +1 -1
  130. package/dist/web/standalone/.next/static/chunks/app/page-7e9530a7122506c5.js +1 -0
  131. package/dist/web/standalone/.next/static/chunks/main-app-d3d4c336195465f9.js +1 -0
  132. package/dist/web/standalone/.next/static/chunks/next/dist/client/components/builtin/global-error-ab5a8926e07ec673.js +1 -0
  133. package/dist/web/standalone/node_modules/node-pty/build/Makefile +2 -2
  134. package/dist/web/standalone/node_modules/node-pty/build/Release/pty.node +0 -0
  135. package/dist/web/standalone/node_modules/node-pty/build/pty.target.mk +14 -14
  136. package/dist/web/standalone/node_modules/node-pty/node-addon-api/node_addon_api.target.mk +14 -14
  137. package/dist/web/standalone/node_modules/node-pty/node-addon-api/node_addon_api_except.target.mk +14 -14
  138. package/dist/web/standalone/node_modules/node-pty/node-addon-api/node_addon_api_maybe.target.mk +14 -14
  139. package/dist/web/standalone/server.js +1 -1
  140. package/package.json +1 -1
  141. package/packages/pi-coding-agent/dist/core/auth-storage.test.js +8 -6
  142. package/packages/pi-coding-agent/dist/core/auth-storage.test.js.map +1 -1
  143. package/packages/pi-coding-agent/dist/core/extensions/runner.test.js +26 -24
  144. package/packages/pi-coding-agent/dist/core/extensions/runner.test.js.map +1 -1
  145. package/packages/pi-coding-agent/dist/core/fs-utils.test.js +48 -29
  146. package/packages/pi-coding-agent/dist/core/fs-utils.test.js.map +1 -1
  147. package/packages/pi-coding-agent/dist/core/resolve-config-value.test.js +44 -34
  148. package/packages/pi-coding-agent/dist/core/resolve-config-value.test.js.map +1 -1
  149. package/packages/pi-coding-agent/dist/core/session-manager.test.js +34 -30
  150. package/packages/pi-coding-agent/dist/core/session-manager.test.js.map +1 -1
  151. package/packages/pi-coding-agent/dist/core/tools/edit-diff.test.js +12 -10
  152. package/packages/pi-coding-agent/dist/core/tools/edit-diff.test.js.map +1 -1
  153. package/packages/pi-coding-agent/dist/resources/extensions/memory/storage.test.js +47 -43
  154. package/packages/pi-coding-agent/dist/resources/extensions/memory/storage.test.js.map +1 -1
  155. package/packages/pi-coding-agent/src/core/auth-storage.test.ts +7 -7
  156. package/packages/pi-coding-agent/src/core/extensions/runner.test.ts +26 -26
  157. package/packages/pi-coding-agent/src/core/fs-utils.test.ts +43 -31
  158. package/packages/pi-coding-agent/src/core/resolve-config-value.test.ts +45 -40
  159. package/packages/pi-coding-agent/src/core/session-manager.test.ts +33 -33
  160. package/packages/pi-coding-agent/src/core/tools/edit-diff.test.ts +17 -17
  161. package/packages/pi-coding-agent/src/resources/extensions/memory/storage.test.ts +74 -74
  162. package/src/resources/extensions/gsd/auto-start.ts +0 -14
  163. package/src/resources/extensions/gsd/commands/handlers/workflow.ts +0 -8
  164. package/src/resources/extensions/gsd/tests/all-milestones-complete-merge.test.ts +99 -99
  165. package/src/resources/extensions/gsd/tests/auto-lock-creation.test.ts +16 -14
  166. package/src/resources/extensions/gsd/tests/auto-paused-session-validation.test.ts +57 -43
  167. package/src/resources/extensions/gsd/tests/auto-preflight.test.ts +13 -11
  168. package/src/resources/extensions/gsd/tests/auto-recovery.test.ts +523 -465
  169. package/src/resources/extensions/gsd/tests/auto-secrets-gate.test.ts +75 -73
  170. package/src/resources/extensions/gsd/tests/auto-start-needs-discussion.test.ts +56 -34
  171. package/src/resources/extensions/gsd/tests/auto-worktree-milestone-merge.test.ts +656 -533
  172. package/src/resources/extensions/gsd/tests/auto-worktree.test.ts +143 -165
  173. package/src/resources/extensions/gsd/tests/cache-staleness-regression.test.ts +52 -29
  174. package/src/resources/extensions/gsd/tests/captures.test.ts +176 -148
  175. package/src/resources/extensions/gsd/tests/claude-import-tui.test.ts +33 -32
  176. package/src/resources/extensions/gsd/tests/collect-from-manifest.test.ts +143 -141
  177. package/src/resources/extensions/gsd/tests/commands-inspect-open-db.test.ts +25 -25
  178. package/src/resources/extensions/gsd/tests/commands-logs.test.ts +81 -81
  179. package/src/resources/extensions/gsd/tests/complete-milestone.test.ts +59 -38
  180. package/src/resources/extensions/gsd/tests/complete-slice.test.ts +263 -228
  181. package/src/resources/extensions/gsd/tests/complete-task.test.ts +302 -250
  182. package/src/resources/extensions/gsd/tests/context-store.test.ts +367 -354
  183. package/src/resources/extensions/gsd/tests/continue-here.test.ts +72 -68
  184. package/src/resources/extensions/gsd/tests/cost-projection.test.ts +106 -92
  185. package/src/resources/extensions/gsd/tests/crash-recovery.test.ts +35 -27
  186. package/src/resources/extensions/gsd/tests/dashboard-budget.test.ts +237 -220
  187. package/src/resources/extensions/gsd/tests/db-writer.test.ts +420 -390
  188. package/src/resources/extensions/gsd/tests/definition-loader.test.ts +92 -76
  189. package/src/resources/extensions/gsd/tests/derive-state-crossval.test.ts +83 -68
  190. package/src/resources/extensions/gsd/tests/derive-state-db.test.ts +183 -152
  191. package/src/resources/extensions/gsd/tests/derive-state-deps.test.ts +101 -78
  192. package/src/resources/extensions/gsd/tests/derive-state.test.ts +227 -192
  193. package/src/resources/extensions/gsd/tests/detection.test.ts +278 -232
  194. package/src/resources/extensions/gsd/tests/dev-engine-wrapper.test.ts +34 -30
  195. package/src/resources/extensions/gsd/tests/dispatch-guard.test.ts +180 -164
  196. package/src/resources/extensions/gsd/tests/dispatch-missing-task-plans.test.ts +49 -43
  197. package/src/resources/extensions/gsd/tests/dispatch-uat-last-completed.test.ts +32 -28
  198. package/src/resources/extensions/gsd/tests/doctor-completion-deferral.test.ts +29 -27
  199. package/src/resources/extensions/gsd/tests/doctor-delimiter-fix.test.ts +38 -34
  200. package/src/resources/extensions/gsd/tests/doctor-enhancements.test.ts +75 -54
  201. package/src/resources/extensions/gsd/tests/doctor-environment-worktree.test.ts +32 -21
  202. package/src/resources/extensions/gsd/tests/doctor-environment.test.ts +97 -72
  203. package/src/resources/extensions/gsd/tests/doctor-fixlevel.test.ts +44 -38
  204. package/src/resources/extensions/gsd/tests/doctor-git.test.ts +145 -104
  205. package/src/resources/extensions/gsd/tests/doctor-proactive.test.ts +106 -84
  206. package/src/resources/extensions/gsd/tests/doctor-roadmap-summary-atomicity.test.ts +60 -54
  207. package/src/resources/extensions/gsd/tests/doctor-runtime.test.ts +93 -72
  208. package/src/resources/extensions/gsd/tests/doctor.test.ts +134 -104
  209. package/src/resources/extensions/gsd/tests/ensure-db-open.test.ts +131 -123
  210. package/src/resources/extensions/gsd/tests/exit-command.test.ts +24 -20
  211. package/src/resources/extensions/gsd/tests/feature-branch-lifecycle-integration.test.ts +57 -48
  212. package/src/resources/extensions/gsd/tests/files-loadfile-eisdir.test.ts +7 -5
  213. package/src/resources/extensions/gsd/tests/flag-file-db.test.ts +42 -30
  214. package/src/resources/extensions/gsd/tests/freeform-decisions.test.ts +206 -198
  215. package/src/resources/extensions/gsd/tests/git-locale.test.ts +27 -13
  216. package/src/resources/extensions/gsd/tests/git-service.test.ts +388 -285
  217. package/src/resources/extensions/gsd/tests/gitignore-tracked-gsd.test.ts +39 -31
  218. package/src/resources/extensions/gsd/tests/graph-operations.test.ts +69 -63
  219. package/src/resources/extensions/gsd/tests/gsd-db.test.ts +264 -255
  220. package/src/resources/extensions/gsd/tests/gsd-inspect.test.ts +119 -108
  221. package/src/resources/extensions/gsd/tests/gsd-recover.test.ts +103 -81
  222. package/src/resources/extensions/gsd/tests/gsd-tools.test.ts +262 -229
  223. package/src/resources/extensions/gsd/tests/headless-answers.test.ts +13 -13
  224. package/src/resources/extensions/gsd/tests/health-widget.test.ts +37 -29
  225. package/src/resources/extensions/gsd/tests/idle-recovery.test.ts +102 -81
  226. package/src/resources/extensions/gsd/tests/init-wizard.test.ts +18 -16
  227. package/src/resources/extensions/gsd/tests/integration-edge.test.ts +46 -41
  228. package/src/resources/extensions/gsd/tests/integration-lifecycle.test.ts +53 -42
  229. package/src/resources/extensions/gsd/tests/integration-mixed-milestones.test.ts +91 -75
  230. package/src/resources/extensions/gsd/tests/integration-proof.test.ts +18 -18
  231. package/src/resources/extensions/gsd/tests/markdown-renderer.test.ts +194 -150
  232. package/src/resources/extensions/gsd/tests/md-importer.test.ts +125 -101
  233. package/src/resources/extensions/gsd/tests/memory-extractor.test.ts +54 -45
  234. package/src/resources/extensions/gsd/tests/memory-store.test.ts +93 -80
  235. package/src/resources/extensions/gsd/tests/migrate-command.test.ts +66 -57
  236. package/src/resources/extensions/gsd/tests/migrate-hierarchy.test.ts +93 -83
  237. package/src/resources/extensions/gsd/tests/migrate-parser.test.ts +170 -161
  238. package/src/resources/extensions/gsd/tests/migrate-transformer.test.ts +141 -125
  239. package/src/resources/extensions/gsd/tests/migrate-validator-parsers.test.ts +131 -107
  240. package/src/resources/extensions/gsd/tests/migrate-writer-integration.test.ts +96 -87
  241. package/src/resources/extensions/gsd/tests/migrate-writer.test.ts +164 -125
  242. package/src/resources/extensions/gsd/tests/must-have-parser.test.ts +94 -81
  243. package/src/resources/extensions/gsd/tests/none-mode-gates.test.ts +36 -35
  244. package/src/resources/extensions/gsd/tests/overrides.test.ts +106 -99
  245. package/src/resources/extensions/gsd/tests/parallel-crash-recovery.test.ts +47 -40
  246. package/src/resources/extensions/gsd/tests/parallel-worker-monitoring.test.ts +28 -25
  247. package/src/resources/extensions/gsd/tests/parallel-workers-multi-milestone-e2e.test.ts +83 -66
  248. package/src/resources/extensions/gsd/tests/park-edge-cases.test.ts +77 -54
  249. package/src/resources/extensions/gsd/tests/park-milestone.test.ts +115 -68
  250. package/src/resources/extensions/gsd/tests/parsers.test.ts +611 -546
  251. package/src/resources/extensions/gsd/tests/paths.test.ts +87 -72
  252. package/src/resources/extensions/gsd/tests/post-unit-hooks.test.ts +117 -77
  253. package/src/resources/extensions/gsd/tests/prompt-db.test.ts +56 -56
  254. package/src/resources/extensions/gsd/tests/queue-draft-detection.test.ts +119 -93
  255. package/src/resources/extensions/gsd/tests/queue-order.test.ts +82 -70
  256. package/src/resources/extensions/gsd/tests/queue-reorder-e2e.test.ts +55 -42
  257. package/src/resources/extensions/gsd/tests/quick-branch-lifecycle.test.ts +73 -45
  258. package/src/resources/extensions/gsd/tests/reassess-prompt.test.ts +38 -28
  259. package/src/resources/extensions/gsd/tests/replan-slice.test.ts +80 -73
  260. package/src/resources/extensions/gsd/tests/repo-identity-worktree.test.ts +74 -71
  261. package/src/resources/extensions/gsd/tests/requirements.test.ts +75 -70
  262. package/src/resources/extensions/gsd/tests/retry-state-reset.test.ts +66 -44
  263. package/src/resources/extensions/gsd/tests/roadmap-parse-regression.test.ts +181 -114
  264. package/src/resources/extensions/gsd/tests/rule-registry.test.ts +65 -63
  265. package/src/resources/extensions/gsd/tests/run-uat.test.ts +128 -66
  266. package/src/resources/extensions/gsd/tests/session-lock-multipath.test.ts +25 -18
  267. package/src/resources/extensions/gsd/tests/session-lock-regression.test.ts +44 -37
  268. package/src/resources/extensions/gsd/tests/shared-wal.test.ts +26 -19
  269. package/src/resources/extensions/gsd/tests/stalled-tool-recovery.test.ts +8 -6
  270. package/src/resources/extensions/gsd/tests/symlink-numbered-variants.test.ts +28 -22
  271. package/src/resources/extensions/gsd/tests/token-savings.test.ts +56 -54
  272. package/src/resources/extensions/gsd/tests/tool-call-loop-guard.test.ts +25 -23
  273. package/src/resources/extensions/gsd/tests/tool-naming.test.ts +11 -9
  274. package/src/resources/extensions/gsd/tests/unique-milestone-ids.test.ts +82 -66
  275. package/src/resources/extensions/gsd/tests/unit-runtime.test.ts +47 -46
  276. package/src/resources/extensions/gsd/tests/visualizer-critical-path.test.ts +22 -20
  277. package/src/resources/extensions/gsd/tests/visualizer-data.test.ts +86 -84
  278. package/src/resources/extensions/gsd/tests/visualizer-overlay.test.ts +43 -41
  279. package/src/resources/extensions/gsd/tests/visualizer-views.test.ts +96 -94
  280. package/src/resources/extensions/gsd/tests/windows-path-normalization.test.ts +13 -11
  281. package/src/resources/extensions/gsd/tests/worker-registry.test.ts +29 -27
  282. package/src/resources/extensions/gsd/tests/workflow-templates.test.ts +52 -50
  283. package/src/resources/extensions/gsd/tests/worktree-bugfix.test.ts +13 -10
  284. package/src/resources/extensions/gsd/tests/worktree-db-integration.test.ts +18 -14
  285. package/src/resources/extensions/gsd/tests/worktree-db.test.ts +39 -38
  286. package/src/resources/extensions/gsd/tests/worktree-e2e.test.ts +21 -17
  287. package/src/resources/extensions/gsd/tests/worktree-health.test.ts +30 -25
  288. package/src/resources/extensions/gsd/tests/worktree-integration.test.ts +37 -30
  289. package/src/resources/extensions/gsd/tests/worktree-symlink-removal.test.ts +22 -15
  290. package/src/resources/extensions/gsd/tests/worktree-sync-milestones.test.ts +66 -59
  291. package/src/resources/extensions/gsd/tests/worktree.test.ts +50 -44
  292. package/dist/web/standalone/.next/static/chunks/app/page-b9367c5ae13b99c6.js +0 -1
  293. package/dist/web/standalone/.next/static/chunks/main-app-fdab67f7802d7832.js +0 -1
  294. package/dist/web/standalone/.next/static/chunks/next/dist/client/components/builtin/global-error-459824ffb8c323dd.js +0 -1
  295. package/src/resources/extensions/gsd/tests/quick-auto-guard.test.ts +0 -100
  296. package/src/resources/extensions/gsd/tests/sqlite-unavailable-gate.test.ts +0 -63
  297. /package/dist/web/standalone/.next/static/{-zps1Q9mQmioAKLcQiCr8 → mgkxN0mGP6gSUmGPEzbk_}/_buildManifest.js +0 -0
  298. /package/dist/web/standalone/.next/static/{-zps1Q9mQmioAKLcQiCr8 → mgkxN0mGP6gSUmGPEzbk_}/_ssgManifest.js +0 -0
@@ -20,11 +20,11 @@ import {
20
20
  parseSliceBranch,
21
21
  } from '../worktree.ts';
22
22
  import { clearPathCache } from '../paths.ts';
23
- import { describe, test, beforeEach, afterEach } from 'node:test';
24
- import assert from 'node:assert/strict';
23
+ import { createTestContext } from './test-helpers.ts';
25
24
 
26
25
  // ─── Assertion Helpers ────────────────────────────────────────────────────
27
26
 
27
+ const { assertEq, assertTrue, assertMatch, report } = createTestContext();
28
28
  // ─── Fixture Helpers ──────────────────────────────────────────────────────
29
29
 
30
30
  function createFixtureBase(): string {
@@ -79,9 +79,11 @@ function createGitRepo(): string {
79
79
  // Test Groups
80
80
  // ═══════════════════════════════════════════════════════════════════════════
81
81
 
82
- // ─── Group 1: deriveState with new-format-only milestones ─────────────
82
+ async function main(): Promise<void> {
83
83
 
84
- test('Group 1: deriveState with new-format-only milestones', async () => {
84
+ // ─── Group 1: deriveState with new-format-only milestones ─────────────
85
+ console.log('\n=== Group 1: deriveState with new-format-only milestones ===');
86
+ {
85
87
  const base = createFixtureBase();
86
88
  try {
87
89
  // Create M001-abc123 with roadmap + 2 slices (S01 complete, S02 in-progress)
@@ -123,32 +125,32 @@ test('Group 1: deriveState with new-format-only milestones', async () => {
123
125
  const state = await deriveState(base);
124
126
 
125
127
  // Phase should be executing (active milestone with incomplete slice + plan + tasks)
126
- assert.deepStrictEqual(state.phase, 'executing', 'G1: phase is executing');
127
- assert.ok(state.activeMilestone !== null, 'G1: activeMilestone is not null');
128
- assert.deepStrictEqual(state.activeMilestone?.id, 'M001-abc123', 'G1: activeMilestone id is M001-abc123');
129
- assert.deepStrictEqual(state.activeMilestone?.title, 'Test Feature', 'G1: title stripped to Test Feature');
128
+ assertEq(state.phase, 'executing', 'G1: phase is executing');
129
+ assertTrue(state.activeMilestone !== null, 'G1: activeMilestone is not null');
130
+ assertEq(state.activeMilestone?.id, 'M001-abc123', 'G1: activeMilestone id is M001-abc123');
131
+ assertEq(state.activeMilestone?.title, 'Test Feature', 'G1: title stripped to Test Feature');
130
132
 
131
133
  // Registry
132
- assert.deepStrictEqual(state.registry.length, 1, 'G1: registry has 1 entry');
133
- assert.deepStrictEqual(state.registry[0]?.id, 'M001-abc123', 'G1: registry entry id');
134
- assert.deepStrictEqual(state.registry[0]?.status, 'active', 'G1: registry entry status is active');
135
- assert.deepStrictEqual(state.registry[0]?.title, 'Test Feature', 'G1: registry title stripped');
134
+ assertEq(state.registry.length, 1, 'G1: registry has 1 entry');
135
+ assertEq(state.registry[0]?.id, 'M001-abc123', 'G1: registry entry id');
136
+ assertEq(state.registry[0]?.status, 'active', 'G1: registry entry status is active');
137
+ assertEq(state.registry[0]?.title, 'Test Feature', 'G1: registry title stripped');
136
138
 
137
139
  // Active slice
138
- assert.ok(state.activeSlice !== null, 'G1: activeSlice is not null');
139
- assert.deepStrictEqual(state.activeSlice?.id, 'S02', 'G1: activeSlice is S02');
140
+ assertTrue(state.activeSlice !== null, 'G1: activeSlice is not null');
141
+ assertEq(state.activeSlice?.id, 'S02', 'G1: activeSlice is S02');
140
142
 
141
143
  // Progress
142
- assert.deepStrictEqual(state.progress?.milestones?.done, 0, 'G1: milestones done = 0');
143
- assert.deepStrictEqual(state.progress?.milestones?.total, 1, 'G1: milestones total = 1');
144
+ assertEq(state.progress?.milestones?.done, 0, 'G1: milestones done = 0');
145
+ assertEq(state.progress?.milestones?.total, 1, 'G1: milestones total = 1');
144
146
  } finally {
145
147
  cleanup(base);
146
148
  }
147
- });
149
+ }
148
150
 
149
151
  // ─── Group 2: deriveState with mixed-format milestones ────────────────
150
-
151
- test('Group 2: deriveState with mixed old+new format milestones', async () => {
152
+ console.log('\n=== Group 2: deriveState with mixed old+new format milestones ===');
153
+ {
152
154
  const base = createFixtureBase();
153
155
  try {
154
156
  // M001 — complete milestone (all slices done + summary)
@@ -215,40 +217,40 @@ Everything worked.
215
217
  const state = await deriveState(base);
216
218
 
217
219
  // Registry — should have 2 entries sorted by seq number
218
- assert.deepStrictEqual(state.registry.length, 2, 'G2: registry has 2 entries');
219
- assert.deepStrictEqual(state.registry[0]?.id, 'M001', 'G2: registry[0] is M001 (sorted first)');
220
- assert.deepStrictEqual(state.registry[1]?.id, 'M002-abc123', 'G2: registry[1] is M002-abc123 (sorted second)');
220
+ assertEq(state.registry.length, 2, 'G2: registry has 2 entries');
221
+ assertEq(state.registry[0]?.id, 'M001', 'G2: registry[0] is M001 (sorted first)');
222
+ assertEq(state.registry[1]?.id, 'M002-abc123', 'G2: registry[1] is M002-abc123 (sorted second)');
221
223
 
222
224
  // M001 is complete
223
- assert.deepStrictEqual(state.registry[0]?.status, 'complete', 'G2: M001 status is complete');
224
- assert.deepStrictEqual(state.registry[0]?.title, 'Legacy Feature', 'G2: M001 title stripped');
225
+ assertEq(state.registry[0]?.status, 'complete', 'G2: M001 status is complete');
226
+ assertEq(state.registry[0]?.title, 'Legacy Feature', 'G2: M001 title stripped');
225
227
 
226
228
  // M002-abc123 is active
227
- assert.deepStrictEqual(state.registry[1]?.status, 'active', 'G2: M002-abc123 status is active');
228
- assert.deepStrictEqual(state.registry[1]?.title, 'New Feature', 'G2: M002-abc123 title stripped');
229
+ assertEq(state.registry[1]?.status, 'active', 'G2: M002-abc123 status is active');
230
+ assertEq(state.registry[1]?.title, 'New Feature', 'G2: M002-abc123 title stripped');
229
231
 
230
232
  // Active milestone
231
- assert.ok(state.activeMilestone !== null, 'G2: activeMilestone is not null');
232
- assert.deepStrictEqual(state.activeMilestone?.id, 'M002-abc123', 'G2: activeMilestone is M002-abc123');
233
- assert.deepStrictEqual(state.activeMilestone?.title, 'New Feature', 'G2: activeMilestone title stripped');
233
+ assertTrue(state.activeMilestone !== null, 'G2: activeMilestone is not null');
234
+ assertEq(state.activeMilestone?.id, 'M002-abc123', 'G2: activeMilestone is M002-abc123');
235
+ assertEq(state.activeMilestone?.title, 'New Feature', 'G2: activeMilestone title stripped');
234
236
 
235
237
  // Phase
236
- assert.deepStrictEqual(state.phase, 'executing', 'G2: phase is executing');
238
+ assertEq(state.phase, 'executing', 'G2: phase is executing');
237
239
 
238
240
  // Active slice
239
- assert.deepStrictEqual(state.activeSlice?.id, 'S02', 'G2: activeSlice is S02');
241
+ assertEq(state.activeSlice?.id, 'S02', 'G2: activeSlice is S02');
240
242
 
241
243
  // Progress
242
- assert.deepStrictEqual(state.progress?.milestones?.done, 1, 'G2: milestones done = 1');
243
- assert.deepStrictEqual(state.progress?.milestones?.total, 2, 'G2: milestones total = 2');
244
+ assertEq(state.progress?.milestones?.done, 1, 'G2: milestones done = 1');
245
+ assertEq(state.progress?.milestones?.total, 2, 'G2: milestones total = 2');
244
246
  } finally {
245
247
  cleanup(base);
246
248
  }
247
- });
249
+ }
248
250
 
249
251
  // ─── Group 3: indexWorkspace with mixed-format milestones ─────────────
250
-
251
- test('Group 3: indexWorkspace with mixed-format milestones', async () => {
252
+ console.log('\n=== Group 3: indexWorkspace with mixed-format milestones ===');
253
+ {
252
254
  const base = createFixtureBase();
253
255
  try {
254
256
  // Same fixture as Group 2: M001 (complete) + M002-abc123 (active)
@@ -302,39 +304,39 @@ Everything worked.
302
304
  const index = await indexWorkspace(base);
303
305
 
304
306
  // Both milestones indexed
305
- assert.deepStrictEqual(index.milestones.length, 2, 'G3: 2 milestones in index');
306
- assert.deepStrictEqual(index.milestones[0]?.id, 'M001', 'G3: index[0] is M001');
307
- assert.deepStrictEqual(index.milestones[1]?.id, 'M002-abc123', 'G3: index[1] is M002-abc123');
307
+ assertEq(index.milestones.length, 2, 'G3: 2 milestones in index');
308
+ assertEq(index.milestones[0]?.id, 'M001', 'G3: index[0] is M001');
309
+ assertEq(index.milestones[1]?.id, 'M002-abc123', 'G3: index[1] is M002-abc123');
308
310
 
309
311
  // Titles stripped from both formats
310
- assert.deepStrictEqual(index.milestones[0]?.title, 'Legacy Feature', 'G3: M001 title stripped');
311
- assert.deepStrictEqual(index.milestones[1]?.title, 'New Feature', 'G3: M002-abc123 title stripped');
312
+ assertEq(index.milestones[0]?.title, 'Legacy Feature', 'G3: M001 title stripped');
313
+ assertEq(index.milestones[1]?.title, 'New Feature', 'G3: M002-abc123 title stripped');
312
314
 
313
315
  // Active state
314
- assert.deepStrictEqual(index.active.milestoneId, 'M002-abc123', 'G3: active milestone is M002-abc123');
315
- assert.deepStrictEqual(index.active.sliceId, 'S01', 'G3: active slice is S01');
316
+ assertEq(index.active.milestoneId, 'M002-abc123', 'G3: active milestone is M002-abc123');
317
+ assertEq(index.active.sliceId, 'S01', 'G3: active slice is S01');
316
318
 
317
319
  // Scopes include new-format paths
318
- assert.ok(
320
+ assertTrue(
319
321
  index.scopes.some(s => s.scope === 'M002-abc123'),
320
322
  'G3: scope includes M002-abc123 milestone',
321
323
  );
322
- assert.ok(
324
+ assertTrue(
323
325
  index.scopes.some(s => s.scope === 'M002-abc123/S01'),
324
326
  'G3: scope includes M002-abc123/S01 slice',
325
327
  );
326
- assert.ok(
328
+ assertTrue(
327
329
  index.scopes.some(s => s.scope === 'M002-abc123/S01/T01'),
328
330
  'G3: scope includes M002-abc123/S01/T01 task',
329
331
  );
330
332
  } finally {
331
333
  cleanup(base);
332
334
  }
333
- });
335
+ }
334
336
 
335
337
  // ─── Group 4: inlinePriorMilestoneSummary with mixed formats ──────────
336
-
337
- test('Group 4: inlinePriorMilestoneSummary with mixed formats', async () => {
338
+ console.log('\n=== Group 4: inlinePriorMilestoneSummary with mixed formats ===');
339
+ {
338
340
  const base = createFixtureBase();
339
341
  try {
340
342
  // M001 — completed with summary
@@ -356,21 +358,21 @@ Built the legacy feature successfully.
356
358
  const result = await inlinePriorMilestoneSummary('M002-abc123', base);
357
359
 
358
360
  // Result should be non-null (M001 is before M002-abc123)
359
- assert.ok(result !== null, 'G4: result is non-null');
360
- assert.ok(typeof result === 'string', 'G4: result is a string');
361
+ assertTrue(result !== null, 'G4: result is non-null');
362
+ assertTrue(typeof result === 'string', 'G4: result is a string');
361
363
 
362
364
  // Should contain the M001 summary content
363
- assert.ok(result!.includes('Prior Milestone Summary'), 'G4: contains Prior Milestone Summary header');
364
- assert.ok(result!.includes('Built the legacy feature successfully'), 'G4: contains M001 summary content');
365
- assert.ok(result!.includes('Used old format for milestone IDs'), 'G4: contains M001 key decisions');
365
+ assertTrue(result!.includes('Prior Milestone Summary'), 'G4: contains Prior Milestone Summary header');
366
+ assertTrue(result!.includes('Built the legacy feature successfully'), 'G4: contains M001 summary content');
367
+ assertTrue(result!.includes('Used old format for milestone IDs'), 'G4: contains M001 key decisions');
366
368
  } finally {
367
369
  cleanup(base);
368
370
  }
369
- });
371
+ }
370
372
 
371
373
  // ─── Group 5: dispatch-guard with new-format milestones ──────────────
372
-
373
- test('Group 5: dispatch-guard with new-format milestones', () => {
374
+ console.log('\n=== Group 5: dispatch-guard with new-format milestones ===');
375
+ {
374
376
  const base = createGitRepo();
375
377
  try {
376
378
  // M001-abc123: all slices complete
@@ -401,28 +403,28 @@ test('Group 5: dispatch-guard with new-format milestones', () => {
401
403
  run('git commit -m init', base);
402
404
 
403
405
  // No blocker: M001-abc123 is complete, dispatching M002-abc123/S01
404
- assert.deepStrictEqual(
406
+ assertEq(
405
407
  getPriorSliceCompletionBlocker(base, 'main', 'plan-slice', 'M002-abc123/S01'),
406
408
  null,
407
409
  'G5: no blocker for M002-abc123/S01 when M001-abc123 all complete',
408
410
  );
409
411
 
410
412
  // No blocker for first slice of first milestone
411
- assert.deepStrictEqual(
413
+ assertEq(
412
414
  getPriorSliceCompletionBlocker(base, 'main', 'execute-task', 'M001-abc123/S01/T01'),
413
415
  null,
414
416
  'G5: no blocker for M001-abc123/S01/T01 (first milestone first slice)',
415
417
  );
416
418
 
417
419
  // Blocker: trying to dispatch M002-abc123/S02 when S01 is incomplete
418
- assert.match(
420
+ assertMatch(
419
421
  getPriorSliceCompletionBlocker(base, 'main', 'execute-task', 'M002-abc123/S02/T01') ?? '',
420
422
  /M002-abc123\/S01 is not complete/,
421
423
  'G5: blocks M002-abc123/S02 when S01 incomplete',
422
424
  );
423
425
 
424
426
  // Non-slice dispatch type should not be blocked
425
- assert.deepStrictEqual(
427
+ assertEq(
426
428
  getPriorSliceCompletionBlocker(base, 'main', 'plan-milestone', 'M002-abc123'),
427
429
  null,
428
430
  'G5: non-slice dispatch type not blocked',
@@ -445,7 +447,7 @@ test('Group 5: dispatch-guard with new-format milestones', () => {
445
447
 
446
448
  // M001 (seq=1) < M001-abc123 (seq=1) — but M001 has incomplete S02
447
449
  // Since M001 seq=1 and M002-abc123 seq=2, blocker should reference M001/S02
448
- assert.match(
450
+ assertMatch(
449
451
  getPriorSliceCompletionBlocker(base, 'main', 'plan-slice', 'M002-abc123/S01') ?? '',
450
452
  /earlier slice M001\/S02 is not complete/,
451
453
  'G5: mixed-format blocker references M001/S02',
@@ -466,7 +468,7 @@ test('Group 5: dispatch-guard with new-format milestones', () => {
466
468
  run('git commit -m complete-m001', base);
467
469
  clearPathCache();
468
470
 
469
- assert.deepStrictEqual(
471
+ assertEq(
470
472
  getPriorSliceCompletionBlocker(base, 'main', 'plan-slice', 'M002-abc123/S01'),
471
473
  null,
472
474
  'G5: no blocker after M001 completed (mixed format)',
@@ -474,7 +476,7 @@ test('Group 5: dispatch-guard with new-format milestones', () => {
474
476
 
475
477
  // M001-abc123 still has all complete, M002-abc123/S01 still incomplete
476
478
  // Check that S02 of M002-abc123 is still blocked by its own S01
477
- assert.match(
479
+ assertMatch(
478
480
  getPriorSliceCompletionBlocker(base, 'main', 'execute-task', 'M002-abc123/S02/T01') ?? '',
479
481
  /M002-abc123\/S01 is not complete/,
480
482
  'G5: intra-milestone blocker still works in mixed-format context',
@@ -506,7 +508,7 @@ test('Group 5: dispatch-guard with new-format milestones', () => {
506
508
  run('git commit -m add-m003', base);
507
509
  clearPathCache();
508
510
 
509
- assert.match(
511
+ assertMatch(
510
512
  getPriorSliceCompletionBlocker(base, 'main', 'execute-task', 'M003-xyz789/S02/T01') ?? '',
511
513
  /earlier slice M003-xyz789\/S01 is not complete/,
512
514
  'G5: positional path produces "earlier slice" message with new-format milestone ID',
@@ -514,13 +516,13 @@ test('Group 5: dispatch-guard with new-format milestones', () => {
514
516
  } finally {
515
517
  cleanup(base);
516
518
  }
517
- });
519
+ }
518
520
 
519
521
  // ─── Group 6: Branch name helpers with new-format IDs ───────────────
520
-
521
- test('Group 6: Branch name helpers with new-format IDs', () => {
522
+ console.log('\n=== Group 6: Branch name helpers with new-format IDs ===');
523
+ {
522
524
  // Test getSliceBranchName with new-format ID
523
- assert.deepStrictEqual(
525
+ assertEq(
524
526
  getSliceBranchName('M001-abc123', 'S01'),
525
527
  'gsd/M001-abc123/S01',
526
528
  'G6: getSliceBranchName returns gsd/M001-abc123/S01',
@@ -528,12 +530,26 @@ test('Group 6: Branch name helpers with new-format IDs', () => {
528
530
 
529
531
  // Test parseSliceBranch with new-format branch name
530
532
  const parsed = parseSliceBranch('gsd/M001-abc123/S01');
531
- assert.ok(parsed !== null, 'G6: parseSliceBranch returns non-null for new-format');
532
- assert.deepStrictEqual(parsed?.milestoneId, 'M001-abc123', 'G6: parsed milestoneId is M001-abc123');
533
- assert.deepStrictEqual(parsed?.sliceId, 'S01', 'G6: parsed sliceId is S01');
534
- assert.deepStrictEqual(parsed?.worktreeName, null, 'G6: parsed worktreeName is null (no worktree)');
535
- });
533
+ assertTrue(parsed !== null, 'G6: parseSliceBranch returns non-null for new-format');
534
+ assertEq(parsed?.milestoneId, 'M001-abc123', 'G6: parsed milestoneId is M001-abc123');
535
+ assertEq(parsed?.sliceId, 'S01', 'G6: parsed sliceId is S01');
536
+ assertEq(parsed?.worktreeName, null, 'G6: parsed worktreeName is null (no worktree)');
537
+ }
536
538
 
537
539
  // ─── Summary ──────────────────────────────────────────────────────────
540
+ report();
541
+ }
538
542
 
539
- // When run via vitest, wrap in test(); when run via tsx, call directly.
543
+ // When run via vitest, wrap in test(); when run via tsx, call directly.
544
+ const isVitest = typeof globalThis !== 'undefined' && (globalThis as any).__vitest_worker__?.config?.defines != null && 'vitest' in (globalThis as any).__vitest_worker__.config.defines || process.env.VITEST;
545
+ if (isVitest) {
546
+ const { test } = await import('node:test');
547
+ test('integration-mixed-milestones: all groups pass', async () => {
548
+ await main();
549
+ });
550
+ } else {
551
+ main().catch((error) => {
552
+ console.error(error);
553
+ process.exit(1);
554
+ });
555
+ }
@@ -278,12 +278,8 @@ test("full lifecycle: migration through completion through doctor", async (t) =>
278
278
  const base = createRealisticFixture();
279
279
  const dbPath = join(base, ".gsd", "gsd.db");
280
280
 
281
- t.after(() => {
282
- closeDatabase();
283
- rmSync(base, { recursive: true, force: true });
284
- });
285
-
286
- // ── (a) Open file-backed DB ──────────────────────────────────────
281
+ try {
282
+ // ── (a) Open file-backed DB ──────────────────────────────────────
287
283
  const opened = openDatabase(dbPath);
288
284
  assert.equal(opened, true, "DB should open successfully");
289
285
  assert.equal(isDbAvailable(), true, "DB should be available");
@@ -418,6 +414,10 @@ test("full lifecycle: migration through completion through doctor", async (t) =>
418
414
  const rogues = detectRogueFileWrites("execute-task", "M001/S01/T99", base);
419
415
  assert.ok(rogues.length > 0, "Should detect rogue file write for T99");
420
416
  assert.equal(rogues[0].unitId, "M001/S01/T99", "Rogue detection should identify the correct unit");
417
+ } finally {
418
+ closeDatabase();
419
+ rmSync(base, { recursive: true, force: true });
420
+ }
421
421
  });
422
422
 
423
423
  // ═══════════════════════════════════════════════════════════════════════════
@@ -429,12 +429,8 @@ test("recovery: DB loss → migrateFromMarkdown restores state, stale render det
429
429
  const base = createRealisticFixture();
430
430
  const dbPath = join(base, ".gsd", "gsd.db");
431
431
 
432
- t.after(() => {
433
- closeDatabase();
434
- rmSync(base, { recursive: true, force: true });
435
- });
436
-
437
- // Set up a completed state first
432
+ try {
433
+ // Set up a completed state first
438
434
  openDatabase(dbPath);
439
435
  migrateHierarchyToDb(base);
440
436
  await handleCompleteTask(makeCompleteTaskParams("T01"), base);
@@ -507,6 +503,10 @@ test("recovery: DB loss → migrateFromMarkdown restores state, stale render det
507
503
  const t2Recovered = getTask("M001", "S01", "T02");
508
504
  assert.ok(t2Recovered, "T02 should exist after recovery");
509
505
  assert.equal(t2Recovered!.status, "complete", "T02 should be complete after recovery");
506
+ } finally {
507
+ closeDatabase();
508
+ rmSync(base, { recursive: true, force: true });
509
+ }
510
510
  });
511
511
 
512
512
  // ═══════════════════════════════════════════════════════════════════════════
@@ -517,12 +517,8 @@ test("undo/reset: undo task and reset slice revert DB + markdown", async (t) =>
517
517
  const base = createRealisticFixture();
518
518
  const dbPath = join(base, ".gsd", "gsd.db");
519
519
 
520
- t.after(() => {
521
- closeDatabase();
522
- rmSync(base, { recursive: true, force: true });
523
- });
524
-
525
- // Build up completed state
520
+ try {
521
+ // Build up completed state
526
522
  openDatabase(dbPath);
527
523
  migrateHierarchyToDb(base);
528
524
  await handleCompleteTask(makeCompleteTaskParams("T01"), base);
@@ -640,4 +636,8 @@ test("undo/reset: undo task and reset slice revert DB + markdown", async (t) =>
640
636
  resetNotifs.some(n => n.level === "success"),
641
637
  "Reset should produce success notification",
642
638
  );
639
+ } finally {
640
+ closeDatabase();
641
+ rmSync(base, { recursive: true, force: true });
642
+ }
643
643
  });