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
@@ -73,7 +73,7 @@ describe("DevWorkflowEngine", () => {
73
73
  assert.equal(engine.engineId, "dev");
74
74
  });
75
75
 
76
- test("deriveState returns EngineState with expected fields", async (t) => {
76
+ test("deriveState returns EngineState with expected fields", async () => {
77
77
  const { DevWorkflowEngine } = await import("../dev-workflow-engine.ts");
78
78
  const engine = new DevWorkflowEngine();
79
79
 
@@ -81,29 +81,31 @@ describe("DevWorkflowEngine", () => {
81
81
  const tempDir = mkdtempSync(join(tmpdir(), "gsd-engine-test-"));
82
82
  mkdirSync(join(tempDir, ".gsd", "milestones"), { recursive: true });
83
83
 
84
- t.after(() => rmSync(tempDir, { recursive: true, force: true }));
85
-
86
- const state = await engine.deriveState(tempDir);
87
-
88
- assert.equal(typeof state.phase, "string", "phase should be a string");
89
- assert.ok(
90
- "currentMilestoneId" in state,
91
- "state should have currentMilestoneId",
92
- );
93
- assert.ok(
94
- "activeSliceId" in state,
95
- "state should have activeSliceId",
96
- );
97
- assert.ok(
98
- "activeTaskId" in state,
99
- "state should have activeTaskId",
100
- );
101
- assert.equal(
102
- typeof state.isComplete,
103
- "boolean",
104
- "isComplete should be boolean",
105
- );
106
- assert.ok("raw" in state, "state should have raw field");
84
+ try {
85
+ const state = await engine.deriveState(tempDir);
86
+
87
+ assert.equal(typeof state.phase, "string", "phase should be a string");
88
+ assert.ok(
89
+ "currentMilestoneId" in state,
90
+ "state should have currentMilestoneId",
91
+ );
92
+ assert.ok(
93
+ "activeSliceId" in state,
94
+ "state should have activeSliceId",
95
+ );
96
+ assert.ok(
97
+ "activeTaskId" in state,
98
+ "state should have activeTaskId",
99
+ );
100
+ assert.equal(
101
+ typeof state.isComplete,
102
+ "boolean",
103
+ "isComplete should be boolean",
104
+ );
105
+ assert.ok("raw" in state, "state should have raw field");
106
+ } finally {
107
+ rmSync(tempDir, { recursive: true, force: true });
108
+ }
107
109
  });
108
110
 
109
111
  test("reconcile returns continue for non-complete state", async () => {
@@ -278,14 +280,16 @@ describe("Kill switch (GSD_ENGINE_BYPASS)", () => {
278
280
  }
279
281
  });
280
282
 
281
- test("GSD_ENGINE_BYPASS=1 does not affect resolveEngine (bypass checked in autoLoop)", async (t) => {
283
+ test("GSD_ENGINE_BYPASS=1 does not affect resolveEngine (bypass checked in autoLoop)", async () => {
282
284
  const { resolveEngine } = await import("../engine-resolver.ts");
283
285
  process.env.GSD_ENGINE_BYPASS = "1";
284
- t.after(() => delete process.env.GSD_ENGINE_BYPASS);
285
-
286
- // resolveEngine should still resolve normally bypass is checked in autoLoop
287
- const { engine } = resolveEngine({ activeEngineId: null });
288
- assert.ok(engine, "should return an engine even with bypass set");
286
+ try {
287
+ // resolveEngine should still resolve normally — bypass is checked in autoLoop
288
+ const { engine } = resolveEngine({ activeEngineId: null });
289
+ assert.ok(engine, "should return an engine even with bypass set");
290
+ } finally {
291
+ delete process.env.GSD_ENGINE_BYPASS;
292
+ }
289
293
  });
290
294
  });
291
295
 
@@ -20,199 +20,215 @@ function teardownRepo(repo: string): void {
20
20
  rmSync(repo, { recursive: true, force: true });
21
21
  }
22
22
 
23
- test("dispatch guard blocks when prior milestone has incomplete slices", (t) => {
23
+ test("dispatch guard blocks when prior milestone has incomplete slices", () => {
24
24
  const repo = setupRepo();
25
- t.after(() => teardownRepo(repo));
26
-
27
- mkdirSync(join(repo, ".gsd", "milestones", "M002"), { recursive: true });
28
- mkdirSync(join(repo, ".gsd", "milestones", "M003"), { recursive: true });
29
-
30
- // Seed DB: M002 with S01 complete, S02 pending
31
- insertMilestone({ id: "M002", title: "Previous" });
32
- insertSlice({ id: "S01", milestoneId: "M002", title: "Done", status: "complete", depends: [], sequence: 1 });
33
- insertSlice({ id: "S02", milestoneId: "M002", title: "Pending", status: "pending", depends: ["S01"], sequence: 2 });
34
-
35
- // M003 with two pending slices
36
- insertMilestone({ id: "M003", title: "Current" });
37
- insertSlice({ id: "S01", milestoneId: "M003", title: "First", status: "pending", depends: [], sequence: 1 });
38
- insertSlice({ id: "S02", milestoneId: "M003", title: "Second", status: "pending", depends: ["S01"], sequence: 2 });
39
-
40
- // Need ROADMAP files for milestone discovery (findMilestoneIds reads disk)
41
- writeFileSync(join(repo, ".gsd", "milestones", "M002", "M002-ROADMAP.md"), "# M002\n");
42
- writeFileSync(join(repo, ".gsd", "milestones", "M003", "M003-ROADMAP.md"), "# M003\n");
43
-
44
- assert.equal(
45
- getPriorSliceCompletionBlocker(repo, "main", "plan-slice", "M003/S01"),
46
- "Cannot dispatch plan-slice M003/S01: earlier slice M002/S02 is not complete.",
47
- );
25
+ try {
26
+ mkdirSync(join(repo, ".gsd", "milestones", "M002"), { recursive: true });
27
+ mkdirSync(join(repo, ".gsd", "milestones", "M003"), { recursive: true });
28
+
29
+ // Seed DB: M002 with S01 complete, S02 pending
30
+ insertMilestone({ id: "M002", title: "Previous" });
31
+ insertSlice({ id: "S01", milestoneId: "M002", title: "Done", status: "complete", depends: [], sequence: 1 });
32
+ insertSlice({ id: "S02", milestoneId: "M002", title: "Pending", status: "pending", depends: ["S01"], sequence: 2 });
33
+
34
+ // M003 with two pending slices
35
+ insertMilestone({ id: "M003", title: "Current" });
36
+ insertSlice({ id: "S01", milestoneId: "M003", title: "First", status: "pending", depends: [], sequence: 1 });
37
+ insertSlice({ id: "S02", milestoneId: "M003", title: "Second", status: "pending", depends: ["S01"], sequence: 2 });
38
+
39
+ // Need ROADMAP files for milestone discovery (findMilestoneIds reads disk)
40
+ writeFileSync(join(repo, ".gsd", "milestones", "M002", "M002-ROADMAP.md"), "# M002\n");
41
+ writeFileSync(join(repo, ".gsd", "milestones", "M003", "M003-ROADMAP.md"), "# M003\n");
42
+
43
+ assert.equal(
44
+ getPriorSliceCompletionBlocker(repo, "main", "plan-slice", "M003/S01"),
45
+ "Cannot dispatch plan-slice M003/S01: earlier slice M002/S02 is not complete.",
46
+ );
47
+ } finally {
48
+ teardownRepo(repo);
49
+ }
48
50
  });
49
51
 
50
- test("dispatch guard blocks later slice in same milestone when earlier incomplete", (t) => {
52
+ test("dispatch guard blocks later slice in same milestone when earlier incomplete", () => {
51
53
  const repo = setupRepo();
52
- t.after(() => teardownRepo(repo));
53
-
54
- mkdirSync(join(repo, ".gsd", "milestones", "M002"), { recursive: true });
55
- mkdirSync(join(repo, ".gsd", "milestones", "M003"), { recursive: true });
56
-
57
- insertMilestone({ id: "M002", title: "Previous" });
58
- insertSlice({ id: "S01", milestoneId: "M002", title: "Done", status: "complete", depends: [], sequence: 1 });
59
- insertSlice({ id: "S02", milestoneId: "M002", title: "Done", status: "complete", depends: ["S01"], sequence: 2 });
60
-
61
- insertMilestone({ id: "M003", title: "Current" });
62
- insertSlice({ id: "S01", milestoneId: "M003", title: "First", status: "pending", depends: [], sequence: 1 });
63
- insertSlice({ id: "S02", milestoneId: "M003", title: "Second", status: "pending", depends: ["S01"], sequence: 2 });
64
-
65
- writeFileSync(join(repo, ".gsd", "milestones", "M002", "M002-ROADMAP.md"), "# M002\n");
66
- writeFileSync(join(repo, ".gsd", "milestones", "M003", "M003-ROADMAP.md"), "# M003\n");
67
-
68
- assert.equal(
69
- getPriorSliceCompletionBlocker(repo, "main", "execute-task", "M003/S02/T01"),
70
- "Cannot dispatch execute-task M003/S02/T01: dependency slice M003/S01 is not complete.",
71
- );
54
+ try {
55
+ mkdirSync(join(repo, ".gsd", "milestones", "M002"), { recursive: true });
56
+ mkdirSync(join(repo, ".gsd", "milestones", "M003"), { recursive: true });
57
+
58
+ insertMilestone({ id: "M002", title: "Previous" });
59
+ insertSlice({ id: "S01", milestoneId: "M002", title: "Done", status: "complete", depends: [], sequence: 1 });
60
+ insertSlice({ id: "S02", milestoneId: "M002", title: "Done", status: "complete", depends: ["S01"], sequence: 2 });
61
+
62
+ insertMilestone({ id: "M003", title: "Current" });
63
+ insertSlice({ id: "S01", milestoneId: "M003", title: "First", status: "pending", depends: [], sequence: 1 });
64
+ insertSlice({ id: "S02", milestoneId: "M003", title: "Second", status: "pending", depends: ["S01"], sequence: 2 });
65
+
66
+ writeFileSync(join(repo, ".gsd", "milestones", "M002", "M002-ROADMAP.md"), "# M002\n");
67
+ writeFileSync(join(repo, ".gsd", "milestones", "M003", "M003-ROADMAP.md"), "# M003\n");
68
+
69
+ assert.equal(
70
+ getPriorSliceCompletionBlocker(repo, "main", "execute-task", "M003/S02/T01"),
71
+ "Cannot dispatch execute-task M003/S02/T01: dependency slice M003/S01 is not complete.",
72
+ );
73
+ } finally {
74
+ teardownRepo(repo);
75
+ }
72
76
  });
73
77
 
74
- test("dispatch guard allows dispatch when all earlier slices complete", (t) => {
78
+ test("dispatch guard allows dispatch when all earlier slices complete", () => {
75
79
  const repo = setupRepo();
76
- t.after(() => teardownRepo(repo));
77
-
78
- mkdirSync(join(repo, ".gsd", "milestones", "M003"), { recursive: true });
80
+ try {
81
+ mkdirSync(join(repo, ".gsd", "milestones", "M003"), { recursive: true });
79
82
 
80
- insertMilestone({ id: "M003", title: "Current" });
81
- insertSlice({ id: "S01", milestoneId: "M003", title: "First", status: "complete", depends: [], sequence: 1 });
82
- insertSlice({ id: "S02", milestoneId: "M003", title: "Second", status: "pending", depends: ["S01"], sequence: 2 });
83
+ insertMilestone({ id: "M003", title: "Current" });
84
+ insertSlice({ id: "S01", milestoneId: "M003", title: "First", status: "complete", depends: [], sequence: 1 });
85
+ insertSlice({ id: "S02", milestoneId: "M003", title: "Second", status: "pending", depends: ["S01"], sequence: 2 });
83
86
 
84
- writeFileSync(join(repo, ".gsd", "milestones", "M003", "M003-ROADMAP.md"), "# M003\n");
87
+ writeFileSync(join(repo, ".gsd", "milestones", "M003", "M003-ROADMAP.md"), "# M003\n");
85
88
 
86
- assert.equal(getPriorSliceCompletionBlocker(repo, "main", "execute-task", "M003/S02/T01"), null);
87
- assert.equal(getPriorSliceCompletionBlocker(repo, "main", "plan-milestone", "M003"), null);
89
+ assert.equal(getPriorSliceCompletionBlocker(repo, "main", "execute-task", "M003/S02/T01"), null);
90
+ assert.equal(getPriorSliceCompletionBlocker(repo, "main", "plan-milestone", "M003"), null);
91
+ } finally {
92
+ teardownRepo(repo);
93
+ }
88
94
  });
89
95
 
90
- test("dispatch guard unblocks slice when positionally-earlier slice depends on it (#1638)", (t) => {
96
+ test("dispatch guard unblocks slice when positionally-earlier slice depends on it (#1638)", () => {
91
97
  // S05 depends on S06, but S05 appears first positionally.
92
98
  // Old behavior: S06 blocked because S05 (positionally earlier) is incomplete.
93
99
  // Fixed behavior: S06 has no unmet dependencies, so it can dispatch.
94
100
  const repo = setupRepo();
95
- t.after(() => teardownRepo(repo));
96
-
97
- mkdirSync(join(repo, ".gsd", "milestones", "M001"), { recursive: true });
98
-
99
- insertMilestone({ id: "M001", title: "Test" });
100
- insertSlice({ id: "S01", milestoneId: "M001", title: "Setup", status: "complete", depends: [], sequence: 1 });
101
- insertSlice({ id: "S02", milestoneId: "M001", title: "Core", status: "complete", depends: ["S01"], sequence: 2 });
102
- insertSlice({ id: "S03", milestoneId: "M001", title: "API", status: "complete", depends: ["S02"], sequence: 3 });
103
- insertSlice({ id: "S04", milestoneId: "M001", title: "Auth", status: "complete", depends: ["S03"], sequence: 4 });
104
- insertSlice({ id: "S05", milestoneId: "M001", title: "Integration", status: "pending", depends: ["S04", "S06"], sequence: 5 });
105
- insertSlice({ id: "S06", milestoneId: "M001", title: "Data Layer", status: "pending", depends: ["S04"], sequence: 6 });
106
-
107
- writeFileSync(join(repo, ".gsd", "milestones", "M001", "M001-ROADMAP.md"), "# M001\n");
108
-
109
- // S06 depends only on S04 (complete) — should be unblocked
110
- assert.equal(
111
- getPriorSliceCompletionBlocker(repo, "main", "plan-slice", "M001/S06"),
112
- null,
113
- );
114
-
115
- // S05 depends on S04 (complete) and S06 (incomplete) — should be blocked
116
- assert.equal(
117
- getPriorSliceCompletionBlocker(repo, "main", "plan-slice", "M001/S05"),
118
- "Cannot dispatch plan-slice M001/S05: dependency slice M001/S06 is not complete.",
119
- );
101
+ try {
102
+ mkdirSync(join(repo, ".gsd", "milestones", "M001"), { recursive: true });
103
+
104
+ insertMilestone({ id: "M001", title: "Test" });
105
+ insertSlice({ id: "S01", milestoneId: "M001", title: "Setup", status: "complete", depends: [], sequence: 1 });
106
+ insertSlice({ id: "S02", milestoneId: "M001", title: "Core", status: "complete", depends: ["S01"], sequence: 2 });
107
+ insertSlice({ id: "S03", milestoneId: "M001", title: "API", status: "complete", depends: ["S02"], sequence: 3 });
108
+ insertSlice({ id: "S04", milestoneId: "M001", title: "Auth", status: "complete", depends: ["S03"], sequence: 4 });
109
+ insertSlice({ id: "S05", milestoneId: "M001", title: "Integration", status: "pending", depends: ["S04", "S06"], sequence: 5 });
110
+ insertSlice({ id: "S06", milestoneId: "M001", title: "Data Layer", status: "pending", depends: ["S04"], sequence: 6 });
111
+
112
+ writeFileSync(join(repo, ".gsd", "milestones", "M001", "M001-ROADMAP.md"), "# M001\n");
113
+
114
+ // S06 depends only on S04 (complete) — should be unblocked
115
+ assert.equal(
116
+ getPriorSliceCompletionBlocker(repo, "main", "plan-slice", "M001/S06"),
117
+ null,
118
+ );
119
+
120
+ // S05 depends on S04 (complete) and S06 (incomplete) — should be blocked
121
+ assert.equal(
122
+ getPriorSliceCompletionBlocker(repo, "main", "plan-slice", "M001/S05"),
123
+ "Cannot dispatch plan-slice M001/S05: dependency slice M001/S06 is not complete.",
124
+ );
125
+ } finally {
126
+ teardownRepo(repo);
127
+ }
120
128
  });
121
129
 
122
- test("dispatch guard falls back to positional ordering when no dependencies declared", (t) => {
130
+ test("dispatch guard falls back to positional ordering when no dependencies declared", () => {
123
131
  const repo = setupRepo();
124
- t.after(() => teardownRepo(repo));
125
-
126
- mkdirSync(join(repo, ".gsd", "milestones", "M001"), { recursive: true });
127
-
128
- insertMilestone({ id: "M001", title: "Test" });
129
- insertSlice({ id: "S01", milestoneId: "M001", title: "First", status: "complete", depends: [], sequence: 1 });
130
- insertSlice({ id: "S02", milestoneId: "M001", title: "Second", status: "pending", depends: [], sequence: 2 });
131
- insertSlice({ id: "S03", milestoneId: "M001", title: "Third", status: "pending", depends: [], sequence: 3 });
132
-
133
- writeFileSync(join(repo, ".gsd", "milestones", "M001", "M001-ROADMAP.md"), "# M001\n");
134
-
135
- // S03 has no dependencies — positional fallback blocks on S02
136
- assert.equal(
137
- getPriorSliceCompletionBlocker(repo, "main", "plan-slice", "M001/S03"),
138
- "Cannot dispatch plan-slice M001/S03: earlier slice M001/S02 is not complete.",
139
- );
140
-
141
- // S02 has no dependencies — positional fallback: S01 is done, so unblocked
142
- assert.equal(
143
- getPriorSliceCompletionBlocker(repo, "main", "plan-slice", "M001/S02"),
144
- null,
145
- );
132
+ try {
133
+ mkdirSync(join(repo, ".gsd", "milestones", "M001"), { recursive: true });
134
+
135
+ insertMilestone({ id: "M001", title: "Test" });
136
+ insertSlice({ id: "S01", milestoneId: "M001", title: "First", status: "complete", depends: [], sequence: 1 });
137
+ insertSlice({ id: "S02", milestoneId: "M001", title: "Second", status: "pending", depends: [], sequence: 2 });
138
+ insertSlice({ id: "S03", milestoneId: "M001", title: "Third", status: "pending", depends: [], sequence: 3 });
139
+
140
+ writeFileSync(join(repo, ".gsd", "milestones", "M001", "M001-ROADMAP.md"), "# M001\n");
141
+
142
+ // S03 has no dependencies — positional fallback blocks on S02
143
+ assert.equal(
144
+ getPriorSliceCompletionBlocker(repo, "main", "plan-slice", "M001/S03"),
145
+ "Cannot dispatch plan-slice M001/S03: earlier slice M001/S02 is not complete.",
146
+ );
147
+
148
+ // S02 has no dependencies — positional fallback: S01 is done, so unblocked
149
+ assert.equal(
150
+ getPriorSliceCompletionBlocker(repo, "main", "plan-slice", "M001/S02"),
151
+ null,
152
+ );
153
+ } finally {
154
+ teardownRepo(repo);
155
+ }
146
156
  });
147
157
 
148
- test("dispatch guard allows slice with all declared dependencies complete", (t) => {
158
+ test("dispatch guard allows slice with all declared dependencies complete", () => {
149
159
  const repo = setupRepo();
150
- t.after(() => teardownRepo(repo));
151
-
152
- mkdirSync(join(repo, ".gsd", "milestones", "M001"), { recursive: true });
153
-
154
- insertMilestone({ id: "M001", title: "Test" });
155
- insertSlice({ id: "S01", milestoneId: "M001", title: "Setup", status: "complete", depends: [], sequence: 1 });
156
- insertSlice({ id: "S02", milestoneId: "M001", title: "Core", status: "complete", depends: ["S01"], sequence: 2 });
157
- insertSlice({ id: "S03", milestoneId: "M001", title: "Feature A", status: "pending", depends: ["S01", "S02"], sequence: 3 });
158
- insertSlice({ id: "S04", milestoneId: "M001", title: "Feature B", status: "pending", depends: ["S01"], sequence: 4 });
159
-
160
- writeFileSync(join(repo, ".gsd", "milestones", "M001", "M001-ROADMAP.md"), "# M001\n");
161
-
162
- // S03 depends on S01 (done) and S02 (done) — unblocked
163
- assert.equal(
164
- getPriorSliceCompletionBlocker(repo, "main", "plan-slice", "M001/S03"),
165
- null,
166
- );
167
-
168
- // S04 depends only on S01 (done) — unblocked even though S03 is incomplete
169
- assert.equal(
170
- getPriorSliceCompletionBlocker(repo, "main", "plan-slice", "M001/S04"),
171
- null,
172
- );
160
+ try {
161
+ mkdirSync(join(repo, ".gsd", "milestones", "M001"), { recursive: true });
162
+
163
+ insertMilestone({ id: "M001", title: "Test" });
164
+ insertSlice({ id: "S01", milestoneId: "M001", title: "Setup", status: "complete", depends: [], sequence: 1 });
165
+ insertSlice({ id: "S02", milestoneId: "M001", title: "Core", status: "complete", depends: ["S01"], sequence: 2 });
166
+ insertSlice({ id: "S03", milestoneId: "M001", title: "Feature A", status: "pending", depends: ["S01", "S02"], sequence: 3 });
167
+ insertSlice({ id: "S04", milestoneId: "M001", title: "Feature B", status: "pending", depends: ["S01"], sequence: 4 });
168
+
169
+ writeFileSync(join(repo, ".gsd", "milestones", "M001", "M001-ROADMAP.md"), "# M001\n");
170
+
171
+ // S03 depends on S01 (done) and S02 (done) — unblocked
172
+ assert.equal(
173
+ getPriorSliceCompletionBlocker(repo, "main", "plan-slice", "M001/S03"),
174
+ null,
175
+ );
176
+
177
+ // S04 depends only on S01 (done) — unblocked even though S03 is incomplete
178
+ assert.equal(
179
+ getPriorSliceCompletionBlocker(repo, "main", "plan-slice", "M001/S04"),
180
+ null,
181
+ );
182
+ } finally {
183
+ teardownRepo(repo);
184
+ }
173
185
  });
174
186
 
175
- test("dispatch guard skips completed milestone with SUMMARY even if it has unchecked remediation slices (#1716)", (t) => {
187
+ test("dispatch guard skips completed milestone with SUMMARY even if it has unchecked remediation slices (#1716)", () => {
176
188
  const repo = setupRepo();
177
- t.after(() => teardownRepo(repo));
178
-
179
- mkdirSync(join(repo, ".gsd", "milestones", "M001"), { recursive: true });
180
- mkdirSync(join(repo, ".gsd", "milestones", "M002"), { recursive: true });
181
-
182
- // M001 is complete (has SUMMARY) but has unchecked remediation slices in DB
183
- insertMilestone({ id: "M001", title: "Previous" });
184
- insertSlice({ id: "S01", milestoneId: "M001", title: "Core", status: "complete", depends: [], sequence: 1 });
185
- insertSlice({ id: "S02", milestoneId: "M001", title: "Tests", status: "complete", depends: ["S01"], sequence: 2 });
186
- insertSlice({ id: "S03-R", milestoneId: "M001", title: "Remediation", status: "pending", depends: ["S02"], sequence: 3 });
187
- insertSlice({ id: "S04-R", milestoneId: "M001", title: "Remediation 2", status: "pending", depends: ["S02"], sequence: 4 });
188
-
189
- insertMilestone({ id: "M002", title: "Current" });
190
- insertSlice({ id: "S01", milestoneId: "M002", title: "Start", status: "pending", depends: [], sequence: 1 });
191
-
192
- // M001 SUMMARY on disk triggers skip
193
- writeFileSync(join(repo, ".gsd", "milestones", "M001", "M001-ROADMAP.md"), "# M001\n");
194
- writeFileSync(join(repo, ".gsd", "milestones", "M001", "M001-SUMMARY.md"),
195
- "---\nstatus: complete\n---\n# M001 Summary\nDone.\n");
196
- writeFileSync(join(repo, ".gsd", "milestones", "M002", "M002-ROADMAP.md"), "# M002\n");
197
-
198
- // M001 has SUMMARY — should be skipped, not block M002/S01
199
- assert.equal(
200
- getPriorSliceCompletionBlocker(repo, "main", "plan-slice", "M002/S01"),
201
- null,
202
- );
189
+ try {
190
+ mkdirSync(join(repo, ".gsd", "milestones", "M001"), { recursive: true });
191
+ mkdirSync(join(repo, ".gsd", "milestones", "M002"), { recursive: true });
192
+
193
+ // M001 is complete (has SUMMARY) but has unchecked remediation slices in DB
194
+ insertMilestone({ id: "M001", title: "Previous" });
195
+ insertSlice({ id: "S01", milestoneId: "M001", title: "Core", status: "complete", depends: [], sequence: 1 });
196
+ insertSlice({ id: "S02", milestoneId: "M001", title: "Tests", status: "complete", depends: ["S01"], sequence: 2 });
197
+ insertSlice({ id: "S03-R", milestoneId: "M001", title: "Remediation", status: "pending", depends: ["S02"], sequence: 3 });
198
+ insertSlice({ id: "S04-R", milestoneId: "M001", title: "Remediation 2", status: "pending", depends: ["S02"], sequence: 4 });
199
+
200
+ insertMilestone({ id: "M002", title: "Current" });
201
+ insertSlice({ id: "S01", milestoneId: "M002", title: "Start", status: "pending", depends: [], sequence: 1 });
202
+
203
+ // M001 SUMMARY on disk triggers skip
204
+ writeFileSync(join(repo, ".gsd", "milestones", "M001", "M001-ROADMAP.md"), "# M001\n");
205
+ writeFileSync(join(repo, ".gsd", "milestones", "M001", "M001-SUMMARY.md"),
206
+ "---\nstatus: complete\n---\n# M001 Summary\nDone.\n");
207
+ writeFileSync(join(repo, ".gsd", "milestones", "M002", "M002-ROADMAP.md"), "# M002\n");
208
+
209
+ // M001 has SUMMARY — should be skipped, not block M002/S01
210
+ assert.equal(
211
+ getPriorSliceCompletionBlocker(repo, "main", "plan-slice", "M002/S01"),
212
+ null,
213
+ );
214
+ } finally {
215
+ teardownRepo(repo);
216
+ }
203
217
  });
204
218
 
205
- test("dispatch guard works without git repo", (t) => {
219
+ test("dispatch guard works without git repo", () => {
206
220
  const repo = setupRepo();
207
- t.after(() => teardownRepo(repo));
208
-
209
- mkdirSync(join(repo, ".gsd", "milestones", "M001"), { recursive: true });
221
+ try {
222
+ mkdirSync(join(repo, ".gsd", "milestones", "M001"), { recursive: true });
210
223
 
211
- insertMilestone({ id: "M001", title: "Test" });
212
- insertSlice({ id: "S01", milestoneId: "M001", title: "Done", status: "complete", depends: [], sequence: 1 });
213
- insertSlice({ id: "S02", milestoneId: "M001", title: "Pending", status: "pending", depends: ["S01"], sequence: 2 });
224
+ insertMilestone({ id: "M001", title: "Test" });
225
+ insertSlice({ id: "S01", milestoneId: "M001", title: "Done", status: "complete", depends: [], sequence: 1 });
226
+ insertSlice({ id: "S02", milestoneId: "M001", title: "Pending", status: "pending", depends: ["S01"], sequence: 2 });
214
227
 
215
- writeFileSync(join(repo, ".gsd", "milestones", "M001", "M001-ROADMAP.md"), "# M001\n");
228
+ writeFileSync(join(repo, ".gsd", "milestones", "M001", "M001-ROADMAP.md"), "# M001\n");
216
229
 
217
- assert.equal(getPriorSliceCompletionBlocker(repo, "main", "plan-slice", "M001/S02"), null);
230
+ assert.equal(getPriorSliceCompletionBlocker(repo, "main", "plan-slice", "M001/S02"), null);
231
+ } finally {
232
+ teardownRepo(repo);
233
+ }
218
234
  });
@@ -71,56 +71,62 @@ function scaffoldTaskPlan(basePath: string, mid: string, sid: string, tid: strin
71
71
 
72
72
  // ─── Tests ─────────────────────────────────────────────────────────────────
73
73
 
74
- test("dispatch: missing task plan triggers plan-slice (not stop) — issue #909", async (t) => {
74
+ test("dispatch: missing task plan triggers plan-slice (not stop) — issue #909", async () => {
75
75
  const tmp = mkdtempSync(join(tmpdir(), "gsd-909-"));
76
- t.after(() => rmSync(tmp, { recursive: true, force: true }));
77
-
78
- // Slice plan exists with tasks, but tasks/ directory is empty
79
- scaffoldSlicePlan(tmp, "M002", "S03");
80
-
81
- const ctx = makeContext(tmp);
82
- const result = await resolveDispatch(ctx);
83
-
84
- assert.equal(result.action, "dispatch", "should dispatch, not stop");
85
- assert.ok(result.action === "dispatch" && result.unitType === "plan-slice",
86
- `unitType should be plan-slice, got: ${result.action === "dispatch" ? result.unitType : "(stop)"}`);
87
- assert.ok(result.action === "dispatch" && result.unitId === "M002/S03",
88
- `unitId should be M002/S03, got: ${result.action === "dispatch" ? result.unitId : "(stop)"}`);
76
+ try {
77
+ // Slice plan exists with tasks, but tasks/ directory is empty
78
+ scaffoldSlicePlan(tmp, "M002", "S03");
79
+
80
+ const ctx = makeContext(tmp);
81
+ const result = await resolveDispatch(ctx);
82
+
83
+ assert.equal(result.action, "dispatch", "should dispatch, not stop");
84
+ assert.ok(result.action === "dispatch" && result.unitType === "plan-slice",
85
+ `unitType should be plan-slice, got: ${result.action === "dispatch" ? result.unitType : "(stop)"}`);
86
+ assert.ok(result.action === "dispatch" && result.unitId === "M002/S03",
87
+ `unitId should be M002/S03, got: ${result.action === "dispatch" ? result.unitId : "(stop)"}`);
88
+ } finally {
89
+ rmSync(tmp, { recursive: true, force: true });
90
+ }
89
91
  });
90
92
 
91
- test("dispatch: present task plan proceeds to execute-task normally", async (t) => {
93
+ test("dispatch: present task plan proceeds to execute-task normally", async () => {
92
94
  const tmp = mkdtempSync(join(tmpdir(), "gsd-909-ok-"));
93
- t.after(() => rmSync(tmp, { recursive: true, force: true }));
94
-
95
- scaffoldSlicePlan(tmp, "M002", "S03");
96
- scaffoldTaskPlan(tmp, "M002", "S03", "T01");
97
-
98
- const ctx = makeContext(tmp);
99
- const result = await resolveDispatch(ctx);
100
-
101
- assert.equal(result.action, "dispatch");
102
- assert.ok(result.action === "dispatch" && result.unitType === "execute-task",
103
- `unitType should be execute-task, got: ${result.action === "dispatch" ? result.unitType : "(stop)"}`);
104
- assert.ok(result.action === "dispatch" && result.unitId === "M002/S03/T01",
105
- `unitId should be M002/S03/T01, got: ${result.action === "dispatch" ? result.unitId : "(stop)"}`);
95
+ try {
96
+ scaffoldSlicePlan(tmp, "M002", "S03");
97
+ scaffoldTaskPlan(tmp, "M002", "S03", "T01");
98
+
99
+ const ctx = makeContext(tmp);
100
+ const result = await resolveDispatch(ctx);
101
+
102
+ assert.equal(result.action, "dispatch");
103
+ assert.ok(result.action === "dispatch" && result.unitType === "execute-task",
104
+ `unitType should be execute-task, got: ${result.action === "dispatch" ? result.unitType : "(stop)"}`);
105
+ assert.ok(result.action === "dispatch" && result.unitId === "M002/S03/T01",
106
+ `unitId should be M002/S03/T01, got: ${result.action === "dispatch" ? result.unitId : "(stop)"}`);
107
+ } finally {
108
+ rmSync(tmp, { recursive: true, force: true });
109
+ }
106
110
  });
107
111
 
108
- test("dispatch: plan-slice recovery loop — second call after plan-slice still recovers cleanly", async (t) => {
112
+ test("dispatch: plan-slice recovery loop — second call after plan-slice still recovers cleanly", async () => {
109
113
  // Simulate: plan-slice ran but T01-PLAN.md is still missing (e.g. agent crashed mid-write).
110
114
  // Dispatch should still re-dispatch plan-slice, not hard-stop.
111
115
  const tmp = mkdtempSync(join(tmpdir(), "gsd-909-loop-"));
112
- t.after(() => rmSync(tmp, { recursive: true, force: true }));
113
-
114
- scaffoldSlicePlan(tmp, "M002", "S03");
115
-
116
- const ctx = makeContext(tmp);
117
- const r1 = await resolveDispatch(ctx);
118
- assert.equal(r1.action, "dispatch");
119
- assert.ok(r1.action === "dispatch" && r1.unitType === "plan-slice");
120
-
121
- // Still no task plan written — dispatch again
122
- const r2 = await resolveDispatch(ctx);
123
- assert.equal(r2.action, "dispatch");
124
- assert.ok(r2.action === "dispatch" && r2.unitType === "plan-slice",
125
- "should keep dispatching plan-slice until task plans appear");
116
+ try {
117
+ scaffoldSlicePlan(tmp, "M002", "S03");
118
+
119
+ const ctx = makeContext(tmp);
120
+ const r1 = await resolveDispatch(ctx);
121
+ assert.equal(r1.action, "dispatch");
122
+ assert.ok(r1.action === "dispatch" && r1.unitType === "plan-slice");
123
+
124
+ // Still no task plan written — dispatch again
125
+ const r2 = await resolveDispatch(ctx);
126
+ assert.equal(r2.action, "dispatch");
127
+ assert.ok(r2.action === "dispatch" && r2.unitType === "plan-slice",
128
+ "should keep dispatching plan-slice until task plans appear");
129
+ } finally {
130
+ rmSync(tmp, { recursive: true, force: true });
131
+ }
126
132
  });