gsd-pi 2.44.0-dev.62b5d6c → 2.44.0-dev.73f2fd5

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 (326) hide show
  1. package/README.md +30 -12
  2. package/dist/resources/extensions/gsd/auto/infra-errors.js +3 -0
  3. package/dist/resources/extensions/gsd/auto/phases.js +36 -36
  4. package/dist/resources/extensions/gsd/auto-prompts.js +24 -1
  5. package/dist/resources/extensions/gsd/auto-start.js +10 -0
  6. package/dist/resources/extensions/gsd/auto-timers.js +57 -3
  7. package/dist/resources/extensions/gsd/auto-worktree-sync.js +4 -0
  8. package/dist/resources/extensions/gsd/auto-worktree.js +9 -6
  9. package/dist/resources/extensions/gsd/auto.js +30 -3
  10. package/dist/resources/extensions/gsd/bootstrap/db-tools.js +156 -0
  11. package/dist/resources/extensions/gsd/bootstrap/system-context.js +46 -12
  12. package/dist/resources/extensions/gsd/commands/catalog.js +6 -1
  13. package/dist/resources/extensions/gsd/commands/handlers/core.js +1 -0
  14. package/dist/resources/extensions/gsd/commands/handlers/ops.js +5 -0
  15. package/dist/resources/extensions/gsd/commands/handlers/workflow.js +5 -0
  16. package/dist/resources/extensions/gsd/commands-mcp-status.js +187 -0
  17. package/dist/resources/extensions/gsd/db-writer.js +34 -16
  18. package/dist/resources/extensions/gsd/doctor.js +8 -0
  19. package/dist/resources/extensions/gsd/git-service.js +8 -3
  20. package/dist/resources/extensions/gsd/gsd-db.js +12 -1
  21. package/dist/resources/extensions/gsd/markdown-renderer.js +1 -1
  22. package/dist/resources/extensions/gsd/preferences.js +9 -1
  23. package/dist/resources/extensions/gsd/prompts/complete-milestone.md +2 -4
  24. package/dist/resources/extensions/gsd/prompts/plan-slice.md +1 -1
  25. package/dist/resources/extensions/gsd/prompts/reassess-roadmap.md +6 -6
  26. package/dist/resources/extensions/gsd/prompts/replan-slice.md +3 -14
  27. package/dist/resources/extensions/gsd/prompts/validate-milestone.md +7 -37
  28. package/dist/resources/extensions/gsd/provider-error-pause.js +7 -0
  29. package/dist/resources/extensions/gsd/state.js +19 -2
  30. package/dist/resources/extensions/gsd/tools/plan-slice.js +1 -0
  31. package/dist/resources/extensions/gsd/tools/plan-task.js +1 -0
  32. package/dist/resources/extensions/gsd/tools/replan-slice.js +2 -0
  33. package/dist/resources/extensions/gsd/tools/validate-milestone.js +88 -0
  34. package/dist/resources/extensions/gsd/worktree-resolver.js +6 -0
  35. package/dist/resources/extensions/mcp-client/index.js +14 -0
  36. package/dist/web/standalone/.next/BUILD_ID +1 -1
  37. package/dist/web/standalone/.next/app-path-routes-manifest.json +17 -17
  38. package/dist/web/standalone/.next/build-manifest.json +2 -2
  39. package/dist/web/standalone/.next/prerender-manifest.json +3 -3
  40. package/dist/web/standalone/.next/server/app/_global-error.html +2 -2
  41. package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
  42. package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  43. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
  44. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
  45. package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  46. package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  47. package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  48. package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
  49. package/dist/web/standalone/.next/server/app/_not-found.rsc +1 -1
  50. package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
  51. package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  52. package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +1 -1
  53. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  54. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  55. package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
  56. package/dist/web/standalone/.next/server/app/index.html +1 -1
  57. package/dist/web/standalone/.next/server/app/index.rsc +1 -1
  58. package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +1 -1
  59. package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +1 -1
  60. package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
  61. package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +1 -1
  62. package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
  63. package/dist/web/standalone/.next/server/app-paths-manifest.json +17 -17
  64. package/dist/web/standalone/.next/server/pages/404.html +1 -1
  65. package/dist/web/standalone/.next/server/pages/500.html +2 -2
  66. package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
  67. package/package.json +1 -1
  68. package/packages/pi-coding-agent/dist/core/auth-storage.d.ts +3 -1
  69. package/packages/pi-coding-agent/dist/core/auth-storage.d.ts.map +1 -1
  70. package/packages/pi-coding-agent/dist/core/auth-storage.js +15 -1
  71. package/packages/pi-coding-agent/dist/core/auth-storage.js.map +1 -1
  72. package/packages/pi-coding-agent/dist/core/auth-storage.test.js +6 -8
  73. package/packages/pi-coding-agent/dist/core/auth-storage.test.js.map +1 -1
  74. package/packages/pi-coding-agent/dist/core/extensions/runner.test.js +24 -26
  75. package/packages/pi-coding-agent/dist/core/extensions/runner.test.js.map +1 -1
  76. package/packages/pi-coding-agent/dist/core/fs-utils.test.js +29 -48
  77. package/packages/pi-coding-agent/dist/core/fs-utils.test.js.map +1 -1
  78. package/packages/pi-coding-agent/dist/core/local-model-check.d.ts +15 -0
  79. package/packages/pi-coding-agent/dist/core/local-model-check.d.ts.map +1 -0
  80. package/packages/pi-coding-agent/dist/core/local-model-check.js +41 -0
  81. package/packages/pi-coding-agent/dist/core/local-model-check.js.map +1 -0
  82. package/packages/pi-coding-agent/dist/core/model-registry.d.ts +11 -0
  83. package/packages/pi-coding-agent/dist/core/model-registry.d.ts.map +1 -1
  84. package/packages/pi-coding-agent/dist/core/model-registry.js +20 -1
  85. package/packages/pi-coding-agent/dist/core/model-registry.js.map +1 -1
  86. package/packages/pi-coding-agent/dist/core/resolve-config-value.test.js +34 -44
  87. package/packages/pi-coding-agent/dist/core/resolve-config-value.test.js.map +1 -1
  88. package/packages/pi-coding-agent/dist/core/session-manager.test.js +30 -34
  89. package/packages/pi-coding-agent/dist/core/session-manager.test.js.map +1 -1
  90. package/packages/pi-coding-agent/dist/core/settings-manager.d.ts +3 -0
  91. package/packages/pi-coding-agent/dist/core/settings-manager.d.ts.map +1 -1
  92. package/packages/pi-coding-agent/dist/core/settings-manager.js +6 -0
  93. package/packages/pi-coding-agent/dist/core/settings-manager.js.map +1 -1
  94. package/packages/pi-coding-agent/dist/core/tools/edit-diff.test.js +10 -12
  95. package/packages/pi-coding-agent/dist/core/tools/edit-diff.test.js.map +1 -1
  96. package/packages/pi-coding-agent/dist/main.d.ts.map +1 -1
  97. package/packages/pi-coding-agent/dist/main.js +17 -0
  98. package/packages/pi-coding-agent/dist/main.js.map +1 -1
  99. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/timestamp.test.d.ts +2 -0
  100. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/timestamp.test.d.ts.map +1 -0
  101. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/timestamp.test.js +32 -0
  102. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/timestamp.test.js.map +1 -0
  103. package/packages/pi-coding-agent/dist/modes/interactive/components/assistant-message.d.ts +3 -1
  104. package/packages/pi-coding-agent/dist/modes/interactive/components/assistant-message.d.ts.map +1 -1
  105. package/packages/pi-coding-agent/dist/modes/interactive/components/assistant-message.js +8 -1
  106. package/packages/pi-coding-agent/dist/modes/interactive/components/assistant-message.js.map +1 -1
  107. package/packages/pi-coding-agent/dist/modes/interactive/components/settings-selector.d.ts +2 -0
  108. package/packages/pi-coding-agent/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
  109. package/packages/pi-coding-agent/dist/modes/interactive/components/settings-selector.js +12 -0
  110. package/packages/pi-coding-agent/dist/modes/interactive/components/settings-selector.js.map +1 -1
  111. package/packages/pi-coding-agent/dist/modes/interactive/components/timestamp.d.ts +15 -0
  112. package/packages/pi-coding-agent/dist/modes/interactive/components/timestamp.d.ts.map +1 -0
  113. package/packages/pi-coding-agent/dist/modes/interactive/components/timestamp.js +40 -0
  114. package/packages/pi-coding-agent/dist/modes/interactive/components/timestamp.js.map +1 -0
  115. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
  116. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.js +4 -1
  117. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.js.map +1 -1
  118. package/packages/pi-coding-agent/dist/modes/interactive/components/user-message.d.ts +5 -2
  119. package/packages/pi-coding-agent/dist/modes/interactive/components/user-message.d.ts.map +1 -1
  120. package/packages/pi-coding-agent/dist/modes/interactive/components/user-message.js +13 -2
  121. package/packages/pi-coding-agent/dist/modes/interactive/components/user-message.js.map +1 -1
  122. package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.d.ts.map +1 -1
  123. package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.js +17 -8
  124. package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.js.map +1 -1
  125. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  126. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js +7 -3
  127. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js.map +1 -1
  128. package/packages/pi-coding-agent/dist/resources/extensions/memory/storage.test.js +43 -47
  129. package/packages/pi-coding-agent/dist/resources/extensions/memory/storage.test.js.map +1 -1
  130. package/packages/pi-coding-agent/src/core/auth-storage.test.ts +7 -7
  131. package/packages/pi-coding-agent/src/core/auth-storage.ts +15 -1
  132. package/packages/pi-coding-agent/src/core/extensions/runner.test.ts +26 -26
  133. package/packages/pi-coding-agent/src/core/fs-utils.test.ts +31 -43
  134. package/packages/pi-coding-agent/src/core/local-model-check.ts +45 -0
  135. package/packages/pi-coding-agent/src/core/model-registry.ts +21 -1
  136. package/packages/pi-coding-agent/src/core/resolve-config-value.test.ts +40 -45
  137. package/packages/pi-coding-agent/src/core/session-manager.test.ts +33 -33
  138. package/packages/pi-coding-agent/src/core/settings-manager.ts +9 -0
  139. package/packages/pi-coding-agent/src/core/tools/edit-diff.test.ts +17 -17
  140. package/packages/pi-coding-agent/src/main.ts +19 -0
  141. package/packages/pi-coding-agent/src/modes/interactive/components/__tests__/timestamp.test.ts +38 -0
  142. package/packages/pi-coding-agent/src/modes/interactive/components/assistant-message.ts +10 -0
  143. package/packages/pi-coding-agent/src/modes/interactive/components/settings-selector.ts +15 -0
  144. package/packages/pi-coding-agent/src/modes/interactive/components/timestamp.ts +48 -0
  145. package/packages/pi-coding-agent/src/modes/interactive/components/tool-execution.ts +3 -1
  146. package/packages/pi-coding-agent/src/modes/interactive/components/user-message.ts +18 -3
  147. package/packages/pi-coding-agent/src/modes/interactive/controllers/chat-controller.ts +16 -7
  148. package/packages/pi-coding-agent/src/modes/interactive/interactive-mode.ts +8 -1
  149. package/packages/pi-coding-agent/src/resources/extensions/memory/storage.test.ts +74 -74
  150. package/src/resources/extensions/gsd/auto/infra-errors.ts +3 -0
  151. package/src/resources/extensions/gsd/auto/phases.ts +45 -48
  152. package/src/resources/extensions/gsd/auto-prompts.ts +24 -1
  153. package/src/resources/extensions/gsd/auto-start.ts +14 -0
  154. package/src/resources/extensions/gsd/auto-timers.ts +64 -3
  155. package/src/resources/extensions/gsd/auto-worktree-sync.ts +5 -0
  156. package/src/resources/extensions/gsd/auto-worktree.ts +9 -6
  157. package/src/resources/extensions/gsd/auto.ts +37 -3
  158. package/src/resources/extensions/gsd/bootstrap/db-tools.ts +148 -0
  159. package/src/resources/extensions/gsd/bootstrap/system-context.ts +48 -11
  160. package/src/resources/extensions/gsd/commands/catalog.ts +6 -1
  161. package/src/resources/extensions/gsd/commands/handlers/core.ts +1 -0
  162. package/src/resources/extensions/gsd/commands/handlers/ops.ts +5 -0
  163. package/src/resources/extensions/gsd/commands/handlers/workflow.ts +8 -0
  164. package/src/resources/extensions/gsd/commands-mcp-status.ts +247 -0
  165. package/src/resources/extensions/gsd/db-writer.ts +39 -17
  166. package/src/resources/extensions/gsd/doctor.ts +7 -1
  167. package/src/resources/extensions/gsd/git-service.ts +6 -2
  168. package/src/resources/extensions/gsd/gsd-db.ts +16 -1
  169. package/src/resources/extensions/gsd/markdown-renderer.ts +1 -1
  170. package/src/resources/extensions/gsd/preferences.ts +11 -1
  171. package/src/resources/extensions/gsd/prompts/complete-milestone.md +2 -4
  172. package/src/resources/extensions/gsd/prompts/plan-slice.md +1 -1
  173. package/src/resources/extensions/gsd/prompts/reassess-roadmap.md +6 -6
  174. package/src/resources/extensions/gsd/prompts/replan-slice.md +3 -14
  175. package/src/resources/extensions/gsd/prompts/validate-milestone.md +7 -37
  176. package/src/resources/extensions/gsd/provider-error-pause.ts +9 -0
  177. package/src/resources/extensions/gsd/state.ts +19 -1
  178. package/src/resources/extensions/gsd/tests/all-milestones-complete-merge.test.ts +99 -99
  179. package/src/resources/extensions/gsd/tests/auto-lock-creation.test.ts +14 -16
  180. package/src/resources/extensions/gsd/tests/auto-paused-session-validation.test.ts +43 -57
  181. package/src/resources/extensions/gsd/tests/auto-pr-bugs.test.ts +88 -0
  182. package/src/resources/extensions/gsd/tests/auto-preflight.test.ts +11 -13
  183. package/src/resources/extensions/gsd/tests/auto-recovery.test.ts +465 -523
  184. package/src/resources/extensions/gsd/tests/auto-secrets-gate.test.ts +73 -75
  185. package/src/resources/extensions/gsd/tests/auto-start-needs-discussion.test.ts +34 -56
  186. package/src/resources/extensions/gsd/tests/auto-worktree-milestone-merge.test.ts +533 -656
  187. package/src/resources/extensions/gsd/tests/auto-worktree.test.ts +165 -143
  188. package/src/resources/extensions/gsd/tests/cache-staleness-regression.test.ts +29 -52
  189. package/src/resources/extensions/gsd/tests/captures.test.ts +148 -176
  190. package/src/resources/extensions/gsd/tests/claude-import-tui.test.ts +32 -33
  191. package/src/resources/extensions/gsd/tests/collect-from-manifest.test.ts +141 -143
  192. package/src/resources/extensions/gsd/tests/commands-inspect-open-db.test.ts +25 -25
  193. package/src/resources/extensions/gsd/tests/commands-logs.test.ts +81 -81
  194. package/src/resources/extensions/gsd/tests/complete-milestone.test.ts +38 -59
  195. package/src/resources/extensions/gsd/tests/complete-slice.test.ts +228 -263
  196. package/src/resources/extensions/gsd/tests/complete-task.test.ts +250 -302
  197. package/src/resources/extensions/gsd/tests/completed-units-metrics-sync.test.ts +114 -0
  198. package/src/resources/extensions/gsd/tests/context-store.test.ts +354 -367
  199. package/src/resources/extensions/gsd/tests/continue-here.test.ts +68 -72
  200. package/src/resources/extensions/gsd/tests/cost-projection.test.ts +92 -106
  201. package/src/resources/extensions/gsd/tests/crash-recovery.test.ts +27 -35
  202. package/src/resources/extensions/gsd/tests/dashboard-budget.test.ts +220 -237
  203. package/src/resources/extensions/gsd/tests/db-writer.test.ts +465 -416
  204. package/src/resources/extensions/gsd/tests/definition-loader.test.ts +76 -92
  205. package/src/resources/extensions/gsd/tests/derive-state-crossval.test.ts +68 -83
  206. package/src/resources/extensions/gsd/tests/derive-state-db.test.ts +210 -181
  207. package/src/resources/extensions/gsd/tests/derive-state-deps.test.ts +78 -101
  208. package/src/resources/extensions/gsd/tests/derive-state.test.ts +192 -227
  209. package/src/resources/extensions/gsd/tests/detection.test.ts +232 -278
  210. package/src/resources/extensions/gsd/tests/dev-engine-wrapper.test.ts +30 -34
  211. package/src/resources/extensions/gsd/tests/dispatch-guard.test.ts +164 -180
  212. package/src/resources/extensions/gsd/tests/dispatch-missing-task-plans.test.ts +43 -49
  213. package/src/resources/extensions/gsd/tests/dispatch-uat-last-completed.test.ts +28 -32
  214. package/src/resources/extensions/gsd/tests/doctor-completion-deferral.test.ts +27 -29
  215. package/src/resources/extensions/gsd/tests/doctor-delimiter-fix.test.ts +34 -38
  216. package/src/resources/extensions/gsd/tests/doctor-enhancements.test.ts +54 -75
  217. package/src/resources/extensions/gsd/tests/doctor-environment-worktree.test.ts +21 -32
  218. package/src/resources/extensions/gsd/tests/doctor-environment.test.ts +72 -97
  219. package/src/resources/extensions/gsd/tests/doctor-fixlevel.test.ts +38 -44
  220. package/src/resources/extensions/gsd/tests/doctor-git.test.ts +104 -145
  221. package/src/resources/extensions/gsd/tests/doctor-proactive.test.ts +84 -106
  222. package/src/resources/extensions/gsd/tests/doctor-roadmap-summary-atomicity.test.ts +54 -60
  223. package/src/resources/extensions/gsd/tests/doctor-runtime.test.ts +72 -93
  224. package/src/resources/extensions/gsd/tests/doctor.test.ts +104 -134
  225. package/src/resources/extensions/gsd/tests/ensure-db-open.test.ts +123 -131
  226. package/src/resources/extensions/gsd/tests/est-annotation-timeout.test.ts +120 -0
  227. package/src/resources/extensions/gsd/tests/exit-command.test.ts +20 -24
  228. package/src/resources/extensions/gsd/tests/feature-branch-lifecycle-integration.test.ts +48 -57
  229. package/src/resources/extensions/gsd/tests/files-loadfile-eisdir.test.ts +5 -7
  230. package/src/resources/extensions/gsd/tests/flag-file-db.test.ts +30 -42
  231. package/src/resources/extensions/gsd/tests/freeform-decisions.test.ts +198 -206
  232. package/src/resources/extensions/gsd/tests/git-locale.test.ts +13 -27
  233. package/src/resources/extensions/gsd/tests/git-service.test.ts +285 -388
  234. package/src/resources/extensions/gsd/tests/gitignore-tracked-gsd.test.ts +31 -39
  235. package/src/resources/extensions/gsd/tests/graph-operations.test.ts +63 -69
  236. package/src/resources/extensions/gsd/tests/gsd-db.test.ts +255 -264
  237. package/src/resources/extensions/gsd/tests/gsd-inspect.test.ts +108 -119
  238. package/src/resources/extensions/gsd/tests/gsd-recover.test.ts +81 -103
  239. package/src/resources/extensions/gsd/tests/gsd-tools.test.ts +229 -262
  240. package/src/resources/extensions/gsd/tests/headless-answers.test.ts +13 -13
  241. package/src/resources/extensions/gsd/tests/health-widget.test.ts +29 -37
  242. package/src/resources/extensions/gsd/tests/idle-recovery.test.ts +81 -102
  243. package/src/resources/extensions/gsd/tests/infra-error.test.ts +20 -2
  244. package/src/resources/extensions/gsd/tests/init-wizard.test.ts +16 -18
  245. package/src/resources/extensions/gsd/tests/integration-edge.test.ts +41 -46
  246. package/src/resources/extensions/gsd/tests/integration-lifecycle.test.ts +42 -53
  247. package/src/resources/extensions/gsd/tests/integration-mixed-milestones.test.ts +75 -91
  248. package/src/resources/extensions/gsd/tests/integration-proof.test.ts +18 -18
  249. package/src/resources/extensions/gsd/tests/knowledge.test.ts +89 -0
  250. package/src/resources/extensions/gsd/tests/markdown-renderer.test.ts +150 -194
  251. package/src/resources/extensions/gsd/tests/mcp-status.test.ts +103 -0
  252. package/src/resources/extensions/gsd/tests/md-importer.test.ts +101 -125
  253. package/src/resources/extensions/gsd/tests/memory-extractor.test.ts +45 -54
  254. package/src/resources/extensions/gsd/tests/memory-store.test.ts +80 -93
  255. package/src/resources/extensions/gsd/tests/merge-conflict-stops-loop.test.ts +66 -0
  256. package/src/resources/extensions/gsd/tests/migrate-command.test.ts +57 -66
  257. package/src/resources/extensions/gsd/tests/migrate-hierarchy.test.ts +83 -93
  258. package/src/resources/extensions/gsd/tests/migrate-parser.test.ts +161 -170
  259. package/src/resources/extensions/gsd/tests/migrate-transformer.test.ts +125 -141
  260. package/src/resources/extensions/gsd/tests/migrate-validator-parsers.test.ts +107 -131
  261. package/src/resources/extensions/gsd/tests/migrate-writer-integration.test.ts +87 -96
  262. package/src/resources/extensions/gsd/tests/migrate-writer.test.ts +125 -164
  263. package/src/resources/extensions/gsd/tests/must-have-parser.test.ts +81 -94
  264. package/src/resources/extensions/gsd/tests/none-mode-gates.test.ts +35 -36
  265. package/src/resources/extensions/gsd/tests/overrides.test.ts +99 -106
  266. package/src/resources/extensions/gsd/tests/parallel-crash-recovery.test.ts +40 -47
  267. package/src/resources/extensions/gsd/tests/parallel-worker-monitoring.test.ts +25 -28
  268. package/src/resources/extensions/gsd/tests/parallel-workers-multi-milestone-e2e.test.ts +66 -83
  269. package/src/resources/extensions/gsd/tests/park-edge-cases.test.ts +54 -77
  270. package/src/resources/extensions/gsd/tests/park-milestone.test.ts +68 -115
  271. package/src/resources/extensions/gsd/tests/parsers.test.ts +546 -611
  272. package/src/resources/extensions/gsd/tests/paths.test.ts +72 -87
  273. package/src/resources/extensions/gsd/tests/post-unit-hooks.test.ts +77 -117
  274. package/src/resources/extensions/gsd/tests/preferences.test.ts +27 -0
  275. package/src/resources/extensions/gsd/tests/prompt-contracts.test.ts +11 -7
  276. package/src/resources/extensions/gsd/tests/prompt-db.test.ts +56 -56
  277. package/src/resources/extensions/gsd/tests/queue-draft-detection.test.ts +93 -119
  278. package/src/resources/extensions/gsd/tests/queue-order.test.ts +70 -82
  279. package/src/resources/extensions/gsd/tests/queue-reorder-e2e.test.ts +42 -55
  280. package/src/resources/extensions/gsd/tests/quick-auto-guard.test.ts +100 -0
  281. package/src/resources/extensions/gsd/tests/quick-branch-lifecycle.test.ts +45 -73
  282. package/src/resources/extensions/gsd/tests/reassess-prompt.test.ts +28 -38
  283. package/src/resources/extensions/gsd/tests/replan-slice.test.ts +73 -80
  284. package/src/resources/extensions/gsd/tests/repo-identity-worktree.test.ts +71 -74
  285. package/src/resources/extensions/gsd/tests/requirements.test.ts +70 -75
  286. package/src/resources/extensions/gsd/tests/retry-state-reset.test.ts +44 -66
  287. package/src/resources/extensions/gsd/tests/roadmap-parse-regression.test.ts +114 -181
  288. package/src/resources/extensions/gsd/tests/rule-registry.test.ts +63 -65
  289. package/src/resources/extensions/gsd/tests/run-uat.test.ts +66 -128
  290. package/src/resources/extensions/gsd/tests/session-lock-multipath.test.ts +18 -25
  291. package/src/resources/extensions/gsd/tests/session-lock-regression.test.ts +37 -44
  292. package/src/resources/extensions/gsd/tests/shared-wal.test.ts +19 -26
  293. package/src/resources/extensions/gsd/tests/sqlite-unavailable-gate.test.ts +63 -0
  294. package/src/resources/extensions/gsd/tests/stalled-tool-recovery.test.ts +6 -8
  295. package/src/resources/extensions/gsd/tests/stop-auto-merge-back.test.ts +67 -0
  296. package/src/resources/extensions/gsd/tests/symlink-numbered-variants.test.ts +22 -28
  297. package/src/resources/extensions/gsd/tests/terminated-transient.test.ts +49 -0
  298. package/src/resources/extensions/gsd/tests/token-savings.test.ts +54 -56
  299. package/src/resources/extensions/gsd/tests/tool-call-loop-guard.test.ts +23 -25
  300. package/src/resources/extensions/gsd/tests/tool-naming.test.ts +10 -11
  301. package/src/resources/extensions/gsd/tests/unique-milestone-ids.test.ts +66 -82
  302. package/src/resources/extensions/gsd/tests/unit-runtime.test.ts +46 -47
  303. package/src/resources/extensions/gsd/tests/visualizer-critical-path.test.ts +20 -22
  304. package/src/resources/extensions/gsd/tests/visualizer-data.test.ts +84 -86
  305. package/src/resources/extensions/gsd/tests/visualizer-overlay.test.ts +41 -43
  306. package/src/resources/extensions/gsd/tests/visualizer-views.test.ts +94 -96
  307. package/src/resources/extensions/gsd/tests/windows-path-normalization.test.ts +11 -13
  308. package/src/resources/extensions/gsd/tests/worker-registry.test.ts +27 -29
  309. package/src/resources/extensions/gsd/tests/workflow-templates.test.ts +50 -52
  310. package/src/resources/extensions/gsd/tests/worktree-bugfix.test.ts +10 -13
  311. package/src/resources/extensions/gsd/tests/worktree-db-integration.test.ts +14 -18
  312. package/src/resources/extensions/gsd/tests/worktree-db.test.ts +38 -39
  313. package/src/resources/extensions/gsd/tests/worktree-e2e.test.ts +17 -21
  314. package/src/resources/extensions/gsd/tests/worktree-health.test.ts +25 -30
  315. package/src/resources/extensions/gsd/tests/worktree-integration.test.ts +30 -37
  316. package/src/resources/extensions/gsd/tests/worktree-symlink-removal.test.ts +15 -22
  317. package/src/resources/extensions/gsd/tests/worktree-sync-milestones.test.ts +59 -66
  318. package/src/resources/extensions/gsd/tests/worktree.test.ts +44 -50
  319. package/src/resources/extensions/gsd/tools/plan-slice.ts +2 -0
  320. package/src/resources/extensions/gsd/tools/plan-task.ts +2 -0
  321. package/src/resources/extensions/gsd/tools/replan-slice.ts +3 -0
  322. package/src/resources/extensions/gsd/tools/validate-milestone.ts +127 -0
  323. package/src/resources/extensions/gsd/worktree-resolver.ts +7 -0
  324. package/src/resources/extensions/mcp-client/index.ts +20 -0
  325. /package/dist/web/standalone/.next/static/{fOnWQBjWXMKUs4bqTg530 → kxxAA66bah_yhPYqLBHE2}/_buildManifest.js +0 -0
  326. /package/dist/web/standalone/.next/static/{fOnWQBjWXMKUs4bqTg530 → kxxAA66bah_yhPYqLBHE2}/_ssgManifest.js +0 -0
