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,3 @@
1
- import { describe, test } from 'node:test';
2
- import assert from 'node:assert/strict';
3
1
  import { mkdtempSync, mkdirSync, rmSync, writeFileSync } from 'node:fs';
4
2
  import { join } from 'node:path';
5
3
  import { tmpdir } from 'node:os';
@@ -14,6 +12,10 @@ import {
14
12
  insertSlice,
15
13
  insertTask,
16
14
  } from '../gsd-db.ts';
15
+ import { createTestContext } from './test-helpers.ts';
16
+
17
+ const { assertEq, assertTrue, report } = createTestContext();
18
+
17
19
  // ─── Fixture Helpers ───────────────────────────────────────────────────────
18
20
 
19
21
  function createFixtureBase(): string {
@@ -98,10 +100,11 @@ const REQUIREMENTS_CONTENT = `# Requirements
98
100
  - Description: Already validated.
99
101
  `;
100
102
 
101
- describe('derive-state-db', async () => {
103
+ async function main(): Promise<void> {
102
104
 
103
105
  // ─── Test 1: DB-backed deriveState produces identical GSDState ─────────
104
- test('derive-state-db: DB path matches file path', async () => {
106
+ console.log('\n=== derive-state-db: DB path matches file path ===');
107
+ {
105
108
  const base = createFixtureBase();
106
109
  try {
107
110
  // Write files to disk (for file-only path)
@@ -117,7 +120,7 @@ describe('derive-state-db', async () => {
117
120
 
118
121
  // Now open DB, insert matching artifacts
119
122
  openDatabase(':memory:');
120
- assert.ok(isDbAvailable(), 'db-match: DB is available after open');
123
+ assertTrue(isDbAvailable(), 'db-match: DB is available after open');
121
124
 
122
125
  insertArtifactRow('milestones/M001/M001-ROADMAP.md', ROADMAP_CONTENT, {
123
126
  artifact_type: 'roadmap',
@@ -137,35 +140,36 @@ describe('derive-state-db', async () => {
137
140
  const dbState = await deriveState(base);
138
141
 
139
142
  // Field-by-field equality
140
- assert.deepStrictEqual(dbState.phase, fileState.phase, 'db-match: phase matches');
141
- assert.deepStrictEqual(dbState.activeMilestone?.id, fileState.activeMilestone?.id, 'db-match: activeMilestone.id matches');
142
- assert.deepStrictEqual(dbState.activeMilestone?.title, fileState.activeMilestone?.title, 'db-match: activeMilestone.title matches');
143
- assert.deepStrictEqual(dbState.activeSlice?.id, fileState.activeSlice?.id, 'db-match: activeSlice.id matches');
144
- assert.deepStrictEqual(dbState.activeSlice?.title, fileState.activeSlice?.title, 'db-match: activeSlice.title matches');
145
- assert.deepStrictEqual(dbState.activeTask?.id, fileState.activeTask?.id, 'db-match: activeTask.id matches');
146
- assert.deepStrictEqual(dbState.activeTask?.title, fileState.activeTask?.title, 'db-match: activeTask.title matches');
147
- assert.deepStrictEqual(dbState.blockers, fileState.blockers, 'db-match: blockers match');
148
- assert.deepStrictEqual(dbState.registry.length, fileState.registry.length, 'db-match: registry length matches');
149
- assert.deepStrictEqual(dbState.registry[0]?.status, fileState.registry[0]?.status, 'db-match: registry[0] status matches');
150
- assert.deepStrictEqual(dbState.requirements?.active, fileState.requirements?.active, 'db-match: requirements.active matches');
151
- assert.deepStrictEqual(dbState.requirements?.validated, fileState.requirements?.validated, 'db-match: requirements.validated matches');
152
- assert.deepStrictEqual(dbState.requirements?.total, fileState.requirements?.total, 'db-match: requirements.total matches');
153
- assert.deepStrictEqual(dbState.progress?.milestones?.done, fileState.progress?.milestones?.done, 'db-match: milestones.done matches');
154
- assert.deepStrictEqual(dbState.progress?.milestones?.total, fileState.progress?.milestones?.total, 'db-match: milestones.total matches');
155
- assert.deepStrictEqual(dbState.progress?.slices?.done, fileState.progress?.slices?.done, 'db-match: slices.done matches');
156
- assert.deepStrictEqual(dbState.progress?.slices?.total, fileState.progress?.slices?.total, 'db-match: slices.total matches');
157
- assert.deepStrictEqual(dbState.progress?.tasks?.done, fileState.progress?.tasks?.done, 'db-match: tasks.done matches');
158
- assert.deepStrictEqual(dbState.progress?.tasks?.total, fileState.progress?.tasks?.total, 'db-match: tasks.total matches');
143
+ assertEq(dbState.phase, fileState.phase, 'db-match: phase matches');
144
+ assertEq(dbState.activeMilestone?.id, fileState.activeMilestone?.id, 'db-match: activeMilestone.id matches');
145
+ assertEq(dbState.activeMilestone?.title, fileState.activeMilestone?.title, 'db-match: activeMilestone.title matches');
146
+ assertEq(dbState.activeSlice?.id, fileState.activeSlice?.id, 'db-match: activeSlice.id matches');
147
+ assertEq(dbState.activeSlice?.title, fileState.activeSlice?.title, 'db-match: activeSlice.title matches');
148
+ assertEq(dbState.activeTask?.id, fileState.activeTask?.id, 'db-match: activeTask.id matches');
149
+ assertEq(dbState.activeTask?.title, fileState.activeTask?.title, 'db-match: activeTask.title matches');
150
+ assertEq(dbState.blockers, fileState.blockers, 'db-match: blockers match');
151
+ assertEq(dbState.registry.length, fileState.registry.length, 'db-match: registry length matches');
152
+ assertEq(dbState.registry[0]?.status, fileState.registry[0]?.status, 'db-match: registry[0] status matches');
153
+ assertEq(dbState.requirements?.active, fileState.requirements?.active, 'db-match: requirements.active matches');
154
+ assertEq(dbState.requirements?.validated, fileState.requirements?.validated, 'db-match: requirements.validated matches');
155
+ assertEq(dbState.requirements?.total, fileState.requirements?.total, 'db-match: requirements.total matches');
156
+ assertEq(dbState.progress?.milestones?.done, fileState.progress?.milestones?.done, 'db-match: milestones.done matches');
157
+ assertEq(dbState.progress?.milestones?.total, fileState.progress?.milestones?.total, 'db-match: milestones.total matches');
158
+ assertEq(dbState.progress?.slices?.done, fileState.progress?.slices?.done, 'db-match: slices.done matches');
159
+ assertEq(dbState.progress?.slices?.total, fileState.progress?.slices?.total, 'db-match: slices.total matches');
160
+ assertEq(dbState.progress?.tasks?.done, fileState.progress?.tasks?.done, 'db-match: tasks.done matches');
161
+ assertEq(dbState.progress?.tasks?.total, fileState.progress?.tasks?.total, 'db-match: tasks.total matches');
159
162
 
160
163
  closeDatabase();
161
164
  } finally {
162
165
  closeDatabase();
163
166
  cleanup(base);
164
167
  }
165
- });
168
+ }
166
169
 
167
170
  // ─── Test 2: Fallback when DB unavailable ─────────────────────────────
168
- test('derive-state-db: fallback when DB unavailable', async () => {
171
+ console.log('\n=== derive-state-db: fallback when DB unavailable ===');
172
+ {
169
173
  const base = createFixtureBase();
170
174
  try {
171
175
  writeFile(base, 'milestones/M001/M001-ROADMAP.md', ROADMAP_CONTENT);
@@ -174,21 +178,22 @@ describe('derive-state-db', async () => {
174
178
  writeFile(base, 'milestones/M001/slices/S01/tasks/T01-PLAN.md', '# T01 Plan');
175
179
 
176
180
  // No DB open — isDbAvailable() is false
177
- assert.ok(!isDbAvailable(), 'fallback: DB is not available');
181
+ assertTrue(!isDbAvailable(), 'fallback: DB is not available');
178
182
  invalidateStateCache();
179
183
  const state = await deriveState(base);
180
184
 
181
- assert.deepStrictEqual(state.phase, 'executing', 'fallback: phase is executing');
182
- assert.deepStrictEqual(state.activeMilestone?.id, 'M001', 'fallback: activeMilestone is M001');
183
- assert.deepStrictEqual(state.activeSlice?.id, 'S01', 'fallback: activeSlice is S01');
184
- assert.deepStrictEqual(state.activeTask?.id, 'T01', 'fallback: activeTask is T01');
185
+ assertEq(state.phase, 'executing', 'fallback: phase is executing');
186
+ assertEq(state.activeMilestone?.id, 'M001', 'fallback: activeMilestone is M001');
187
+ assertEq(state.activeSlice?.id, 'S01', 'fallback: activeSlice is S01');
188
+ assertEq(state.activeTask?.id, 'T01', 'fallback: activeTask is T01');
185
189
  } finally {
186
190
  cleanup(base);
187
191
  }
188
- });
192
+ }
189
193
 
190
194
  // ─── Test 3: Empty DB falls back to file reads ────────────────────────
191
- test('derive-state-db: empty DB falls back to files', async () => {
195
+ console.log('\n=== derive-state-db: empty DB falls back to files ===');
196
+ {
192
197
  const base = createFixtureBase();
193
198
  try {
194
199
  writeFile(base, 'milestones/M001/M001-ROADMAP.md', ROADMAP_CONTENT);
@@ -198,26 +203,27 @@ describe('derive-state-db', async () => {
198
203
 
199
204
  // Open DB but insert nothing — empty artifacts table
200
205
  openDatabase(':memory:');
201
- assert.ok(isDbAvailable(), 'empty-db: DB is available');
206
+ assertTrue(isDbAvailable(), 'empty-db: DB is available');
202
207
 
203
208
  invalidateStateCache();
204
209
  const state = await deriveState(base);
205
210
 
206
211
  // Should still work via cachedLoadFile → loadFile disk fallback
207
- assert.deepStrictEqual(state.phase, 'executing', 'empty-db: phase is executing');
208
- assert.deepStrictEqual(state.activeMilestone?.id, 'M001', 'empty-db: activeMilestone is M001');
209
- assert.deepStrictEqual(state.activeSlice?.id, 'S01', 'empty-db: activeSlice is S01');
210
- assert.deepStrictEqual(state.activeTask?.id, 'T01', 'empty-db: activeTask is T01');
212
+ assertEq(state.phase, 'executing', 'empty-db: phase is executing');
213
+ assertEq(state.activeMilestone?.id, 'M001', 'empty-db: activeMilestone is M001');
214
+ assertEq(state.activeSlice?.id, 'S01', 'empty-db: activeSlice is S01');
215
+ assertEq(state.activeTask?.id, 'T01', 'empty-db: activeTask is T01');
211
216
 
212
217
  closeDatabase();
213
218
  } finally {
214
219
  closeDatabase();
215
220
  cleanup(base);
216
221
  }
217
- });
222
+ }
218
223
 
219
224
  // ─── Test 4: Partial DB content fills gaps from disk ──────────────────
220
- test('derive-state-db: partial DB fills gaps from disk', async () => {
225
+ console.log('\n=== derive-state-db: partial DB fills gaps from disk ===');
226
+ {
221
227
  const base = createFixtureBase();
222
228
  try {
223
229
  // Write all files to disk
@@ -238,24 +244,25 @@ describe('derive-state-db', async () => {
238
244
  const state = await deriveState(base);
239
245
 
240
246
  // Should work: roadmap from DB, plan from disk fallback
241
- assert.deepStrictEqual(state.phase, 'executing', 'partial-db: phase is executing');
242
- assert.deepStrictEqual(state.activeMilestone?.id, 'M001', 'partial-db: activeMilestone is M001');
243
- assert.deepStrictEqual(state.activeSlice?.id, 'S01', 'partial-db: activeSlice is S01');
244
- assert.deepStrictEqual(state.activeTask?.id, 'T01', 'partial-db: activeTask is T01');
247
+ assertEq(state.phase, 'executing', 'partial-db: phase is executing');
248
+ assertEq(state.activeMilestone?.id, 'M001', 'partial-db: activeMilestone is M001');
249
+ assertEq(state.activeSlice?.id, 'S01', 'partial-db: activeSlice is S01');
250
+ assertEq(state.activeTask?.id, 'T01', 'partial-db: activeTask is T01');
245
251
  // Requirements loaded from disk fallback
246
- assert.deepStrictEqual(state.requirements?.active, 2, 'partial-db: requirements.active from disk');
247
- assert.deepStrictEqual(state.requirements?.validated, 1, 'partial-db: requirements.validated from disk');
248
- assert.deepStrictEqual(state.requirements?.total, 3, 'partial-db: requirements.total from disk');
252
+ assertEq(state.requirements?.active, 2, 'partial-db: requirements.active from disk');
253
+ assertEq(state.requirements?.validated, 1, 'partial-db: requirements.validated from disk');
254
+ assertEq(state.requirements?.total, 3, 'partial-db: requirements.total from disk');
249
255
 
250
256
  closeDatabase();
251
257
  } finally {
252
258
  closeDatabase();
253
259
  cleanup(base);
254
260
  }
255
- });
261
+ }
256
262
 
257
263
  // ─── Test 5: Requirements counting from disk (DB no longer used for content) ─
258
- test('derive-state-db: requirements from disk content', async () => {
264
+ console.log('\n=== derive-state-db: requirements from disk content ===');
265
+ {
259
266
  const base = createFixtureBase();
260
267
  try {
261
268
  // Write minimal milestone dir (needed for milestone discovery)
@@ -267,16 +274,17 @@ describe('derive-state-db', async () => {
267
274
  const state = await deriveState(base);
268
275
 
269
276
  // Requirements should come from disk
270
- assert.deepStrictEqual(state.requirements?.active, 2, 'req-from-disk: requirements.active = 2');
271
- assert.deepStrictEqual(state.requirements?.validated, 1, 'req-from-disk: requirements.validated = 1');
272
- assert.deepStrictEqual(state.requirements?.total, 3, 'req-from-disk: requirements.total = 3');
277
+ assertEq(state.requirements?.active, 2, 'req-from-disk: requirements.active = 2');
278
+ assertEq(state.requirements?.validated, 1, 'req-from-disk: requirements.validated = 1');
279
+ assertEq(state.requirements?.total, 3, 'req-from-disk: requirements.total = 3');
273
280
  } finally {
274
281
  cleanup(base);
275
282
  }
276
- });
283
+ }
277
284
 
278
285
  // ─── Test 6: DB content with multi-milestone registry ─────────────────
279
- test('derive-state-db: multi-milestone from DB', async () => {
286
+ console.log('\n=== derive-state-db: multi-milestone from DB ===');
287
+ {
280
288
  const base = createFixtureBase();
281
289
 
282
290
  const completedRoadmap = `# M001: First Milestone
@@ -329,23 +337,24 @@ describe('derive-state-db', async () => {
329
337
  invalidateStateCache();
330
338
  const state = await deriveState(base);
331
339
 
332
- assert.deepStrictEqual(state.registry.length, 2, 'multi-ms-db: registry has 2 entries');
333
- assert.deepStrictEqual(state.registry[0]?.id, 'M001', 'multi-ms-db: registry[0] is M001');
334
- assert.deepStrictEqual(state.registry[0]?.status, 'complete', 'multi-ms-db: M001 is complete');
335
- assert.deepStrictEqual(state.registry[1]?.id, 'M002', 'multi-ms-db: registry[1] is M002');
336
- assert.deepStrictEqual(state.registry[1]?.status, 'active', 'multi-ms-db: M002 is active');
337
- assert.deepStrictEqual(state.activeMilestone?.id, 'M002', 'multi-ms-db: activeMilestone is M002');
338
- assert.deepStrictEqual(state.phase, 'planning', 'multi-ms-db: phase is planning (no plan for S01)');
340
+ assertEq(state.registry.length, 2, 'multi-ms-db: registry has 2 entries');
341
+ assertEq(state.registry[0]?.id, 'M001', 'multi-ms-db: registry[0] is M001');
342
+ assertEq(state.registry[0]?.status, 'complete', 'multi-ms-db: M001 is complete');
343
+ assertEq(state.registry[1]?.id, 'M002', 'multi-ms-db: registry[1] is M002');
344
+ assertEq(state.registry[1]?.status, 'active', 'multi-ms-db: M002 is active');
345
+ assertEq(state.activeMilestone?.id, 'M002', 'multi-ms-db: activeMilestone is M002');
346
+ assertEq(state.phase, 'planning', 'multi-ms-db: phase is planning (no plan for S01)');
339
347
 
340
348
  closeDatabase();
341
349
  } finally {
342
350
  closeDatabase();
343
351
  cleanup(base);
344
352
  }
345
- });
353
+ }
346
354
 
347
355
  // ─── Test 7: Cache invalidation works for DB path ─────────────────────
348
- test('derive-state-db: cache invalidation', async () => {
356
+ console.log('\n=== derive-state-db: cache invalidation ===');
357
+ {
349
358
  const base = createFixtureBase();
350
359
  try {
351
360
  writeFile(base, 'milestones/M001/M001-ROADMAP.md', ROADMAP_CONTENT);
@@ -366,7 +375,7 @@ describe('derive-state-db', async () => {
366
375
 
367
376
  invalidateStateCache();
368
377
  const state1 = await deriveState(base);
369
- assert.deepStrictEqual(state1.activeTask?.id, 'T01', 'cache-inv: first call gets T01');
378
+ assertEq(state1.activeTask?.id, 'T01', 'cache-inv: first call gets T01');
370
379
 
371
380
  // Simulate task completion by updating the plan in DB
372
381
  const updatedPlan = PLAN_CONTENT.replace('- [ ] **T01:', '- [x] **T01:');
@@ -380,27 +389,28 @@ describe('derive-state-db', async () => {
380
389
 
381
390
  // Without invalidation, should return cached result (T01 still active)
382
391
  const state2 = await deriveState(base);
383
- assert.deepStrictEqual(state2.activeTask?.id, 'T01', 'cache-inv: cached result still has T01');
392
+ assertEq(state2.activeTask?.id, 'T01', 'cache-inv: cached result still has T01');
384
393
 
385
394
  // After invalidation, should pick up updated content
386
395
  invalidateStateCache();
387
396
  const state3 = await deriveState(base);
388
- assert.deepStrictEqual(state3.phase, 'summarizing', 'cache-inv: after invalidation, phase is summarizing (all tasks done)');
389
- assert.deepStrictEqual(state3.activeTask, null, 'cache-inv: activeTask is null after all done');
397
+ assertEq(state3.phase, 'summarizing', 'cache-inv: after invalidation, phase is summarizing (all tasks done)');
398
+ assertEq(state3.activeTask, null, 'cache-inv: activeTask is null after all done');
390
399
 
391
400
  closeDatabase();
392
401
  } finally {
393
402
  closeDatabase();
394
403
  cleanup(base);
395
404
  }
396
- });
405
+ }
397
406
 
398
407
  // ═════════════════════════════════════════════════════════════════════════
399
408
  // New: deriveStateFromDb() cross-validation tests
400
409
  // ═════════════════════════════════════════════════════════════════════════
401
410
 
402
411
  // ─── Test 8: Pre-planning — milestone exists, no roadmap, no slices ───
403
- test('derive-state-db: pre-planning via DB', async () => {
412
+ console.log('\n=== derive-state-db: pre-planning via DB ===');
413
+ {
404
414
  const base = createFixtureBase();
405
415
  try {
406
416
  // Create milestone dir on disk with a CONTEXT file (not a ghost)
@@ -417,22 +427,23 @@ describe('derive-state-db', async () => {
417
427
  invalidateStateCache();
418
428
  const dbState = await deriveStateFromDb(base);
419
429
 
420
- assert.deepStrictEqual(dbState.phase, fileState.phase, 'pre-plan-db: phase matches');
421
- assert.deepStrictEqual(dbState.activeMilestone?.id, fileState.activeMilestone?.id, 'pre-plan-db: activeMilestone.id matches');
422
- assert.deepStrictEqual(dbState.activeSlice, fileState.activeSlice, 'pre-plan-db: activeSlice matches');
423
- assert.deepStrictEqual(dbState.activeTask, fileState.activeTask, 'pre-plan-db: activeTask matches');
424
- assert.deepStrictEqual(dbState.registry.length, fileState.registry.length, 'pre-plan-db: registry length matches');
425
- assert.deepStrictEqual(dbState.registry[0]?.status, fileState.registry[0]?.status, 'pre-plan-db: registry[0] status matches');
430
+ assertEq(dbState.phase, fileState.phase, 'pre-plan-db: phase matches');
431
+ assertEq(dbState.activeMilestone?.id, fileState.activeMilestone?.id, 'pre-plan-db: activeMilestone.id matches');
432
+ assertEq(dbState.activeSlice, fileState.activeSlice, 'pre-plan-db: activeSlice matches');
433
+ assertEq(dbState.activeTask, fileState.activeTask, 'pre-plan-db: activeTask matches');
434
+ assertEq(dbState.registry.length, fileState.registry.length, 'pre-plan-db: registry length matches');
435
+ assertEq(dbState.registry[0]?.status, fileState.registry[0]?.status, 'pre-plan-db: registry[0] status matches');
426
436
 
427
437
  closeDatabase();
428
438
  } finally {
429
439
  closeDatabase();
430
440
  cleanup(base);
431
441
  }
432
- });
442
+ }
433
443
 
434
444
  // ─── Test 9: Executing — active task with partial completion ──────────
435
- test('derive-state-db: executing via DB', async () => {
445
+ console.log('\n=== derive-state-db: executing via DB ===');
446
+ {
436
447
  const base = createFixtureBase();
437
448
  try {
438
449
  // Build filesystem fixture
@@ -455,23 +466,24 @@ describe('derive-state-db', async () => {
455
466
  invalidateStateCache();
456
467
  const dbState = await deriveStateFromDb(base);
457
468
 
458
- assert.deepStrictEqual(dbState.phase, 'executing', 'exec-db: phase is executing');
459
- assert.deepStrictEqual(dbState.activeMilestone?.id, 'M001', 'exec-db: activeMilestone is M001');
460
- assert.deepStrictEqual(dbState.activeSlice?.id, 'S01', 'exec-db: activeSlice is S01');
461
- assert.deepStrictEqual(dbState.activeTask?.id, 'T01', 'exec-db: activeTask is T01');
462
- assert.deepStrictEqual(dbState.progress?.tasks?.done, 1, 'exec-db: tasks.done = 1');
463
- assert.deepStrictEqual(dbState.progress?.tasks?.total, 2, 'exec-db: tasks.total = 2');
464
- assert.deepStrictEqual(dbState.phase, fileState.phase, 'exec-db: phase matches filesystem');
469
+ assertEq(dbState.phase, 'executing', 'exec-db: phase is executing');
470
+ assertEq(dbState.activeMilestone?.id, 'M001', 'exec-db: activeMilestone is M001');
471
+ assertEq(dbState.activeSlice?.id, 'S01', 'exec-db: activeSlice is S01');
472
+ assertEq(dbState.activeTask?.id, 'T01', 'exec-db: activeTask is T01');
473
+ assertEq(dbState.progress?.tasks?.done, 1, 'exec-db: tasks.done = 1');
474
+ assertEq(dbState.progress?.tasks?.total, 2, 'exec-db: tasks.total = 2');
475
+ assertEq(dbState.phase, fileState.phase, 'exec-db: phase matches filesystem');
465
476
 
466
477
  closeDatabase();
467
478
  } finally {
468
479
  closeDatabase();
469
480
  cleanup(base);
470
481
  }
471
- });
482
+ }
472
483
 
473
484
  // ─── Test 10: Summarizing — all tasks complete, no slice summary ──────
474
- test('derive-state-db: summarizing via DB', async () => {
485
+ console.log('\n=== derive-state-db: summarizing via DB ===');
486
+ {
475
487
  const base = createFixtureBase();
476
488
  try {
477
489
  const allDonePlan = `# S01: First Slice
@@ -505,20 +517,21 @@ describe('derive-state-db', async () => {
505
517
  invalidateStateCache();
506
518
  const dbState = await deriveStateFromDb(base);
507
519
 
508
- assert.deepStrictEqual(dbState.phase, 'summarizing', 'summarize-db: phase is summarizing');
509
- assert.deepStrictEqual(dbState.phase, fileState.phase, 'summarize-db: phase matches filesystem');
510
- assert.deepStrictEqual(dbState.activeSlice?.id, 'S01', 'summarize-db: activeSlice is S01');
511
- assert.deepStrictEqual(dbState.activeTask, null, 'summarize-db: activeTask is null');
520
+ assertEq(dbState.phase, 'summarizing', 'summarize-db: phase is summarizing');
521
+ assertEq(dbState.phase, fileState.phase, 'summarize-db: phase matches filesystem');
522
+ assertEq(dbState.activeSlice?.id, 'S01', 'summarize-db: activeSlice is S01');
523
+ assertEq(dbState.activeTask, null, 'summarize-db: activeTask is null');
512
524
 
513
525
  closeDatabase();
514
526
  } finally {
515
527
  closeDatabase();
516
528
  cleanup(base);
517
529
  }
518
- });
530
+ }
519
531
 
520
532
  // ─── Test 11: Complete — all milestones complete ──────────────────────
521
- test('derive-state-db: all complete via DB', async () => {
533
+ console.log('\n=== derive-state-db: all complete via DB ===');
534
+ {
522
535
  const base = createFixtureBase();
523
536
  try {
524
537
  const completedRoadmap = `# M001: Done Milestone
@@ -544,20 +557,21 @@ describe('derive-state-db', async () => {
544
557
  invalidateStateCache();
545
558
  const dbState = await deriveStateFromDb(base);
546
559
 
547
- assert.deepStrictEqual(dbState.phase, 'complete', 'complete-db: phase is complete');
548
- assert.deepStrictEqual(dbState.phase, fileState.phase, 'complete-db: phase matches filesystem');
549
- assert.deepStrictEqual(dbState.registry.length, 1, 'complete-db: registry has 1 entry');
550
- assert.deepStrictEqual(dbState.registry[0]?.status, 'complete', 'complete-db: M001 is complete');
560
+ assertEq(dbState.phase, 'complete', 'complete-db: phase is complete');
561
+ assertEq(dbState.phase, fileState.phase, 'complete-db: phase matches filesystem');
562
+ assertEq(dbState.registry.length, 1, 'complete-db: registry has 1 entry');
563
+ assertEq(dbState.registry[0]?.status, 'complete', 'complete-db: M001 is complete');
551
564
 
552
565
  closeDatabase();
553
566
  } finally {
554
567
  closeDatabase();
555
568
  cleanup(base);
556
569
  }
557
- });
570
+ }
558
571
 
559
572
  // ─── Test 12: Blocked — slice deps unmet ──────────────────────────────
560
- test('derive-state-db: blocked slice via DB', async () => {
573
+ console.log('\n=== derive-state-db: blocked slice via DB ===');
574
+ {
561
575
  const base = createFixtureBase();
562
576
  try {
563
577
  // Roadmap with S02 depending on S01, but S01 not done
@@ -587,19 +601,20 @@ describe('derive-state-db', async () => {
587
601
  invalidateStateCache();
588
602
  const dbState = await deriveStateFromDb(base);
589
603
 
590
- assert.deepStrictEqual(dbState.phase, 'blocked', 'blocked-db: phase is blocked');
591
- assert.deepStrictEqual(dbState.phase, fileState.phase, 'blocked-db: phase matches filesystem');
592
- assert.ok(dbState.blockers.length > 0, 'blocked-db: has blockers');
604
+ assertEq(dbState.phase, 'blocked', 'blocked-db: phase is blocked');
605
+ assertEq(dbState.phase, fileState.phase, 'blocked-db: phase matches filesystem');
606
+ assertTrue(dbState.blockers.length > 0, 'blocked-db: has blockers');
593
607
 
594
608
  closeDatabase();
595
609
  } finally {
596
610
  closeDatabase();
597
611
  cleanup(base);
598
612
  }
599
- });
613
+ }
600
614
 
601
615
  // ─── Test 13: Parked milestone ────────────────────────────────────────
602
- test('derive-state-db: parked milestone via DB', async () => {
616
+ console.log('\n=== derive-state-db: parked milestone via DB ===');
617
+ {
603
618
  const base = createFixtureBase();
604
619
  try {
605
620
  writeFile(base, 'milestones/M001/M001-ROADMAP.md', ROADMAP_CONTENT);
@@ -616,19 +631,20 @@ describe('derive-state-db', async () => {
616
631
  invalidateStateCache();
617
632
  const dbState = await deriveStateFromDb(base);
618
633
 
619
- assert.deepStrictEqual(dbState.phase, fileState.phase, 'parked-db: phase matches filesystem');
620
- assert.deepStrictEqual(dbState.activeMilestone?.id, 'M002', 'parked-db: activeMilestone is M002');
621
- assert.ok(dbState.registry.some(e => e.id === 'M001' && e.status === 'parked'), 'parked-db: M001 is parked in registry');
634
+ assertEq(dbState.phase, fileState.phase, 'parked-db: phase matches filesystem');
635
+ assertEq(dbState.activeMilestone?.id, 'M002', 'parked-db: activeMilestone is M002');
636
+ assertTrue(dbState.registry.some(e => e.id === 'M001' && e.status === 'parked'), 'parked-db: M001 is parked in registry');
622
637
 
623
638
  closeDatabase();
624
639
  } finally {
625
640
  closeDatabase();
626
641
  cleanup(base);
627
642
  }
628
- });
643
+ }
629
644
 
630
645
  // ─── Test 14: Validating-milestone — all slices done, no terminal validation ─
631
- test('derive-state-db: validating-milestone via DB', async () => {
646
+ console.log('\n=== derive-state-db: validating-milestone via DB ===');
647
+ {
632
648
  const base = createFixtureBase();
633
649
  try {
634
650
  const doneRoadmap = `# M001: Validate Test
@@ -653,19 +669,20 @@ describe('derive-state-db', async () => {
653
669
  invalidateStateCache();
654
670
  const dbState = await deriveStateFromDb(base);
655
671
 
656
- assert.deepStrictEqual(dbState.phase, 'validating-milestone', 'validate-db: phase is validating-milestone');
657
- assert.deepStrictEqual(dbState.phase, fileState.phase, 'validate-db: phase matches filesystem');
658
- assert.deepStrictEqual(dbState.activeMilestone?.id, 'M001', 'validate-db: activeMilestone is M001');
672
+ assertEq(dbState.phase, 'validating-milestone', 'validate-db: phase is validating-milestone');
673
+ assertEq(dbState.phase, fileState.phase, 'validate-db: phase matches filesystem');
674
+ assertEq(dbState.activeMilestone?.id, 'M001', 'validate-db: activeMilestone is M001');
659
675
 
660
676
  closeDatabase();
661
677
  } finally {
662
678
  closeDatabase();
663
679
  cleanup(base);
664
680
  }
665
- });
681
+ }
666
682
 
667
683
  // ─── Test 15: Completing-milestone — terminal validation, no summary ──
668
- test('derive-state-db: completing-milestone via DB', async () => {
684
+ console.log('\n=== derive-state-db: completing-milestone via DB ===');
685
+ {
669
686
  const base = createFixtureBase();
670
687
  try {
671
688
  const doneRoadmap = `# M001: Complete Test
@@ -690,18 +707,19 @@ describe('derive-state-db', async () => {
690
707
  invalidateStateCache();
691
708
  const dbState = await deriveStateFromDb(base);
692
709
 
693
- assert.deepStrictEqual(dbState.phase, 'completing-milestone', 'completing-db: phase is completing-milestone');
694
- assert.deepStrictEqual(dbState.phase, fileState.phase, 'completing-db: phase matches filesystem');
710
+ assertEq(dbState.phase, 'completing-milestone', 'completing-db: phase is completing-milestone');
711
+ assertEq(dbState.phase, fileState.phase, 'completing-db: phase matches filesystem');
695
712
 
696
713
  closeDatabase();
697
714
  } finally {
698
715
  closeDatabase();
699
716
  cleanup(base);
700
717
  }
701
- });
718
+ }
702
719
 
703
720
  // ─── Test 16: Replanning-slice — REPLAN-TRIGGER file exists ───────────
704
- test('derive-state-db: replanning-slice via DB', async () => {
721
+ console.log('\n=== derive-state-db: replanning-slice via DB ===');
722
+ {
705
723
  const base = createFixtureBase();
706
724
  try {
707
725
  writeFile(base, 'milestones/M001/M001-ROADMAP.md', ROADMAP_CONTENT);
@@ -731,18 +749,19 @@ describe('derive-state-db', async () => {
731
749
  invalidateStateCache();
732
750
  const dbState = await deriveStateFromDb(base);
733
751
 
734
- assert.deepStrictEqual(dbState.phase, 'replanning-slice', 'replan-db: phase is replanning-slice');
735
- assert.deepStrictEqual(dbState.phase, fileState.phase, 'replan-db: phase matches filesystem');
752
+ assertEq(dbState.phase, 'replanning-slice', 'replan-db: phase is replanning-slice');
753
+ assertEq(dbState.phase, fileState.phase, 'replan-db: phase matches filesystem');
736
754
 
737
755
  closeDatabase();
738
756
  } finally {
739
757
  closeDatabase();
740
758
  cleanup(base);
741
759
  }
742
- });
760
+ }
743
761
 
744
762
  // ─── Test 17: Performance — deriveStateFromDb < 1ms on populated DB ───
745
- test('derive-state-db: performance assertion', async () => {
763
+ console.log('\n=== derive-state-db: performance assertion ===');
764
+ {
746
765
  const base = createFixtureBase();
747
766
  try {
748
767
  writeFile(base, 'milestones/M001/M001-ROADMAP.md', ROADMAP_CONTENT);
@@ -770,17 +789,18 @@ describe('derive-state-db', async () => {
770
789
  console.log(` deriveStateFromDb() took ${elapsed.toFixed(3)}ms`);
771
790
  // Use 10ms threshold — catches real regressions without flaking on
772
791
  // CI runners under load (1ms threshold failed at 1.050ms on GitHub Actions)
773
- assert.ok(elapsed < 10, `perf-db: deriveStateFromDb() <10ms (got ${elapsed.toFixed(3)}ms)`);
792
+ assertTrue(elapsed < 10, `perf-db: deriveStateFromDb() <10ms (got ${elapsed.toFixed(3)}ms)`);
774
793
 
775
794
  closeDatabase();
776
795
  } finally {
777
796
  closeDatabase();
778
797
  cleanup(base);
779
798
  }
780
- });
799
+ }
781
800
 
782
801
  // ─── Test 18: Multi-milestone with deps — M001 complete, M002 depends on M001, M003 depends on M002 ─
783
- test('derive-state-db: multi-milestone deps via DB', async () => {
802
+ console.log('\n=== derive-state-db: multi-milestone deps via DB ===');
803
+ {
784
804
  const base = createFixtureBase();
785
805
  try {
786
806
  const m1Roadmap = `# M001: First
@@ -821,28 +841,29 @@ describe('derive-state-db', async () => {
821
841
  invalidateStateCache();
822
842
  const dbState = await deriveStateFromDb(base);
823
843
 
824
- assert.deepStrictEqual(dbState.registry.length, fileState.registry.length, 'multi-deps-db: registry length matches');
825
- assert.deepStrictEqual(dbState.activeMilestone?.id, 'M002', 'multi-deps-db: activeMilestone is M002 (M001 complete, M003 dep unmet)');
826
- assert.deepStrictEqual(dbState.activeMilestone?.id, fileState.activeMilestone?.id, 'multi-deps-db: activeMilestone matches filesystem');
827
- assert.deepStrictEqual(dbState.phase, fileState.phase, 'multi-deps-db: phase matches filesystem');
844
+ assertEq(dbState.registry.length, fileState.registry.length, 'multi-deps-db: registry length matches');
845
+ assertEq(dbState.activeMilestone?.id, 'M002', 'multi-deps-db: activeMilestone is M002 (M001 complete, M003 dep unmet)');
846
+ assertEq(dbState.activeMilestone?.id, fileState.activeMilestone?.id, 'multi-deps-db: activeMilestone matches filesystem');
847
+ assertEq(dbState.phase, fileState.phase, 'multi-deps-db: phase matches filesystem');
828
848
 
829
849
  // Check registry statuses
830
850
  const m1reg = dbState.registry.find(e => e.id === 'M001');
831
851
  const m2reg = dbState.registry.find(e => e.id === 'M002');
832
852
  const m3reg = dbState.registry.find(e => e.id === 'M003');
833
- assert.deepStrictEqual(m1reg?.status, 'complete', 'multi-deps-db: M001 is complete');
834
- assert.deepStrictEqual(m2reg?.status, 'active', 'multi-deps-db: M002 is active');
835
- assert.deepStrictEqual(m3reg?.status, 'pending', 'multi-deps-db: M003 is pending (dep M002 unmet)');
853
+ assertEq(m1reg?.status, 'complete', 'multi-deps-db: M001 is complete');
854
+ assertEq(m2reg?.status, 'active', 'multi-deps-db: M002 is active');
855
+ assertEq(m3reg?.status, 'pending', 'multi-deps-db: M003 is pending (dep M002 unmet)');
836
856
 
837
857
  closeDatabase();
838
858
  } finally {
839
859
  closeDatabase();
840
860
  cleanup(base);
841
861
  }
842
- });
862
+ }
843
863
 
844
864
  // ─── Test 19: K002 — both 'complete' and 'done' treated as done ───────
845
- test('derive-state-db: K002 status handling', async () => {
865
+ console.log('\n=== derive-state-db: K002 status handling ===');
866
+ {
846
867
  const base = createFixtureBase();
847
868
  try {
848
869
  writeFile(base, 'milestones/M001/M001-ROADMAP.md', ROADMAP_CONTENT);
@@ -861,19 +882,20 @@ describe('derive-state-db', async () => {
861
882
  invalidateStateCache();
862
883
  const dbState = await deriveStateFromDb(base);
863
884
 
864
- assert.deepStrictEqual(dbState.phase, 'executing', 'k002-db: phase is executing');
865
- assert.deepStrictEqual(dbState.activeTask?.id, 'T01', 'k002-db: activeTask is T01 (T02 done)');
866
- assert.deepStrictEqual(dbState.progress?.tasks?.done, 1, 'k002-db: tasks.done counts done status');
885
+ assertEq(dbState.phase, 'executing', 'k002-db: phase is executing');
886
+ assertEq(dbState.activeTask?.id, 'T01', 'k002-db: activeTask is T01 (T02 done)');
887
+ assertEq(dbState.progress?.tasks?.done, 1, 'k002-db: tasks.done counts done status');
867
888
 
868
889
  closeDatabase();
869
890
  } finally {
870
891
  closeDatabase();
871
892
  cleanup(base);
872
893
  }
873
- });
894
+ }
874
895
 
875
896
  // ─── Test 20: Dual-path wiring — deriveState() uses DB when populated ─
876
- test('derive-state-db: dual-path wiring', async () => {
897
+ console.log('\n=== derive-state-db: dual-path wiring ===');
898
+ {
877
899
  const base = createFixtureBase();
878
900
  try {
879
901
  writeFile(base, 'milestones/M001/M001-ROADMAP.md', ROADMAP_CONTENT);
@@ -892,20 +914,21 @@ describe('derive-state-db', async () => {
892
914
  invalidateStateCache();
893
915
  const state = await deriveState(base);
894
916
 
895
- assert.deepStrictEqual(state.phase, 'executing', 'dual-path: phase is executing');
896
- assert.deepStrictEqual(state.activeMilestone?.id, 'M001', 'dual-path: activeMilestone is M001');
897
- assert.deepStrictEqual(state.activeSlice?.id, 'S01', 'dual-path: activeSlice is S01');
898
- assert.deepStrictEqual(state.activeTask?.id, 'T01', 'dual-path: activeTask is T01');
917
+ assertEq(state.phase, 'executing', 'dual-path: phase is executing');
918
+ assertEq(state.activeMilestone?.id, 'M001', 'dual-path: activeMilestone is M001');
919
+ assertEq(state.activeSlice?.id, 'S01', 'dual-path: activeSlice is S01');
920
+ assertEq(state.activeTask?.id, 'T01', 'dual-path: activeTask is T01');
899
921
 
900
922
  closeDatabase();
901
923
  } finally {
902
924
  closeDatabase();
903
925
  cleanup(base);
904
926
  }
905
- });
927
+ }
906
928
 
907
929
  // ─── Test 21: Ghost milestone skipped ─────────────────────────────────
908
- test('derive-state-db: ghost milestone skipped', async () => {
930
+ console.log('\n=== derive-state-db: ghost milestone skipped ===');
931
+ {
909
932
  const base = createFixtureBase();
910
933
  try {
911
934
  // Ghost: milestone dir exists with only META.json, no context/roadmap/summary
@@ -926,20 +949,21 @@ describe('derive-state-db', async () => {
926
949
  const dbState = await deriveStateFromDb(base);
927
950
 
928
951
  // Ghost should be skipped — M002 should be active
929
- assert.deepStrictEqual(dbState.activeMilestone?.id, 'M002', 'ghost-db: activeMilestone is M002 (ghost skipped)');
930
- assert.deepStrictEqual(dbState.activeMilestone?.id, fileState.activeMilestone?.id, 'ghost-db: matches filesystem');
952
+ assertEq(dbState.activeMilestone?.id, 'M002', 'ghost-db: activeMilestone is M002 (ghost skipped)');
953
+ assertEq(dbState.activeMilestone?.id, fileState.activeMilestone?.id, 'ghost-db: matches filesystem');
931
954
  // Ghost should not appear in registry
932
- assert.ok(!dbState.registry.some(e => e.id === 'M001'), 'ghost-db: M001 not in registry');
955
+ assertTrue(!dbState.registry.some(e => e.id === 'M001'), 'ghost-db: M001 not in registry');
933
956
 
934
957
  closeDatabase();
935
958
  } finally {
936
959
  closeDatabase();
937
960
  cleanup(base);
938
961
  }
939
- });
962
+ }
940
963
 
941
964
  // ─── Test 22: Needs-discussion — CONTEXT-DRAFT exists ─────────────────
942
- test('derive-state-db: needs-discussion via DB', async () => {
965
+ console.log('\n=== derive-state-db: needs-discussion via DB ===');
966
+ {
943
967
  const base = createFixtureBase();
944
968
  try {
945
969
  writeFile(base, 'milestones/M001/M001-CONTEXT-DRAFT.md', '# M001: Draft\n\nDraft content.');
@@ -953,13 +977,20 @@ describe('derive-state-db', async () => {
953
977
  invalidateStateCache();
954
978
  const dbState = await deriveStateFromDb(base);
955
979
 
956
- assert.deepStrictEqual(dbState.phase, 'needs-discussion', 'discuss-db: phase is needs-discussion');
957
- assert.deepStrictEqual(dbState.phase, fileState.phase, 'discuss-db: phase matches filesystem');
980
+ assertEq(dbState.phase, 'needs-discussion', 'discuss-db: phase is needs-discussion');
981
+ assertEq(dbState.phase, fileState.phase, 'discuss-db: phase matches filesystem');
958
982
 
959
983
  closeDatabase();
960
984
  } finally {
961
985
  closeDatabase();
962
986
  cleanup(base);
963
987
  }
964
- });
988
+ }
989
+
990
+ report();
991
+ }
992
+
993
+ main().catch((error) => {
994
+ console.error(error);
995
+ process.exit(1);
965
996
  });