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
@@ -1,5 +1,4 @@
1
- import { describe, test, afterEach } from "node:test";
2
- import assert from "node:assert/strict";
1
+ import { createTestContext } from './test-helpers.ts';
3
2
  import * as fs from 'node:fs';
4
3
  import * as path from 'node:path';
5
4
  import * as os from 'node:os';
@@ -18,6 +17,8 @@ import {
18
17
  import { handleCompleteSlice } from '../tools/complete-slice.ts';
19
18
  import type { CompleteSliceParams } from '../types.ts';
20
19
 
20
+ const { assertEq, assertTrue, assertMatch, report } = createTestContext();
21
+
21
22
  // ═══════════════════════════════════════════════════════════════════════════
22
23
  // Helpers
23
24
  // ═══════════════════════════════════════════════════════════════════════════
@@ -114,262 +115,296 @@ Run the test suite and verify all assertions pass.
114
115
  }
115
116
 
116
117
  // ═══════════════════════════════════════════════════════════════════════════
117
- // Tests
118
+ // complete-slice: Schema v6 migration
118
119
  // ═══════════════════════════════════════════════════════════════════════════
119
120
 
120
- describe("complete-slice: schema v6 migration", () => {
121
- test("schema version and columns exist", () => {
122
- const dbPath = tempDbPath();
123
- openDatabase(dbPath);
124
-
125
- const adapter = _getAdapter()!;
126
-
127
- // Verify schema version is current (v10 after M001 planning migrations)
128
- const versionRow = adapter.prepare('SELECT MAX(version) as v FROM schema_version').get();
129
- assert.strictEqual(versionRow?.['v'], 10, 'schema version should be 10');
130
-
131
- // Verify slices table has full_summary_md and full_uat_md columns
132
- const cols = adapter.prepare("PRAGMA table_info(slices)").all();
133
- const colNames = cols.map(c => c['name'] as string);
134
- assert.ok(colNames.includes('full_summary_md'), 'slices table should have full_summary_md column');
135
- assert.ok(colNames.includes('full_uat_md'), 'slices table should have full_uat_md column');
136
-
137
- cleanup(dbPath);
138
- });
139
- });
140
-
141
- describe("complete-slice: getSlice/updateSliceStatus accessors", () => {
142
- test("getSlice and updateSliceStatus work correctly", () => {
143
- const dbPath = tempDbPath();
144
- openDatabase(dbPath);
145
-
146
- // Insert milestone and slice
147
- insertMilestone({ id: 'M001' });
148
- insertSlice({ id: 'S01', milestoneId: 'M001', title: 'Test Slice', risk: 'high' });
149
-
150
- // getSlice returns correct row
151
- const slice = getSlice('M001', 'S01');
152
- assert.ok(slice !== null, 'getSlice should return non-null for existing slice');
153
- assert.strictEqual(slice!.id, 'S01', 'slice id');
154
- assert.strictEqual(slice!.milestone_id, 'M001', 'slice milestone_id');
155
- assert.strictEqual(slice!.title, 'Test Slice', 'slice title');
156
- assert.strictEqual(slice!.risk, 'high', 'slice risk');
157
- assert.strictEqual(slice!.status, 'pending', 'slice default status should be pending');
158
- assert.strictEqual(slice!.completed_at, null, 'slice completed_at should be null initially');
159
- assert.strictEqual(slice!.full_summary_md, '', 'slice full_summary_md should be empty initially');
160
- assert.strictEqual(slice!.full_uat_md, '', 'slice full_uat_md should be empty initially');
161
-
162
- // getSlice returns null for non-existent
163
- const noSlice = getSlice('M001', 'S99');
164
- assert.strictEqual(noSlice, null, 'non-existent slice should return null');
165
-
166
- // updateSliceStatus changes status and completed_at
167
- const now = new Date().toISOString();
168
- updateSliceStatus('M001', 'S01', 'complete', now);
169
- const updated = getSlice('M001', 'S01');
170
- assert.strictEqual(updated!.status, 'complete', 'slice status should be updated to complete');
171
- assert.strictEqual(updated!.completed_at, now, 'slice completed_at should be set');
172
-
173
- cleanup(dbPath);
174
- });
175
- });
176
-
177
- describe("complete-slice: handler", () => {
178
- test("happy path", async () => {
179
- const dbPath = tempDbPath();
180
- openDatabase(dbPath);
181
-
182
- const { basePath, roadmapPath } = createTempProject();
183
-
184
- // Set up DB state: milestone, slice, 2 complete tasks
185
- insertMilestone({ id: 'M001' });
186
- insertSlice({ id: 'S01', milestoneId: 'M001' });
187
- insertTask({ id: 'T01', sliceId: 'S01', milestoneId: 'M001', status: 'complete', title: 'Task 1' });
188
- insertTask({ id: 'T02', sliceId: 'S01', milestoneId: 'M001', status: 'complete', title: 'Task 2' });
189
-
190
- const params = makeValidSliceParams();
191
- const result = await handleCompleteSlice(params, basePath);
192
-
193
- assert.ok(!('error' in result), 'handler should succeed without error');
194
- if (!('error' in result)) {
195
- assert.strictEqual(result.sliceId, 'S01', 'result sliceId');
196
- assert.strictEqual(result.milestoneId, 'M001', 'result milestoneId');
197
- assert.ok(result.summaryPath.endsWith('S01-SUMMARY.md'), 'summaryPath should end with S01-SUMMARY.md');
198
- assert.ok(result.uatPath.endsWith('S01-UAT.md'), 'uatPath should end with S01-UAT.md');
199
-
200
- // (a) Verify SUMMARY.md exists on disk with correct YAML frontmatter
201
- assert.ok(fs.existsSync(result.summaryPath), 'summary file should exist on disk');
202
- const summaryContent = fs.readFileSync(result.summaryPath, 'utf-8');
203
- assert.match(summaryContent, /^---\n/, 'summary should start with YAML frontmatter');
204
- assert.match(summaryContent, /id: S01/, 'summary should contain id: S01');
205
- assert.match(summaryContent, /parent: M001/, 'summary should contain parent: M001');
206
- assert.match(summaryContent, /milestone: M001/, 'summary should contain milestone: M001');
207
- assert.match(summaryContent, /blocker_discovered: false/, 'summary should contain blocker_discovered');
208
- assert.match(summaryContent, /verification_result: passed/, 'summary should contain verification_result');
209
- assert.match(summaryContent, /key_files:/, 'summary should contain key_files');
210
- assert.match(summaryContent, /patterns_established:/, 'summary should contain patterns_established');
211
- assert.match(summaryContent, /observability_surfaces:/, 'summary should contain observability_surfaces');
212
- assert.match(summaryContent, /provides:/, 'summary should contain provides');
213
- assert.match(summaryContent, /# S01: Test Slice/, 'summary should have H1 with slice ID and title');
214
- assert.match(summaryContent, /\*\*Implemented test slice with full coverage\*\*/, 'summary should have one-liner in bold');
215
- assert.match(summaryContent, /## What Happened/, 'summary should have What Happened section');
216
- assert.match(summaryContent, /## Verification/, 'summary should have Verification section');
217
- assert.match(summaryContent, /## Requirements Advanced/, 'summary should have Requirements Advanced section');
218
-
219
- // (b) Verify UAT.md exists on disk
220
- assert.ok(fs.existsSync(result.uatPath), 'UAT file should exist on disk');
221
- const uatContent = fs.readFileSync(result.uatPath, 'utf-8');
222
- assert.match(uatContent, /# S01: Test Slice — UAT/, 'UAT should have correct title');
223
- assert.match(uatContent, /Milestone:\*\* M001/, 'UAT should reference milestone');
224
- assert.match(uatContent, /Smoke Test/, 'UAT should contain smoke test from params');
225
-
226
- // (c) Verify roadmap checkbox toggled to [x]
227
- const roadmapContent = fs.readFileSync(roadmapPath, 'utf-8');
228
- assert.match(roadmapContent, /\[x\]\s+\*\*S01:/, 'S01 should be checked in roadmap');
229
- assert.match(roadmapContent, /\[ \]\s+\*\*S02:/, 'S02 should still be unchecked in roadmap');
230
-
231
- // (d) Verify full_summary_md and full_uat_md stored in DB for D004 recovery
232
- const sliceAfter = getSlice('M001', 'S01');
233
- assert.ok(sliceAfter !== null, 'slice should exist in DB after handler');
234
- assert.ok(sliceAfter!.full_summary_md.length > 0, 'full_summary_md should be non-empty in DB');
235
- assert.match(sliceAfter!.full_summary_md, /id: S01/, 'full_summary_md should contain frontmatter');
236
- assert.ok(sliceAfter!.full_uat_md.length > 0, 'full_uat_md should be non-empty in DB');
237
- assert.match(sliceAfter!.full_uat_md, /S01: Test Slice — UAT/, 'full_uat_md should contain UAT title');
238
-
239
- // (e) Verify slice status is complete in DB
240
- assert.strictEqual(sliceAfter!.status, 'complete', 'slice status should be complete in DB');
241
- assert.ok(sliceAfter!.completed_at !== null, 'completed_at should be set in DB');
242
- }
121
+ console.log('\n=== complete-slice: schema v6 migration ===');
122
+ {
123
+ const dbPath = tempDbPath();
124
+ openDatabase(dbPath);
243
125
 
244
- cleanupDir(basePath);
245
- cleanup(dbPath);
246
- });
126
+ const adapter = _getAdapter()!;
247
127
 
248
- test("rejects incomplete tasks", async () => {
249
- const dbPath = tempDbPath();
250
- openDatabase(dbPath);
128
+ // Verify schema version is current (v10 after M001 planning migrations)
129
+ const versionRow = adapter.prepare('SELECT MAX(version) as v FROM schema_version').get();
130
+ assertEq(versionRow?.['v'], 10, 'schema version should be 10');
251
131
 
252
- // Insert milestone, slice, 2 tasks one complete, one pending
253
- insertMilestone({ id: 'M001' });
254
- insertSlice({ id: 'S01', milestoneId: 'M001' });
255
- insertTask({ id: 'T01', sliceId: 'S01', milestoneId: 'M001', status: 'complete', title: 'Task 1' });
256
- insertTask({ id: 'T02', sliceId: 'S01', milestoneId: 'M001', status: 'pending', title: 'Task 2' });
132
+ // Verify slices table has full_summary_md and full_uat_md columns
133
+ const cols = adapter.prepare("PRAGMA table_info(slices)").all();
134
+ const colNames = cols.map(c => c['name'] as string);
135
+ assertTrue(colNames.includes('full_summary_md'), 'slices table should have full_summary_md column');
136
+ assertTrue(colNames.includes('full_uat_md'), 'slices table should have full_uat_md column');
257
137
 
258
- const params = makeValidSliceParams();
259
- const result = await handleCompleteSlice(params, '/tmp/fake');
138
+ cleanup(dbPath);
139
+ }
260
140
 
261
- assert.ok('error' in result, 'should return error when tasks are incomplete');
262
- if ('error' in result) {
263
- assert.match(result.error, /incomplete tasks/, 'error should mention incomplete tasks');
264
- assert.match(result.error, /T02/, 'error should mention the specific incomplete task ID');
265
- }
141
+ // ═══════════════════════════════════════════════════════════════════════════
142
+ // complete-slice: getSlice/updateSliceStatus accessors
143
+ // ═══════════════════════════════════════════════════════════════════════════
266
144
 
267
- cleanup(dbPath);
268
- });
145
+ console.log('\n=== complete-slice: getSlice/updateSliceStatus accessors ===');
146
+ {
147
+ const dbPath = tempDbPath();
148
+ openDatabase(dbPath);
149
+
150
+ // Insert milestone and slice
151
+ insertMilestone({ id: 'M001' });
152
+ insertSlice({ id: 'S01', milestoneId: 'M001', title: 'Test Slice', risk: 'high' });
153
+
154
+ // getSlice returns correct row
155
+ const slice = getSlice('M001', 'S01');
156
+ assertTrue(slice !== null, 'getSlice should return non-null for existing slice');
157
+ assertEq(slice!.id, 'S01', 'slice id');
158
+ assertEq(slice!.milestone_id, 'M001', 'slice milestone_id');
159
+ assertEq(slice!.title, 'Test Slice', 'slice title');
160
+ assertEq(slice!.risk, 'high', 'slice risk');
161
+ assertEq(slice!.status, 'pending', 'slice default status should be pending');
162
+ assertEq(slice!.completed_at, null, 'slice completed_at should be null initially');
163
+ assertEq(slice!.full_summary_md, '', 'slice full_summary_md should be empty initially');
164
+ assertEq(slice!.full_uat_md, '', 'slice full_uat_md should be empty initially');
165
+
166
+ // getSlice returns null for non-existent
167
+ const noSlice = getSlice('M001', 'S99');
168
+ assertEq(noSlice, null, 'non-existent slice should return null');
169
+
170
+ // updateSliceStatus changes status and completed_at
171
+ const now = new Date().toISOString();
172
+ updateSliceStatus('M001', 'S01', 'complete', now);
173
+ const updated = getSlice('M001', 'S01');
174
+ assertEq(updated!.status, 'complete', 'slice status should be updated to complete');
175
+ assertEq(updated!.completed_at, now, 'slice completed_at should be set');
176
+
177
+ cleanup(dbPath);
178
+ }
269
179
 
270
- test("rejects no tasks", async () => {
271
- const dbPath = tempDbPath();
272
- openDatabase(dbPath);
180
+ // ═══════════════════════════════════════════════════════════════════════════
181
+ // complete-slice: Handler happy path
182
+ // ═══════════════════════════════════════════════════════════════════════════
273
183
 
274
- // Insert milestone and slice but NO tasks
275
- insertMilestone({ id: 'M001' });
276
- insertSlice({ id: 'S01', milestoneId: 'M001' });
184
+ console.log('\n=== complete-slice: handler happy path ===');
185
+ {
186
+ const dbPath = tempDbPath();
187
+ openDatabase(dbPath);
188
+
189
+ const { basePath, roadmapPath } = createTempProject();
190
+
191
+ // Set up DB state: milestone, slice, 2 complete tasks
192
+ insertMilestone({ id: 'M001' });
193
+ insertSlice({ id: 'S01', milestoneId: 'M001' });
194
+ insertTask({ id: 'T01', sliceId: 'S01', milestoneId: 'M001', status: 'complete', title: 'Task 1' });
195
+ insertTask({ id: 'T02', sliceId: 'S01', milestoneId: 'M001', status: 'complete', title: 'Task 2' });
196
+
197
+ const params = makeValidSliceParams();
198
+ const result = await handleCompleteSlice(params, basePath);
199
+
200
+ assertTrue(!('error' in result), 'handler should succeed without error');
201
+ if (!('error' in result)) {
202
+ assertEq(result.sliceId, 'S01', 'result sliceId');
203
+ assertEq(result.milestoneId, 'M001', 'result milestoneId');
204
+ assertTrue(result.summaryPath.endsWith('S01-SUMMARY.md'), 'summaryPath should end with S01-SUMMARY.md');
205
+ assertTrue(result.uatPath.endsWith('S01-UAT.md'), 'uatPath should end with S01-UAT.md');
206
+
207
+ // (a) Verify SUMMARY.md exists on disk with correct YAML frontmatter
208
+ assertTrue(fs.existsSync(result.summaryPath), 'summary file should exist on disk');
209
+ const summaryContent = fs.readFileSync(result.summaryPath, 'utf-8');
210
+ assertMatch(summaryContent, /^---\n/, 'summary should start with YAML frontmatter');
211
+ assertMatch(summaryContent, /id: S01/, 'summary should contain id: S01');
212
+ assertMatch(summaryContent, /parent: M001/, 'summary should contain parent: M001');
213
+ assertMatch(summaryContent, /milestone: M001/, 'summary should contain milestone: M001');
214
+ assertMatch(summaryContent, /blocker_discovered: false/, 'summary should contain blocker_discovered');
215
+ assertMatch(summaryContent, /verification_result: passed/, 'summary should contain verification_result');
216
+ assertMatch(summaryContent, /key_files:/, 'summary should contain key_files');
217
+ assertMatch(summaryContent, /patterns_established:/, 'summary should contain patterns_established');
218
+ assertMatch(summaryContent, /observability_surfaces:/, 'summary should contain observability_surfaces');
219
+ assertMatch(summaryContent, /provides:/, 'summary should contain provides');
220
+ assertMatch(summaryContent, /# S01: Test Slice/, 'summary should have H1 with slice ID and title');
221
+ assertMatch(summaryContent, /\*\*Implemented test slice with full coverage\*\*/, 'summary should have one-liner in bold');
222
+ assertMatch(summaryContent, /## What Happened/, 'summary should have What Happened section');
223
+ assertMatch(summaryContent, /## Verification/, 'summary should have Verification section');
224
+ assertMatch(summaryContent, /## Requirements Advanced/, 'summary should have Requirements Advanced section');
225
+
226
+ // (b) Verify UAT.md exists on disk
227
+ assertTrue(fs.existsSync(result.uatPath), 'UAT file should exist on disk');
228
+ const uatContent = fs.readFileSync(result.uatPath, 'utf-8');
229
+ assertMatch(uatContent, /# S01: Test Slice — UAT/, 'UAT should have correct title');
230
+ assertMatch(uatContent, /Milestone:\*\* M001/, 'UAT should reference milestone');
231
+ assertMatch(uatContent, /Smoke Test/, 'UAT should contain smoke test from params');
232
+
233
+ // (c) Verify roadmap checkbox toggled to [x]
234
+ const roadmapContent = fs.readFileSync(roadmapPath, 'utf-8');
235
+ assertMatch(roadmapContent, /\[x\]\s+\*\*S01:/, 'S01 should be checked in roadmap');
236
+ assertMatch(roadmapContent, /\[ \]\s+\*\*S02:/, 'S02 should still be unchecked in roadmap');
237
+
238
+ // (d) Verify full_summary_md and full_uat_md stored in DB for D004 recovery
239
+ const sliceAfter = getSlice('M001', 'S01');
240
+ assertTrue(sliceAfter !== null, 'slice should exist in DB after handler');
241
+ assertTrue(sliceAfter!.full_summary_md.length > 0, 'full_summary_md should be non-empty in DB');
242
+ assertMatch(sliceAfter!.full_summary_md, /id: S01/, 'full_summary_md should contain frontmatter');
243
+ assertTrue(sliceAfter!.full_uat_md.length > 0, 'full_uat_md should be non-empty in DB');
244
+ assertMatch(sliceAfter!.full_uat_md, /S01: Test Slice — UAT/, 'full_uat_md should contain UAT title');
245
+
246
+ // (e) Verify slice status is complete in DB
247
+ assertEq(sliceAfter!.status, 'complete', 'slice status should be complete in DB');
248
+ assertTrue(sliceAfter!.completed_at !== null, 'completed_at should be set in DB');
249
+ }
277
250
 
278
- const params = makeValidSliceParams();
279
- const result = await handleCompleteSlice(params, '/tmp/fake');
251
+ cleanupDir(basePath);
252
+ cleanup(dbPath);
253
+ }
280
254
 
281
- assert.ok('error' in result, 'should return error when no tasks exist');
282
- if ('error' in result) {
283
- assert.match(result.error, /no tasks found/, 'error should say no tasks found');
284
- }
255
+ // ═══════════════════════════════════════════════════════════════════════════
256
+ // complete-slice: Handler rejects incomplete tasks
257
+ // ═══════════════════════════════════════════════════════════════════════════
285
258
 
286
- cleanup(dbPath);
287
- });
259
+ console.log('\n=== complete-slice: handler rejects incomplete tasks ===');
260
+ {
261
+ const dbPath = tempDbPath();
262
+ openDatabase(dbPath);
288
263
 
289
- test("validation errors", async () => {
290
- const dbPath = tempDbPath();
291
- openDatabase(dbPath);
264
+ // Insert milestone, slice, 2 tasks — one complete, one pending
265
+ insertMilestone({ id: 'M001' });
266
+ insertSlice({ id: 'S01', milestoneId: 'M001' });
267
+ insertTask({ id: 'T01', sliceId: 'S01', milestoneId: 'M001', status: 'complete', title: 'Task 1' });
268
+ insertTask({ id: 'T02', sliceId: 'S01', milestoneId: 'M001', status: 'pending', title: 'Task 2' });
292
269
 
293
- const params = makeValidSliceParams();
270
+ const params = makeValidSliceParams();
271
+ const result = await handleCompleteSlice(params, '/tmp/fake');
294
272
 
295
- // Empty sliceId
296
- const r1 = await handleCompleteSlice({ ...params, sliceId: '' }, '/tmp/fake');
297
- assert.ok('error' in r1, 'should return error for empty sliceId');
298
- if ('error' in r1) {
299
- assert.match(r1.error, /sliceId/, 'error should mention sliceId');
300
- }
273
+ assertTrue('error' in result, 'should return error when tasks are incomplete');
274
+ if ('error' in result) {
275
+ assertMatch(result.error, /incomplete tasks/, 'error should mention incomplete tasks');
276
+ assertMatch(result.error, /T02/, 'error should mention the specific incomplete task ID');
277
+ }
301
278
 
302
- // Empty milestoneId
303
- const r2 = await handleCompleteSlice({ ...params, milestoneId: '' }, '/tmp/fake');
304
- assert.ok('error' in r2, 'should return error for empty milestoneId');
305
- if ('error' in r2) {
306
- assert.match(r2.error, /milestoneId/, 'error should mention milestoneId');
307
- }
279
+ cleanup(dbPath);
280
+ }
308
281
 
309
- cleanup(dbPath);
310
- });
282
+ // ═══════════════════════════════════════════════════════════════════════════
283
+ // complete-slice: Handler rejects no tasks
284
+ // ═══════════════════════════════════════════════════════════════════════════
311
285
 
312
- test("idempotency", async () => {
313
- const dbPath = tempDbPath();
314
- openDatabase(dbPath);
286
+ console.log('\n=== complete-slice: handler rejects no tasks ===');
287
+ {
288
+ const dbPath = tempDbPath();
289
+ openDatabase(dbPath);
315
290
 
316
- const { basePath, roadmapPath } = createTempProject();
291
+ // Insert milestone and slice but NO tasks
292
+ insertMilestone({ id: 'M001' });
293
+ insertSlice({ id: 'S01', milestoneId: 'M001' });
317
294
 
318
- // Set up DB state
319
- insertMilestone({ id: 'M001' });
320
- insertSlice({ id: 'S01', milestoneId: 'M001' });
321
- insertTask({ id: 'T01', sliceId: 'S01', milestoneId: 'M001', status: 'complete', title: 'Task 1' });
295
+ const params = makeValidSliceParams();
296
+ const result = await handleCompleteSlice(params, '/tmp/fake');
322
297
 
323
- const params = makeValidSliceParams();
298
+ assertTrue('error' in result, 'should return error when no tasks exist');
299
+ if ('error' in result) {
300
+ assertMatch(result.error, /no tasks found/, 'error should say no tasks found');
301
+ }
324
302
 
325
- // First call
326
- const r1 = await handleCompleteSlice(params, basePath);
327
- assert.ok(!('error' in r1), 'first call should succeed');
303
+ cleanup(dbPath);
304
+ }
305
+
306
+ // ═══════════════════════════════════════════════════════════════════════════
307
+ // complete-slice: Handler validation errors
308
+ // ═══════════════════════════════════════════════════════════════════════════
328
309
 
329
- // Second call with same params — should not crash
330
- const r2 = await handleCompleteSlice(params, basePath);
331
- assert.ok(!('error' in r2), 'second call should succeed (idempotent)');
310
+ console.log('\n=== complete-slice: handler validation errors ===');
311
+ {
312
+ const dbPath = tempDbPath();
313
+ openDatabase(dbPath);
332
314
 
333
- // Verify only 1 slice row (not duplicated)
334
- const adapter = _getAdapter()!;
335
- const sliceRows = adapter.prepare("SELECT * FROM slices WHERE milestone_id = 'M001' AND id = 'S01'").all();
336
- assert.strictEqual(sliceRows.length, 1, 'should have exactly 1 slice row after 2 calls');
315
+ const params = makeValidSliceParams();
337
316
 
338
- // Files should still exist
339
- if (!('error' in r2)) {
340
- assert.ok(fs.existsSync(r2.summaryPath), 'summary should still exist after second call');
341
- assert.ok(fs.existsSync(r2.uatPath), 'UAT should still exist after second call');
342
- }
317
+ // Empty sliceId
318
+ const r1 = await handleCompleteSlice({ ...params, sliceId: '' }, '/tmp/fake');
319
+ assertTrue('error' in r1, 'should return error for empty sliceId');
320
+ if ('error' in r1) {
321
+ assertMatch(r1.error, /sliceId/, 'error should mention sliceId');
322
+ }
343
323
 
344
- cleanupDir(basePath);
345
- cleanup(dbPath);
346
- });
324
+ // Empty milestoneId
325
+ const r2 = await handleCompleteSlice({ ...params, milestoneId: '' }, '/tmp/fake');
326
+ assertTrue('error' in r2, 'should return error for empty milestoneId');
327
+ if ('error' in r2) {
328
+ assertMatch(r2.error, /milestoneId/, 'error should mention milestoneId');
329
+ }
347
330
 
348
- test("missing roadmap (graceful)", async () => {
349
- const dbPath = tempDbPath();
350
- openDatabase(dbPath);
331
+ cleanup(dbPath);
332
+ }
351
333
 
352
- // Create a temp dir WITHOUT a roadmap file
353
- const basePath = fs.mkdtempSync(path.join(os.tmpdir(), 'gsd-no-roadmap-'));
354
- const sliceDir = path.join(basePath, '.gsd', 'milestones', 'M001', 'slices', 'S01');
355
- fs.mkdirSync(sliceDir, { recursive: true });
334
+ // ═══════════════════════════════════════════════════════════════════════════
335
+ // complete-slice: Handler idempotency
336
+ // ═══════════════════════════════════════════════════════════════════════════
356
337
 
357
- // Set up DB state
358
- insertMilestone({ id: 'M001' });
359
- insertSlice({ id: 'S01', milestoneId: 'M001' });
360
- insertTask({ id: 'T01', sliceId: 'S01', milestoneId: 'M001', status: 'complete', title: 'Task 1' });
338
+ console.log('\n=== complete-slice: handler idempotency ===');
339
+ {
340
+ const dbPath = tempDbPath();
341
+ openDatabase(dbPath);
361
342
 
362
- const params = makeValidSliceParams();
363
- const result = await handleCompleteSlice(params, basePath);
343
+ const { basePath, roadmapPath } = createTempProject();
364
344
 
365
- // Should succeed even without roadmap file — just skip checkbox toggle
366
- assert.ok(!('error' in result), 'handler should succeed without roadmap file');
367
- if (!('error' in result)) {
368
- assert.ok(fs.existsSync(result.summaryPath), 'summary should be written even without roadmap');
369
- assert.ok(fs.existsSync(result.uatPath), 'UAT should be written even without roadmap');
370
- }
345
+ // Set up DB state
346
+ insertMilestone({ id: 'M001' });
347
+ insertSlice({ id: 'S01', milestoneId: 'M001' });
348
+ insertTask({ id: 'T01', sliceId: 'S01', milestoneId: 'M001', status: 'complete', title: 'Task 1' });
349
+
350
+ const params = makeValidSliceParams();
351
+
352
+ // First call
353
+ const r1 = await handleCompleteSlice(params, basePath);
354
+ assertTrue(!('error' in r1), 'first call should succeed');
355
+
356
+ // Second call with same params — should not crash
357
+ const r2 = await handleCompleteSlice(params, basePath);
358
+ assertTrue(!('error' in r2), 'second call should succeed (idempotent)');
359
+
360
+ // Verify only 1 slice row (not duplicated)
361
+ const adapter = _getAdapter()!;
362
+ const sliceRows = adapter.prepare("SELECT * FROM slices WHERE milestone_id = 'M001' AND id = 'S01'").all();
363
+ assertEq(sliceRows.length, 1, 'should have exactly 1 slice row after 2 calls');
364
+
365
+ // Files should still exist
366
+ if (!('error' in r2)) {
367
+ assertTrue(fs.existsSync(r2.summaryPath), 'summary should still exist after second call');
368
+ assertTrue(fs.existsSync(r2.uatPath), 'UAT should still exist after second call');
369
+ }
370
+
371
+ cleanupDir(basePath);
372
+ cleanup(dbPath);
373
+ }
374
+
375
+ // ═══════════════════════════════════════════════════════════════════════════
376
+ // complete-slice: Handler with missing roadmap (graceful)
377
+ // ═══════════════════════════════════════════════════════════════════════════
378
+
379
+ console.log('\n=== complete-slice: handler with missing roadmap ===');
380
+ {
381
+ const dbPath = tempDbPath();
382
+ openDatabase(dbPath);
383
+
384
+ // Create a temp dir WITHOUT a roadmap file
385
+ const basePath = fs.mkdtempSync(path.join(os.tmpdir(), 'gsd-no-roadmap-'));
386
+ const sliceDir = path.join(basePath, '.gsd', 'milestones', 'M001', 'slices', 'S01');
387
+ fs.mkdirSync(sliceDir, { recursive: true });
388
+
389
+ // Set up DB state
390
+ insertMilestone({ id: 'M001' });
391
+ insertSlice({ id: 'S01', milestoneId: 'M001' });
392
+ insertTask({ id: 'T01', sliceId: 'S01', milestoneId: 'M001', status: 'complete', title: 'Task 1' });
393
+
394
+ const params = makeValidSliceParams();
395
+ const result = await handleCompleteSlice(params, basePath);
396
+
397
+ // Should succeed even without roadmap file — just skip checkbox toggle
398
+ assertTrue(!('error' in result), 'handler should succeed without roadmap file');
399
+ if (!('error' in result)) {
400
+ assertTrue(fs.existsSync(result.summaryPath), 'summary should be written even without roadmap');
401
+ assertTrue(fs.existsSync(result.uatPath), 'UAT should be written even without roadmap');
402
+ }
403
+
404
+ cleanupDir(basePath);
405
+ cleanup(dbPath);
406
+ }
407
+
408
+ // ═══════════════════════════════════════════════════════════════════════════
371
409
 
372
- cleanupDir(basePath);
373
- cleanup(dbPath);
374
- });
375
- });
410
+ report();