@@ -63,35 +63,33 @@ steps:
63
63
 
64
64
  // ─── loadDefinition: valid YAML ──────────────────────────────────────────
65
65
 
66
- test("loadDefinition: valid 3-step YAML returns correct structure", () => {
66
+ test("loadDefinition: valid 3-step YAML returns correct structure", (t) => {
67
67
  const dir = writeDefYaml(VALID_3STEP_YAML);
68
- try {
69
- const def = loadDefinition(dir, "test-workflow");
70
-
71
- assert.equal(def.version, 1);
72
- assert.equal(def.name, "test-workflow");
73
- assert.equal(def.description, "A test workflow");
74
- assert.deepEqual(def.params, { topic: "AI" });
75
- assert.equal(def.steps.length, 3);
76
-
77
- // Step 1: research
78
- assert.equal(def.steps[0].id, "research");
79
- assert.equal(def.steps[0].name, "Research the topic");
80
- assert.equal(def.steps[0].prompt, "Research {{topic}} and write findings to research.md");
81
- assert.deepEqual(def.steps[0].requires, []);
82
- assert.deepEqual(def.steps[0].produces, ["research.md"]);
83
-
84
- // Step 2: outline — depends on research
85
- assert.equal(def.steps[1].id, "outline");
86
- assert.deepEqual(def.steps[1].requires, ["research"]);
87
-
88
- // Step 3: draft — depends on outline
89
- assert.equal(def.steps[2].id, "draft");
90
- assert.deepEqual(def.steps[2].requires, ["outline"]);
91
- assert.deepEqual(def.steps[2].produces, ["draft.md"]);
92
- } finally {
93
- try { rmSync(dir, { recursive: true, force: true, maxRetries: 3, retryDelay: 100 }); } catch { /* Windows EPERM */ }
94
- }
68
+ t.after(() => { try { rmSync(dir, { recursive: true, force: true, maxRetries: 3, retryDelay: 100 }); } catch { /* Windows EPERM */ } });
69
+
70
+ const def = loadDefinition(dir, "test-workflow");
71
+
72
+ assert.equal(def.version, 1);
73
+ assert.equal(def.name, "test-workflow");
74
+ assert.equal(def.description, "A test workflow");
75
+ assert.deepEqual(def.params, { topic: "AI" });
76
+ assert.equal(def.steps.length, 3);
77
+
78
+ // Step 1: research
79
+ assert.equal(def.steps[0].id, "research");
80
+ assert.equal(def.steps[0].name, "Research the topic");
81
+ assert.equal(def.steps[0].prompt, "Research {{topic}} and write findings to research.md");
82
+ assert.deepEqual(def.steps[0].requires, []);
83
+ assert.deepEqual(def.steps[0].produces, ["research.md"]);
84
+
85
+ // Step 2: outline — depends on research
86
+ assert.equal(def.steps[1].id, "outline");
87
+ assert.deepEqual(def.steps[1].requires, ["research"]);
88
+
89
+ // Step 3: draft — depends on outline
90
+ assert.equal(def.steps[2].id, "draft");
91
+ assert.deepEqual(def.steps[2].requires, ["outline"]);
92
+ assert.deepEqual(def.steps[2].produces, ["draft.md"]);
95
93
  });
96
94
 
97
95
  // ─── validateDefinition: rejection cases ─────────────────────────────────
@@ -223,23 +221,21 @@ test("validateDefinition: missing step name → error", () => {
223
221
 
224
222
  // ─── loadDefinition: error cases ─────────────────────────────────────────
225
223
 
226
- test("loadDefinition: missing file → descriptive error", () => {
224
+ test("loadDefinition: missing file → descriptive error", (t) => {
227
225
  const dir = makeTmpDir();
228
- try {
229
- assert.throws(
230
- () => loadDefinition(dir, "nonexistent"),
231
- (err: Error) => {
232
- assert.ok(err.message.includes("not found"));
233
- assert.ok(err.message.includes("nonexistent.yaml"));
234
- return true;
235
- },
236
- );
237
- } finally {
238
- try { rmSync(dir, { recursive: true, force: true, maxRetries: 3, retryDelay: 100 }); } catch { /* Windows EPERM */ }
239
- }
240
- });
241
-
242
- test("loadDefinition: invalid YAML schema → descriptive error", () => {
226
+ t.after(() => { try { rmSync(dir, { recursive: true, force: true, maxRetries: 3, retryDelay: 100 }); } catch { /* Windows EPERM */ } });
227
+
228
+ assert.throws(
229
+ () => loadDefinition(dir, "nonexistent"),
230
+ (err: Error) => {
231
+ assert.ok(err.message.includes("not found"));
232
+ assert.ok(err.message.includes("nonexistent.yaml"));
233
+ return true;
234
+ },
235
+ );
236
+ });
237
+
238
+ test("loadDefinition: invalid YAML schema → descriptive error", (t) => {
243
239
  const dir = writeDefYaml(`
244
240
  version: 2
245
241
  name: "bad"
@@ -248,23 +244,21 @@ steps:
248
244
  name: "A"
249
245
  prompt: "do A"
250
246
  `);
251
- try {
252
- assert.throws(
253
- () => loadDefinition(dir, "test-workflow"),
254
- (err: Error) => {
255
- assert.ok(err.message.includes("Invalid workflow definition"));
256
- assert.ok(err.message.includes("Unsupported version"));
257
- return true;
258
- },
259
- );
260
- } finally {
261
- try { rmSync(dir, { recursive: true, force: true, maxRetries: 3, retryDelay: 100 }); } catch { /* Windows EPERM */ }
262
- }
247
+ t.after(() => { try { rmSync(dir, { recursive: true, force: true, maxRetries: 3, retryDelay: 100 }); } catch { /* Windows EPERM */ } });
248
+
249
+ assert.throws(
250
+ () => loadDefinition(dir, "test-workflow"),
251
+ (err: Error) => {
252
+ assert.ok(err.message.includes("Invalid workflow definition"));
253
+ assert.ok(err.message.includes("Unsupported version"));
254
+ return true;
255
+ },
256
+ );
263
257
  });
264
258
 
265
259
  // ─── loadDefinition: snake_case → camelCase conversion ───────────────────
266
260
 
267
- test("loadDefinition: depends_on in YAML maps to requires in TypeScript", () => {
261
+ test("loadDefinition: depends_on in YAML maps to requires in TypeScript", (t) => {
268
262
  const dir = writeDefYaml(`
269
263
  version: 1
270
264
  name: "dep-test"
@@ -277,15 +271,13 @@ steps:
277
271
  prompt: "do second"
278
272
  depends_on: [first]
279
273
  `);
280
- try {
281
- const def = loadDefinition(dir, "test-workflow");
282
- assert.deepEqual(def.steps[1].requires, ["first"]);
283
- } finally {
284
- try { rmSync(dir, { recursive: true, force: true, maxRetries: 3, retryDelay: 100 }); } catch { /* Windows EPERM */ }
285
- }
274
+ t.after(() => { try { rmSync(dir, { recursive: true, force: true, maxRetries: 3, retryDelay: 100 }); } catch { /* Windows EPERM */ } });
275
+
276
+ const def = loadDefinition(dir, "test-workflow");
277
+ assert.deepEqual(def.steps[1].requires, ["first"]);
286
278
  });
287
279
 
288
- test("loadDefinition: context_from in YAML maps to contextFrom in TypeScript", () => {
280
+ test("loadDefinition: context_from in YAML maps to contextFrom in TypeScript", (t) => {
289
281
  const dir = writeDefYaml(`
290
282
  version: 1
291
283
  name: "ctx-test"
@@ -298,12 +290,10 @@ steps:
298
290
  prompt: "do second"
299
291
  context_from: [first]
300
292
  `);
301
- try {
302
- const def = loadDefinition(dir, "test-workflow");
303
- assert.deepEqual(def.steps[1].contextFrom, ["first"]);
304
- } finally {
305
- try { rmSync(dir, { recursive: true, force: true, maxRetries: 3, retryDelay: 100 }); } catch { /* Windows EPERM */ }
306
- }
293
+ t.after(() => { try { rmSync(dir, { recursive: true, force: true, maxRetries: 3, retryDelay: 100 }); } catch { /* Windows EPERM */ } });
294
+
295
+ const def = loadDefinition(dir, "test-workflow");
296
+ assert.deepEqual(def.steps[1].contextFrom, ["first"]);
307
297
  });
308
298
 
309
299
  // ─── validateDefinition: iterate field validation ────────────────────────
@@ -725,7 +715,7 @@ test("validateDefinition: valid minimal step (no requires/produces) → accepted
725
715
  assert.equal(result.errors.length, 0);
726
716
  });
727
717
 
728
- test("loadDefinition: loads without params field → params is undefined", () => {
718
+ test("loadDefinition: loads without params field → params is undefined", (t) => {
729
719
  const dir = writeDefYaml(`
730
720
  version: 1
731
721
  name: "no-params"
@@ -734,15 +724,13 @@ steps:
734
724
  name: "A"
735
725
  prompt: "do A"
736
726
  `);
737
- try {
738
- const def = loadDefinition(dir, "test-workflow");
739
- assert.equal(def.params, undefined);
740
- } finally {
741
- try { rmSync(dir, { recursive: true, force: true, maxRetries: 3, retryDelay: 100 }); } catch { /* Windows EPERM */ }
742
- }
727
+ t.after(() => { try { rmSync(dir, { recursive: true, force: true, maxRetries: 3, retryDelay: 100 }); } catch { /* Windows EPERM */ } });
728
+
729
+ const def = loadDefinition(dir, "test-workflow");
730
+ assert.equal(def.params, undefined);
743
731
  });
744
732
 
745
- test("loadDefinition: loads without description → description is undefined", () => {
733
+ test("loadDefinition: loads without description → description is undefined", (t) => {
746
734
  const dir = writeDefYaml(`
747
735
  version: 1
748
736
  name: "no-desc"
@@ -751,15 +739,13 @@ steps:
751
739
  name: "A"
752
740
  prompt: "do A"
753
741
  `);
754
- try {
755
- const def = loadDefinition(dir, "test-workflow");
756
- assert.equal(def.description, undefined);
757
- } finally {
758
- try { rmSync(dir, { recursive: true, force: true, maxRetries: 3, retryDelay: 100 }); } catch { /* Windows EPERM */ }
759
- }
742
+ t.after(() => { try { rmSync(dir, { recursive: true, force: true, maxRetries: 3, retryDelay: 100 }); } catch { /* Windows EPERM */ } });
743
+
744
+ const def = loadDefinition(dir, "test-workflow");
745
+ assert.equal(def.description, undefined);
760
746
  });
761
747
 
762
- test("loadDefinition: step with no requires/produces defaults to empty arrays", () => {
748
+ test("loadDefinition: step with no requires/produces defaults to empty arrays", (t) => {
763
749
  const dir = writeDefYaml(`
764
750
  version: 1
765
751
  name: "defaults"
@@ -768,11 +754,9 @@ steps:
768
754
  name: "A"
769
755
  prompt: "do A"
770
756
  `);
771
- try {
772
- const def = loadDefinition(dir, "test-workflow");
773
- assert.deepEqual(def.steps[0].requires, []);
774
- assert.deepEqual(def.steps[0].produces, []);
775
- } finally {
776
- try { rmSync(dir, { recursive: true, force: true, maxRetries: 3, retryDelay: 100 }); } catch { /* Windows EPERM */ }
777
- }
757
+ t.after(() => { try { rmSync(dir, { recursive: true, force: true, maxRetries: 3, retryDelay: 100 }); } catch { /* Windows EPERM */ } });
758
+
759
+ const def = loadDefinition(dir, "test-workflow");
760
+ assert.deepEqual(def.steps[0].requires, []);
761
+ assert.deepEqual(def.steps[0].produces, []);
778
762
  });
@@ -1,3 +1,5 @@
1
+ import { describe, test } from 'node:test';
2
+ import assert from 'node:assert/strict';
1
3
  // derive-state-crossval.test.ts — Cross-validation: deriveStateFromDb() vs _deriveStateImpl()
2
4
  // Proves both paths produce field-identical GSDState across 7 fixture scenarios,
3
5
  // plus an auto-migration round-trip test.
@@ -19,11 +21,8 @@ import {
19
21
  insertTask,
20
22
  } from '../gsd-db.ts';
21
23
  import { migrateHierarchyToDb } from '../md-importer.ts';
22
- import { createTestContext } from './test-helpers.ts';
23
24
  import type { GSDState } from '../types.ts';
24
25
 
25
- const { assertEq, assertTrue, report } = createTestContext();
26
-
27
26
  // ─── Fixture Helpers ───────────────────────────────────────────────────────
28
27
 
29
28
  function createFixtureBase(): string {
@@ -48,29 +47,29 @@ function cleanup(base: string): void {
48
47
  */
49
48
  function assertStatesEqual(dbState: GSDState, fileState: GSDState, prefix: string): void {
50
49
  // Phase
51
- assertEq(dbState.phase, fileState.phase, `${prefix}: phase`);
50
+ assert.deepStrictEqual(dbState.phase, fileState.phase, `${prefix}: phase`);
52
51
 
53
52
  // Active refs
54
- assertEq(dbState.activeMilestone?.id ?? null, fileState.activeMilestone?.id ?? null, `${prefix}: activeMilestone.id`);
55
- assertEq(dbState.activeMilestone?.title ?? null, fileState.activeMilestone?.title ?? null, `${prefix}: activeMilestone.title`);
56
- assertEq(dbState.activeSlice?.id ?? null, fileState.activeSlice?.id ?? null, `${prefix}: activeSlice.id`);
57
- assertEq(dbState.activeSlice?.title ?? null, fileState.activeSlice?.title ?? null, `${prefix}: activeSlice.title`);
58
- assertEq(dbState.activeTask?.id ?? null, fileState.activeTask?.id ?? null, `${prefix}: activeTask.id`);
59
- assertEq(dbState.activeTask?.title ?? null, fileState.activeTask?.title ?? null, `${prefix}: activeTask.title`);
53
+ assert.deepStrictEqual(dbState.activeMilestone?.id ?? null, fileState.activeMilestone?.id ?? null, `${prefix}: activeMilestone.id`);
54
+ assert.deepStrictEqual(dbState.activeMilestone?.title ?? null, fileState.activeMilestone?.title ?? null, `${prefix}: activeMilestone.title`);
55
+ assert.deepStrictEqual(dbState.activeSlice?.id ?? null, fileState.activeSlice?.id ?? null, `${prefix}: activeSlice.id`);
56
+ assert.deepStrictEqual(dbState.activeSlice?.title ?? null, fileState.activeSlice?.title ?? null, `${prefix}: activeSlice.title`);
57
+ assert.deepStrictEqual(dbState.activeTask?.id ?? null, fileState.activeTask?.id ?? null, `${prefix}: activeTask.id`);
58
+ assert.deepStrictEqual(dbState.activeTask?.title ?? null, fileState.activeTask?.title ?? null, `${prefix}: activeTask.title`);
60
59
 
61
60
  // Blockers
62
- assertEq(dbState.blockers.length, fileState.blockers.length, `${prefix}: blockers.length`);
61
+ assert.deepStrictEqual(dbState.blockers.length, fileState.blockers.length, `${prefix}: blockers.length`);
63
62
 
64
63
  // Next action (may differ in wording between paths — compare presence)
65
- assertTrue(typeof dbState.nextAction === 'string', `${prefix}: nextAction is string`);
64
+ assert.ok(typeof dbState.nextAction === 'string', `${prefix}: nextAction is string`);
66
65
 
67
66
  // Registry — length and each entry
68
- assertEq(dbState.registry.length, fileState.registry.length, `${prefix}: registry.length`);
67
+ assert.deepStrictEqual(dbState.registry.length, fileState.registry.length, `${prefix}: registry.length`);
69
68
  for (let i = 0; i < fileState.registry.length; i++) {
70
- assertEq(dbState.registry[i]?.id, fileState.registry[i]?.id, `${prefix}: registry[${i}].id`);
71
- assertEq(dbState.registry[i]?.status, fileState.registry[i]?.status, `${prefix}: registry[${i}].status`);
69
+ assert.deepStrictEqual(dbState.registry[i]?.id, fileState.registry[i]?.id, `${prefix}: registry[${i}].id`);
70
+ assert.deepStrictEqual(dbState.registry[i]?.status, fileState.registry[i]?.status, `${prefix}: registry[${i}].status`);
72
71
  // dependsOn may or may not be present
73
- assertEq(
72
+ assert.deepStrictEqual(
74
73
  JSON.stringify(dbState.registry[i]?.dependsOn ?? []),
75
74
  JSON.stringify(fileState.registry[i]?.dependsOn ?? []),
76
75
  `${prefix}: registry[${i}].dependsOn`,
@@ -78,28 +77,27 @@ function assertStatesEqual(dbState: GSDState, fileState: GSDState, prefix: strin
78
77
  }
79
78
 
80
79
  // Requirements
81
- assertEq(dbState.requirements?.active ?? 0, fileState.requirements?.active ?? 0, `${prefix}: requirements.active`);
82
- assertEq(dbState.requirements?.validated ?? 0, fileState.requirements?.validated ?? 0, `${prefix}: requirements.validated`);
83
- assertEq(dbState.requirements?.total ?? 0, fileState.requirements?.total ?? 0, `${prefix}: requirements.total`);
80
+ assert.deepStrictEqual(dbState.requirements?.active ?? 0, fileState.requirements?.active ?? 0, `${prefix}: requirements.active`);
81
+ assert.deepStrictEqual(dbState.requirements?.validated ?? 0, fileState.requirements?.validated ?? 0, `${prefix}: requirements.validated`);
82
+ assert.deepStrictEqual(dbState.requirements?.total ?? 0, fileState.requirements?.total ?? 0, `${prefix}: requirements.total`);
84
83
 
85
84
  // Progress
86
- assertEq(dbState.progress?.milestones?.done, fileState.progress?.milestones?.done, `${prefix}: progress.milestones.done`);
87
- assertEq(dbState.progress?.milestones?.total, fileState.progress?.milestones?.total, `${prefix}: progress.milestones.total`);
88
- assertEq(dbState.progress?.slices?.done ?? 0, fileState.progress?.slices?.done ?? 0, `${prefix}: progress.slices.done`);
89
- assertEq(dbState.progress?.slices?.total ?? 0, fileState.progress?.slices?.total ?? 0, `${prefix}: progress.slices.total`);
90
- assertEq(dbState.progress?.tasks?.done ?? 0, fileState.progress?.tasks?.done ?? 0, `${prefix}: progress.tasks.done`);
91
- assertEq(dbState.progress?.tasks?.total ?? 0, fileState.progress?.tasks?.total ?? 0, `${prefix}: progress.tasks.total`);
85
+ assert.deepStrictEqual(dbState.progress?.milestones?.done, fileState.progress?.milestones?.done, `${prefix}: progress.milestones.done`);
86
+ assert.deepStrictEqual(dbState.progress?.milestones?.total, fileState.progress?.milestones?.total, `${prefix}: progress.milestones.total`);
87
+ assert.deepStrictEqual(dbState.progress?.slices?.done ?? 0, fileState.progress?.slices?.done ?? 0, `${prefix}: progress.slices.done`);
88
+ assert.deepStrictEqual(dbState.progress?.slices?.total ?? 0, fileState.progress?.slices?.total ?? 0, `${prefix}: progress.slices.total`);
89
+ assert.deepStrictEqual(dbState.progress?.tasks?.done ?? 0, fileState.progress?.tasks?.done ?? 0, `${prefix}: progress.tasks.done`);
90
+ assert.deepStrictEqual(dbState.progress?.tasks?.total ?? 0, fileState.progress?.tasks?.total ?? 0, `${prefix}: progress.tasks.total`);
92
91
  }
93
92
 
94
93
  // ═══════════════════════════════════════════════════════════════════════════
95
94
  // Scenario fixtures
96
95
  // ═══════════════════════════════════════════════════════════════════════════
97
96
 
98
- async function main(): Promise<void> {
97
+ describe('derive-state-crossval', async () => {
99
98
 
100
99
  // ─── Scenario A: Pre-planning — milestone with CONTEXT but no roadmap ──
101
- console.log('\n=== crossval A: pre-planning ===');
102
- {
100
+ test('crossval A: pre-planning', async () => {
103
101
  const base = createFixtureBase();
104
102
  try {
105
103
  writeFile(base, 'milestones/M001/M001-CONTEXT.md', '# M001: New Project\n\nWe are exploring scope.');
@@ -116,18 +114,17 @@ async function main(): Promise<void> {
116
114
  const dbState = await deriveStateFromDb(base);
117
115
 
118
116
  assertStatesEqual(dbState, fileState, 'A-preplan');
119
- assertEq(dbState.phase, 'pre-planning', 'A-preplan: phase is pre-planning');
117
+ assert.deepStrictEqual(dbState.phase, 'pre-planning', 'A-preplan: phase is pre-planning');
120
118
 
121
119
  closeDatabase();
122
120
  } finally {
123
121
  closeDatabase();
124
122
  cleanup(base);
125
123
  }
126
- }
124
+ });
127
125
 
128
126
  // ─── Scenario B: Executing — 2 slices, first complete, second active ──
129
- console.log('\n=== crossval B: executing ===');
130
- {
127
+ test('crossval B: executing', async () => {
131
128
  const base = createFixtureBase();
132
129
  try {
133
130
  const roadmap = `# M001: Test Project
@@ -182,20 +179,19 @@ skills_used: []
182
179
  const dbState = await deriveStateFromDb(base);
183
180
 
184
181
  assertStatesEqual(dbState, fileState, 'B-executing');
185
- assertEq(dbState.phase, 'executing', 'B-executing: phase is executing');
186
- assertEq(dbState.activeSlice?.id, 'S02', 'B-executing: activeSlice is S02');
187
- assertEq(dbState.activeTask?.id, 'T02', 'B-executing: activeTask is T02');
182
+ assert.deepStrictEqual(dbState.phase, 'executing', 'B-executing: phase is executing');
183
+ assert.deepStrictEqual(dbState.activeSlice?.id, 'S02', 'B-executing: activeSlice is S02');
184
+ assert.deepStrictEqual(dbState.activeTask?.id, 'T02', 'B-executing: activeTask is T02');
188
185
 
189
186
  closeDatabase();
190
187
  } finally {
191
188
  closeDatabase();
192
189
  cleanup(base);
193
190
  }
194
- }
191
+ });
195
192
 
196
193
  // ─── Scenario C: Summarizing — all tasks done, no slice summary ────────
197
- console.log('\n=== crossval C: summarizing ===');
198
- {
194
+ test('crossval C: summarizing', async () => {
199
195
  const base = createFixtureBase();
200
196
  try {
201
197
  const roadmap = `# M001: Summarize Test
@@ -245,20 +241,19 @@ skills_used: []
245
241
  const dbState = await deriveStateFromDb(base);
246
242
 
247
243
  assertStatesEqual(dbState, fileState, 'C-summarizing');
248
- assertEq(dbState.phase, 'summarizing', 'C-summarizing: phase is summarizing');
249
- assertEq(dbState.activeSlice?.id, 'S01', 'C-summarizing: activeSlice is S01');
250
- assertEq(dbState.activeTask, null, 'C-summarizing: no activeTask');
244
+ assert.deepStrictEqual(dbState.phase, 'summarizing', 'C-summarizing: phase is summarizing');
245
+ assert.deepStrictEqual(dbState.activeSlice?.id, 'S01', 'C-summarizing: activeSlice is S01');
246
+ assert.deepStrictEqual(dbState.activeTask, null, 'C-summarizing: no activeTask');
251
247
 
252
248
  closeDatabase();
253
249
  } finally {
254
250
  closeDatabase();
255
251
  cleanup(base);
256
252
  }
257
- }
253
+ });
258
254
 
259
255
  // ─── Scenario D: Multi-milestone — M001 complete, M002 active ─────────
260
- console.log('\n=== crossval D: multi-milestone ===');
261
- {
256
+ test('crossval D: multi-milestone', async () => {
262
257
  const base = createFixtureBase();
263
258
  try {
264
259
  const m1Roadmap = `# M001: First Milestone
@@ -313,24 +308,23 @@ skills_used: []
313
308
  const dbState = await deriveStateFromDb(base);
314
309
 
315
310
  assertStatesEqual(dbState, fileState, 'D-multims');
316
- assertEq(dbState.activeMilestone?.id, 'M002', 'D-multims: activeMilestone is M002');
317
- assertEq(dbState.registry.length, 2, 'D-multims: 2 milestones in registry');
311
+ assert.deepStrictEqual(dbState.activeMilestone?.id, 'M002', 'D-multims: activeMilestone is M002');
312
+ assert.deepStrictEqual(dbState.registry.length, 2, 'D-multims: 2 milestones in registry');
318
313
 
319
314
  const m1 = dbState.registry.find(e => e.id === 'M001');
320
315
  const m2 = dbState.registry.find(e => e.id === 'M002');
321
- assertEq(m1?.status, 'complete', 'D-multims: M001 complete');
322
- assertEq(m2?.status, 'active', 'D-multims: M002 active');
316
+ assert.deepStrictEqual(m1?.status, 'complete', 'D-multims: M001 complete');
317
+ assert.deepStrictEqual(m2?.status, 'active', 'D-multims: M002 active');
323
318
 
324
319
  closeDatabase();
325
320
  } finally {
326
321
  closeDatabase();
327
322
  cleanup(base);
328
323
  }
329
- }
324
+ });
330
325
 
331
326
  // ─── Scenario E: Blocked — circular slice deps ────────────────────────
332
- console.log('\n=== crossval E: blocked ===');
333
- {
327
+ test('crossval E: blocked', async () => {
334
328
  const base = createFixtureBase();
335
329
  try {
336
330
  const roadmap = `# M001: Blocked Test
@@ -357,19 +351,18 @@ skills_used: []
357
351
  const dbState = await deriveStateFromDb(base);
358
352
 
359
353
  assertStatesEqual(dbState, fileState, 'E-blocked');
360
- assertEq(dbState.phase, 'blocked', 'E-blocked: phase is blocked');
361
- assertTrue(dbState.blockers.length > 0, 'E-blocked: has blockers');
354
+ assert.deepStrictEqual(dbState.phase, 'blocked', 'E-blocked: phase is blocked');
355
+ assert.ok(dbState.blockers.length > 0, 'E-blocked: has blockers');
362
356
 
363
357
  closeDatabase();
364
358
  } finally {
365
359
  closeDatabase();
366
360
  cleanup(base);
367
361
  }
368
- }
362
+ });
369
363
 
370
364
  // ─── Scenario F: Parked — PARKED file on milestone ────────────────────
371
- console.log('\n=== crossval F: parked ===');
372
- {
365
+ test('crossval F: parked', async () => {
373
366
  const base = createFixtureBase();
374
367
  try {
375
368
  const roadmap = `# M001: Parked Milestone
@@ -396,20 +389,19 @@ skills_used: []
396
389
  const dbState = await deriveStateFromDb(base);
397
390
 
398
391
  assertStatesEqual(dbState, fileState, 'F-parked');
399
- assertEq(dbState.activeMilestone?.id, 'M002', 'F-parked: activeMilestone is M002');
400
- assertTrue(dbState.registry.some(e => e.id === 'M001' && e.status === 'parked'), 'F-parked: M001 parked');
392
+ assert.deepStrictEqual(dbState.activeMilestone?.id, 'M002', 'F-parked: activeMilestone is M002');
393
+ assert.ok(dbState.registry.some(e => e.id === 'M001' && e.status === 'parked'), 'F-parked: M001 parked');
401
394
 
402
395
  closeDatabase();
403
396
  } finally {
404
397
  closeDatabase();
405
398
  cleanup(base);
406
399
  }
407
- }
400
+ });
408
401
 
409
402
  // ─── Scenario G: Auto-migration round-trip ────────────────────────────
410
403
  // Create a markdown-only fixture (no DB). Migrate to DB. Both paths identical.
411
- console.log('\n=== crossval G: auto-migration round-trip ===');
412
- {
404
+ test('crossval G: auto-migration round-trip', async () => {
413
405
  const base = createFixtureBase();
414
406
  try {
415
407
  const roadmap = `# M001: Migration Test
@@ -489,9 +481,9 @@ skills_used: []
489
481
  const counts = migrateHierarchyToDb(base);
490
482
 
491
483
  // Verify migration populated correctly
492
- assertTrue(counts.milestones >= 1, 'G-roundtrip: migrated milestones');
493
- assertTrue(counts.slices >= 2, 'G-roundtrip: migrated slices');
494
- assertTrue(counts.tasks >= 3, 'G-roundtrip: migrated tasks');
484
+ assert.ok(counts.milestones >= 1, 'G-roundtrip: migrated milestones');
485
+ assert.ok(counts.slices >= 2, 'G-roundtrip: migrated slices');
486
+ assert.ok(counts.tasks >= 3, 'G-roundtrip: migrated tasks');
495
487
 
496
488
  // Step 3: Get DB-backed state
497
489
  invalidateStateCache();
@@ -499,29 +491,22 @@ skills_used: []
499
491
 
500
492
  // Step 4: Deep cross-validation
501
493
  assertStatesEqual(dbState, fileState, 'G-roundtrip');
502
- assertEq(dbState.phase, 'executing', 'G-roundtrip: phase is executing');
503
- assertEq(dbState.activeSlice?.id, 'S02', 'G-roundtrip: activeSlice is S02');
504
- assertEq(dbState.activeTask?.id, 'T02', 'G-roundtrip: activeTask is T02');
505
- assertEq(dbState.requirements?.active, 1, 'G-roundtrip: requirements.active = 1');
506
- assertEq(dbState.requirements?.validated, 1, 'G-roundtrip: requirements.validated = 1');
507
- assertEq(dbState.requirements?.deferred, 1, 'G-roundtrip: requirements.deferred = 1');
508
- assertEq(dbState.requirements?.total, 3, 'G-roundtrip: requirements.total = 3');
509
- assertEq(dbState.progress?.slices?.done, 1, 'G-roundtrip: slices.done = 1');
510
- assertEq(dbState.progress?.slices?.total, 3, 'G-roundtrip: slices.total = 3');
511
- assertEq(dbState.progress?.tasks?.done, 1, 'G-roundtrip: tasks.done = 1');
512
- assertEq(dbState.progress?.tasks?.total, 3, 'G-roundtrip: tasks.total = 3');
494
+ assert.deepStrictEqual(dbState.phase, 'executing', 'G-roundtrip: phase is executing');
495
+ assert.deepStrictEqual(dbState.activeSlice?.id, 'S02', 'G-roundtrip: activeSlice is S02');
496
+ assert.deepStrictEqual(dbState.activeTask?.id, 'T02', 'G-roundtrip: activeTask is T02');
497
+ assert.deepStrictEqual(dbState.requirements?.active, 1, 'G-roundtrip: requirements.active = 1');
498
+ assert.deepStrictEqual(dbState.requirements?.validated, 1, 'G-roundtrip: requirements.validated = 1');
499
+ assert.deepStrictEqual(dbState.requirements?.deferred, 1, 'G-roundtrip: requirements.deferred = 1');
500
+ assert.deepStrictEqual(dbState.requirements?.total, 3, 'G-roundtrip: requirements.total = 3');
501
+ assert.deepStrictEqual(dbState.progress?.slices?.done, 1, 'G-roundtrip: slices.done = 1');
502
+ assert.deepStrictEqual(dbState.progress?.slices?.total, 3, 'G-roundtrip: slices.total = 3');
503
+ assert.deepStrictEqual(dbState.progress?.tasks?.done, 1, 'G-roundtrip: tasks.done = 1');
504
+ assert.deepStrictEqual(dbState.progress?.tasks?.total, 3, 'G-roundtrip: tasks.total = 3');
513
505
 
514
506
  closeDatabase();
515
507
  } finally {
516
508
  closeDatabase();
517
509
  cleanup(base);
518
510
  }
519
- }
520
-
521
- report();
522
- }
523
-
524
- main().catch((error) => {
525
- console.error(error);
526
- process.exit(1);
511
+ });
527
512
  });