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
@@ -0,0 +1,66 @@
1
+ /**
2
+ * merge-conflict-stops-loop.test.ts — #2330
3
+ *
4
+ * When a squash merge has real code conflicts (not just .gsd/ files),
5
+ * the merge retries forever because MergeConflictError is caught
6
+ * silently in mergeAndExit. This test verifies that:
7
+ * 1. worktree-resolver re-throws MergeConflictError for code conflicts
8
+ * 2. auto/phases.ts wraps mergeAndExit calls to stop the loop on conflict
9
+ */
10
+
11
+ import { readFileSync } from "node:fs";
12
+ import { join } from "node:path";
13
+ import { createTestContext } from "./test-helpers.ts";
14
+
15
+ const { assertTrue, report } = createTestContext();
16
+
17
+ const resolverPath = join(import.meta.dirname, "..", "worktree-resolver.ts");
18
+ const resolverSrc = readFileSync(resolverPath, "utf-8");
19
+
20
+ const phasesPath = join(import.meta.dirname, "..", "auto", "phases.ts");
21
+ const phasesSrc = readFileSync(phasesPath, "utf-8");
22
+
23
+ console.log("\n=== #2330: Merge conflict stops auto loop ===");
24
+
25
+ // ── Test 1: worktree-resolver re-throws MergeConflictError ──────────────
26
+
27
+ const methodStart = resolverSrc.indexOf("Worktree-mode merge:");
28
+ assertTrue(methodStart > 0, "worktree-resolver has _mergeWorktreeMode method");
29
+
30
+ const methodBody = resolverSrc.slice(methodStart, methodStart + 5000);
31
+ const rethrowsConflict =
32
+ methodBody.includes("MergeConflictError") &&
33
+ methodBody.includes("throw err");
34
+
35
+ assertTrue(
36
+ rethrowsConflict,
37
+ "worktree-resolver._mergeWorktreeMode re-throws MergeConflictError (#2330)",
38
+ );
39
+
40
+ // ── Test 2: auto/phases.ts imports and uses MergeConflictError ──────────
41
+
42
+ assertTrue(
43
+ phasesSrc.includes("MergeConflictError") && phasesSrc.includes("mergeAndExit"),
44
+ "auto/phases.ts handles MergeConflictError from mergeAndExit (#2330)",
45
+ );
46
+
47
+ // ── Test 3: The handler stops the loop (doesn't just warn) ──────────────
48
+
49
+ // Find the instanceof MergeConflictError check (not the import line)
50
+ const instanceofIdx = phasesSrc.indexOf("instanceof MergeConflictError");
51
+ assertTrue(instanceofIdx > 0, "auto/phases.ts has instanceof MergeConflictError check");
52
+
53
+ if (instanceofIdx > 0) {
54
+ const afterHandler = phasesSrc.slice(instanceofIdx, instanceofIdx + 500);
55
+ const stopsLoop =
56
+ afterHandler.includes("stopAuto") ||
57
+ afterHandler.includes('action: "break"') ||
58
+ afterHandler.includes("reason: \"merge-conflict\"");
59
+
60
+ assertTrue(
61
+ stopsLoop,
62
+ "auto/phases.ts stops the loop when merge conflict is detected (#2330)",
63
+ );
64
+ }
65
+
66
+ report();
@@ -15,9 +15,9 @@ import {
15
15
  writeGSDDirectory,
16
16
  } from '../migrate/index.ts';
17
17
  import { deriveState } from '../state.ts';
18
- import { createTestContext } from './test-helpers.ts';
18
+ import { describe, test, beforeEach, afterEach } from 'node:test';
19
+ import assert from 'node:assert/strict';
19
20
 
20
- const { assertEq, assertTrue, report } = createTestContext();
21
21
  // ─── Fixture Helpers ───────────────────────────────────────────────────────
22
22
 
23
23
  const SAMPLE_PROJECT = `# Integration Test Project
@@ -195,11 +195,9 @@ function createCompleteFixture(): string {
195
195
  // Tests
196
196
  // ═══════════════════════════════════════════════════════════════════════════
197
197
 
198
- async function main(): Promise<void> {
199
-
200
198
  // ─── Test 1: Path resolution — .planning appended when missing ─────────
201
- console.log('\n=== Path resolution: .planning appended when source path lacks it ===');
202
- {
199
+
200
+ test('Path resolution: .planning appended when source path lacks it', () => {
203
201
  const base = createCompleteFixture();
204
202
  try {
205
203
  // Simulate the command's path resolution logic
@@ -207,16 +205,16 @@ async function main(): Promise<void> {
207
205
  if (!sourcePath.endsWith('.planning')) {
208
206
  sourcePath = join(sourcePath, '.planning');
209
207
  }
210
- assertTrue(sourcePath.endsWith('.planning'), 'path-resolution: .planning appended');
211
- assertTrue(existsSync(sourcePath), 'path-resolution: appended path exists');
208
+ assert.ok(sourcePath.endsWith('.planning'), 'path-resolution: .planning appended');
209
+ assert.ok(existsSync(sourcePath), 'path-resolution: appended path exists');
212
210
  } finally {
213
211
  rmSync(base, { recursive: true, force: true });
214
212
  }
215
- }
213
+ });
216
214
 
217
215
  // ─── Test 2: Path resolution — .planning used as-is ────────────────────
218
- console.log('\n=== Path resolution: .planning used as-is when already present ===');
219
- {
216
+
217
+ test('Path resolution: .planning used as-is when already present', () => {
220
218
  const base = createCompleteFixture();
221
219
  try {
222
220
  const planningPath = join(base, '.planning');
@@ -224,39 +222,39 @@ async function main(): Promise<void> {
224
222
  if (!sourcePath.endsWith('.planning')) {
225
223
  sourcePath = join(sourcePath, '.planning');
226
224
  }
227
- assertEq(sourcePath, resolve(planningPath), 'path-resolution: .planning not double-appended');
228
- assertTrue(existsSync(sourcePath), 'path-resolution: direct path exists');
225
+ assert.deepStrictEqual(sourcePath, resolve(planningPath), 'path-resolution: .planning not double-appended');
226
+ assert.ok(existsSync(sourcePath), 'path-resolution: direct path exists');
229
227
  } finally {
230
228
  rmSync(base, { recursive: true, force: true });
231
229
  }
232
- }
230
+ });
233
231
 
234
232
  // ─── Test 3: Validation gating — non-existent path ─────────────────────
235
- console.log('\n=== Validation gating: non-existent path returns invalid ===');
236
- {
233
+
234
+ test('Validation gating: non-existent path returns invalid', async () => {
237
235
  const fakePath = join(tmpdir(), 'gsd-cmd-nonexistent-' + Date.now(), '.planning');
238
236
  const result = await validatePlanningDirectory(fakePath);
239
- assertEq(result.valid, false, 'validation: non-existent path is invalid');
240
- assertTrue(result.issues.length > 0, 'validation: has issues for non-existent path');
237
+ assert.deepStrictEqual(result.valid, false, 'validation: non-existent path is invalid');
238
+ assert.ok(result.issues.length > 0, 'validation: has issues for non-existent path');
241
239
  const hasFatal = result.issues.some(i => i.severity === 'fatal');
242
- assertTrue(hasFatal, 'validation: non-existent path has fatal issue');
243
- }
240
+ assert.ok(hasFatal, 'validation: non-existent path has fatal issue');
241
+ });
244
242
 
245
243
  // ─── Test 4: Validation gating — valid fixture passes ──────────────────
246
- console.log('\n=== Validation gating: valid fixture passes validation ===');
247
- {
244
+
245
+ test('Validation gating: valid fixture passes validation', async () => {
248
246
  const base = createCompleteFixture();
249
247
  try {
250
248
  const result = await validatePlanningDirectory(join(base, '.planning'));
251
- assertTrue(result.valid === true, 'validation: valid fixture passes');
249
+ assert.ok(result.valid === true, 'validation: valid fixture passes');
252
250
  } finally {
253
251
  rmSync(base, { recursive: true, force: true });
254
252
  }
255
- }
253
+ });
256
254
 
257
255
  // ─── Test 5: Full pipeline round-trip ──────────────────────────────────
258
- console.log('\n=== Full pipeline: parse → transform → preview → write → deriveState ===');
259
- {
256
+
257
+ test('Full pipeline: parse → transform → preview → write → deriveState', async () => {
260
258
  const base = createCompleteFixture();
261
259
  const writeTarget = mkdtempSync(join(tmpdir(), 'gsd-cmd-write-'));
262
260
  try {
@@ -264,17 +262,17 @@ async function main(): Promise<void> {
264
262
 
265
263
  // (a) Validate
266
264
  const validation = await validatePlanningDirectory(planningPath);
267
- assertTrue(validation.valid === true, 'pipeline: validation passes');
265
+ assert.ok(validation.valid === true, 'pipeline: validation passes');
268
266
 
269
267
  // (b) Parse
270
268
  const parsed = await parsePlanningDirectory(planningPath);
271
- assertTrue(parsed.roadmap !== null, 'pipeline: roadmap parsed');
272
- assertTrue(Object.keys(parsed.phases).length >= 2, 'pipeline: phases parsed');
269
+ assert.ok(parsed.roadmap !== null, 'pipeline: roadmap parsed');
270
+ assert.ok(Object.keys(parsed.phases).length >= 2, 'pipeline: phases parsed');
273
271
 
274
272
  // (c) Transform
275
273
  const project = transformToGSD(parsed);
276
- assertTrue(project.milestones.length >= 1, 'pipeline: has milestones');
277
- assertTrue(project.milestones[0].slices.length >= 1, 'pipeline: has slices');
274
+ assert.ok(project.milestones.length >= 1, 'pipeline: has milestones');
275
+ assert.ok(project.milestones[0].slices.length >= 1, 'pipeline: has slices');
278
276
 
279
277
  // Count totals for preview verification
280
278
  let totalTasks = 0;
@@ -294,76 +292,69 @@ async function main(): Promise<void> {
294
292
 
295
293
  // (d) Preview — verify counts match project data
296
294
  const preview = generatePreview(project);
297
- assertEq(preview.milestoneCount, project.milestones.length, 'pipeline: preview milestoneCount');
298
- assertEq(preview.totalSlices, totalSlices, 'pipeline: preview totalSlices');
299
- assertEq(preview.totalTasks, totalTasks, 'pipeline: preview totalTasks');
300
- assertEq(preview.doneSlices, doneSlices, 'pipeline: preview doneSlices');
301
- assertEq(preview.doneTasks, doneTasks, 'pipeline: preview doneTasks');
295
+ assert.deepStrictEqual(preview.milestoneCount, project.milestones.length, 'pipeline: preview milestoneCount');
296
+ assert.deepStrictEqual(preview.totalSlices, totalSlices, 'pipeline: preview totalSlices');
297
+ assert.deepStrictEqual(preview.totalTasks, totalTasks, 'pipeline: preview totalTasks');
298
+ assert.deepStrictEqual(preview.doneSlices, doneSlices, 'pipeline: preview doneSlices');
299
+ assert.deepStrictEqual(preview.doneTasks, doneTasks, 'pipeline: preview doneTasks');
302
300
 
303
301
  // Completion percentages
304
302
  const expectedSlicePct = totalSlices > 0 ? Math.round((doneSlices / totalSlices) * 100) : 0;
305
303
  const expectedTaskPct = totalTasks > 0 ? Math.round((doneTasks / totalTasks) * 100) : 0;
306
- assertEq(preview.sliceCompletionPct, expectedSlicePct, 'pipeline: preview sliceCompletionPct');
307
- assertEq(preview.taskCompletionPct, expectedTaskPct, 'pipeline: preview taskCompletionPct');
304
+ assert.deepStrictEqual(preview.sliceCompletionPct, expectedSlicePct, 'pipeline: preview sliceCompletionPct');
305
+ assert.deepStrictEqual(preview.taskCompletionPct, expectedTaskPct, 'pipeline: preview taskCompletionPct');
308
306
 
309
307
  // Requirements in preview
310
- assertEq(preview.requirements.active, 1, 'pipeline: preview requirements active');
311
- assertEq(preview.requirements.validated, 1, 'pipeline: preview requirements validated');
312
- assertEq(preview.requirements.total, 2, 'pipeline: preview requirements total');
308
+ assert.deepStrictEqual(preview.requirements.active, 1, 'pipeline: preview requirements active');
309
+ assert.deepStrictEqual(preview.requirements.validated, 1, 'pipeline: preview requirements validated');
310
+ assert.deepStrictEqual(preview.requirements.total, 2, 'pipeline: preview requirements total');
313
311
 
314
312
  // (e) Write
315
313
  const result = await writeGSDDirectory(project, writeTarget);
316
- assertTrue(result.paths.length > 0, 'pipeline: files written');
314
+ assert.ok(result.paths.length > 0, 'pipeline: files written');
317
315
 
318
316
  // Key files exist
319
317
  const gsd = join(writeTarget, '.gsd');
320
- assertTrue(existsSync(join(gsd, 'PROJECT.md')), 'pipeline: PROJECT.md written');
321
- assertTrue(existsSync(join(gsd, 'STATE.md')), 'pipeline: STATE.md written');
322
- assertTrue(existsSync(join(gsd, 'REQUIREMENTS.md')), 'pipeline: REQUIREMENTS.md written');
318
+ assert.ok(existsSync(join(gsd, 'PROJECT.md')), 'pipeline: PROJECT.md written');
319
+ assert.ok(existsSync(join(gsd, 'STATE.md')), 'pipeline: STATE.md written');
320
+ assert.ok(existsSync(join(gsd, 'REQUIREMENTS.md')), 'pipeline: REQUIREMENTS.md written');
323
321
 
324
322
  const m001 = join(gsd, 'milestones', 'M001');
325
- assertTrue(existsSync(join(m001, 'M001-ROADMAP.md')), 'pipeline: M001-ROADMAP.md written');
326
- assertTrue(existsSync(join(m001, 'M001-CONTEXT.md')), 'pipeline: M001-CONTEXT.md written');
323
+ assert.ok(existsSync(join(m001, 'M001-ROADMAP.md')), 'pipeline: M001-ROADMAP.md written');
324
+ assert.ok(existsSync(join(m001, 'M001-CONTEXT.md')), 'pipeline: M001-CONTEXT.md written');
327
325
 
328
326
  // At least one slice plan exists
329
327
  const s01Plan = join(m001, 'slices', 'S01', 'S01-PLAN.md');
330
- assertTrue(existsSync(s01Plan), 'pipeline: S01-PLAN.md written');
328
+ assert.ok(existsSync(s01Plan), 'pipeline: S01-PLAN.md written');
331
329
 
332
330
  // (f) deriveState — coherent state from written output
333
331
  console.log(' --- deriveState ---');
334
332
  const state = await deriveState(writeTarget);
335
- assertTrue(state.phase !== undefined, 'pipeline: deriveState returns phase');
336
- assertTrue(state.activeMilestone !== null, 'pipeline: deriveState has activeMilestone');
337
- assertEq(state.activeMilestone!.id, 'M001', 'pipeline: deriveState activeMilestone is M001');
338
- assertTrue(state.progress!.slices !== undefined, 'pipeline: deriveState has slices progress');
339
- assertTrue(state.progress!.tasks !== undefined, 'pipeline: deriveState has tasks progress');
333
+ assert.ok(state.phase !== undefined, 'pipeline: deriveState returns phase');
334
+ assert.ok(state.activeMilestone !== null, 'pipeline: deriveState has activeMilestone');
335
+ assert.deepStrictEqual(state.activeMilestone!.id, 'M001', 'pipeline: deriveState activeMilestone is M001');
336
+ assert.ok(state.progress!.slices !== undefined, 'pipeline: deriveState has slices progress');
337
+ assert.ok(state.progress!.tasks !== undefined, 'pipeline: deriveState has tasks progress');
340
338
 
341
339
  } finally {
342
340
  rmSync(base, { recursive: true, force: true });
343
341
  rmSync(writeTarget, { recursive: true, force: true });
344
342
  }
345
- }
343
+ });
346
344
 
347
345
  // ─── Test 6: .gsd/ exists detection ────────────────────────────────────
348
- console.log('\n=== .gsd/ exists detection ===');
349
- {
346
+
347
+ test('.gsd/ exists detection', () => {
350
348
  const base = mkdtempSync(join(tmpdir(), 'gsd-cmd-exists-'));
351
349
  try {
352
350
  // No .gsd/ yet
353
- assertTrue(!existsSync(join(base, '.gsd')), 'exists-detection: .gsd absent initially');
351
+ assert.ok(!existsSync(join(base, '.gsd')), 'exists-detection: .gsd absent initially');
354
352
 
355
353
  // Create .gsd/
356
354
  mkdirSync(join(base, '.gsd'), { recursive: true });
357
- assertTrue(existsSync(join(base, '.gsd')), 'exists-detection: .gsd detected after creation');
355
+ assert.ok(existsSync(join(base, '.gsd')), 'exists-detection: .gsd detected after creation');
358
356
  } finally {
359
357
  rmSync(base, { recursive: true, force: true });
360
358
  }
361
- }
362
-
363
- report();
364
- }
365
-
366
- main().catch((err) => {
367
- console.error('Unhandled error:', err);
368
- process.exit(1);
369
359
  });
360
+
@@ -18,9 +18,8 @@ import {
18
18
  getActiveTaskFromDb,
19
19
  } from '../gsd-db.ts';
20
20
  import { migrateHierarchyToDb } from '../md-importer.ts';
21
- import { createTestContext } from './test-helpers.ts';
22
-
23
- const { assertEq, assertTrue, report } = createTestContext();
21
+ import { describe, test, beforeEach, afterEach } from 'node:test';
22
+ import assert from 'node:assert/strict';
24
23
 
25
24
  // ─── Fixture Helpers ───────────────────────────────────────────────────────
26
25
 
@@ -98,11 +97,9 @@ const PLAN_S02_1_TASK = `# S02: Second Slice
98
97
  // Test Cases
99
98
  // ═══════════════════════════════════════════════════════════════════════════
100
99
 
101
- async function main(): Promise<void> {
102
-
103
100
  // ─── Test (a): Single milestone with 2 slices, 3 tasks ────────────────
104
- console.log('\n=== migrate-hier: single milestone with 2 slices, 3 tasks ===');
105
- {
101
+
102
+ test('migrate-hier: single milestone with 2 slices, 3 tasks', () => {
106
103
  const base = createFixtureBase();
107
104
  try {
108
105
  writeFile(base, 'milestones/M001/M001-ROADMAP.md', ROADMAP_2_SLICES);
@@ -112,48 +109,48 @@ async function main(): Promise<void> {
112
109
  openDatabase(':memory:');
113
110
  const counts = migrateHierarchyToDb(base);
114
111
 
115
- assertEq(counts.milestones, 1, 'single-ms: 1 milestone inserted');
116
- assertEq(counts.slices, 2, 'single-ms: 2 slices inserted');
117
- assertEq(counts.tasks, 4, 'single-ms: 4 tasks inserted (3 + 1)');
112
+ assert.deepStrictEqual(counts.milestones, 1, 'single-ms: 1 milestone inserted');
113
+ assert.deepStrictEqual(counts.slices, 2, 'single-ms: 2 slices inserted');
114
+ assert.deepStrictEqual(counts.tasks, 4, 'single-ms: 4 tasks inserted (3 + 1)');
118
115
 
119
116
  const milestones = getAllMilestones();
120
- assertEq(milestones.length, 1, 'single-ms: 1 milestone in DB');
121
- assertEq(milestones[0]!.id, 'M001', 'single-ms: milestone ID is M001');
122
- assertEq(milestones[0]!.title, 'M001: Test Milestone', 'single-ms: milestone title correct');
123
- assertEq(milestones[0]!.status, 'active', 'single-ms: milestone status is active');
117
+ assert.deepStrictEqual(milestones.length, 1, 'single-ms: 1 milestone in DB');
118
+ assert.deepStrictEqual(milestones[0]!.id, 'M001', 'single-ms: milestone ID is M001');
119
+ assert.deepStrictEqual(milestones[0]!.title, 'M001: Test Milestone', 'single-ms: milestone title correct');
120
+ assert.deepStrictEqual(milestones[0]!.status, 'active', 'single-ms: milestone status is active');
124
121
 
125
122
  const slices = getMilestoneSlices('M001');
126
- assertEq(slices.length, 2, 'single-ms: 2 slices in DB');
127
- assertEq(slices[0]!.id, 'S01', 'single-ms: first slice is S01');
128
- assertEq(slices[0]!.title, 'First Slice', 'single-ms: S01 title correct');
129
- assertEq(slices[0]!.risk, 'low', 'single-ms: S01 risk is low');
130
- assertEq(slices[0]!.status, 'pending', 'single-ms: S01 status is pending');
131
- assertEq(slices[1]!.id, 'S02', 'single-ms: second slice is S02');
132
- assertEq(slices[1]!.risk, 'high', 'single-ms: S02 risk is high');
123
+ assert.deepStrictEqual(slices.length, 2, 'single-ms: 2 slices in DB');
124
+ assert.deepStrictEqual(slices[0]!.id, 'S01', 'single-ms: first slice is S01');
125
+ assert.deepStrictEqual(slices[0]!.title, 'First Slice', 'single-ms: S01 title correct');
126
+ assert.deepStrictEqual(slices[0]!.risk, 'low', 'single-ms: S01 risk is low');
127
+ assert.deepStrictEqual(slices[0]!.status, 'pending', 'single-ms: S01 status is pending');
128
+ assert.deepStrictEqual(slices[1]!.id, 'S02', 'single-ms: second slice is S02');
129
+ assert.deepStrictEqual(slices[1]!.risk, 'high', 'single-ms: S02 risk is high');
133
130
 
134
131
  const s01Tasks = getSliceTasks('M001', 'S01');
135
- assertEq(s01Tasks.length, 3, 'single-ms: 3 tasks for S01');
136
- assertEq(s01Tasks[0]!.id, 'T01', 'single-ms: first task is T01');
137
- assertEq(s01Tasks[0]!.title, 'First Task', 'single-ms: T01 title correct');
138
- assertEq(s01Tasks[0]!.status, 'pending', 'single-ms: T01 status is pending');
139
- assertEq(s01Tasks[1]!.id, 'T02', 'single-ms: second task is T02');
140
- assertEq(s01Tasks[1]!.status, 'complete', 'single-ms: T02 status is complete (was [x])');
141
- assertEq(s01Tasks[2]!.id, 'T03', 'single-ms: third task is T03');
132
+ assert.deepStrictEqual(s01Tasks.length, 3, 'single-ms: 3 tasks for S01');
133
+ assert.deepStrictEqual(s01Tasks[0]!.id, 'T01', 'single-ms: first task is T01');
134
+ assert.deepStrictEqual(s01Tasks[0]!.title, 'First Task', 'single-ms: T01 title correct');
135
+ assert.deepStrictEqual(s01Tasks[0]!.status, 'pending', 'single-ms: T01 status is pending');
136
+ assert.deepStrictEqual(s01Tasks[1]!.id, 'T02', 'single-ms: second task is T02');
137
+ assert.deepStrictEqual(s01Tasks[1]!.status, 'complete', 'single-ms: T02 status is complete (was [x])');
138
+ assert.deepStrictEqual(s01Tasks[2]!.id, 'T03', 'single-ms: third task is T03');
142
139
 
143
140
  const s02Tasks = getSliceTasks('M001', 'S02');
144
- assertEq(s02Tasks.length, 1, 'single-ms: 1 task for S02');
145
- assertEq(s02Tasks[0]!.id, 'T01', 'single-ms: S02 T01 correct');
141
+ assert.deepStrictEqual(s02Tasks.length, 1, 'single-ms: 1 task for S02');
142
+ assert.deepStrictEqual(s02Tasks[0]!.id, 'T01', 'single-ms: S02 T01 correct');
146
143
 
147
144
  closeDatabase();
148
145
  } finally {
149
146
  closeDatabase();
150
147
  cleanup(base);
151
148
  }
152
- }
149
+ });
153
150
 
154
151
  // ─── Test (b): Multi-milestone — M001 complete, M002 active with deps ─
155
- console.log('\n=== migrate-hier: multi-milestone with deps ===');
156
- {
152
+
153
+ test('migrate-hier: multi-milestone with deps', () => {
157
154
  const base = createFixtureBase();
158
155
  try {
159
156
  // M001: complete (has SUMMARY)
@@ -197,35 +194,35 @@ Depends on M001 completion.
197
194
  openDatabase(':memory:');
198
195
  const counts = migrateHierarchyToDb(base);
199
196
 
200
- assertEq(counts.milestones, 2, 'multi-ms: 2 milestones inserted');
197
+ assert.deepStrictEqual(counts.milestones, 2, 'multi-ms: 2 milestones inserted');
201
198
 
202
199
  const m001 = getMilestone('M001');
203
- assertTrue(m001 !== null, 'multi-ms: M001 exists');
204
- assertEq(m001!.status, 'complete', 'multi-ms: M001 is complete');
200
+ assert.ok(m001 !== null, 'multi-ms: M001 exists');
201
+ assert.deepStrictEqual(m001!.status, 'complete', 'multi-ms: M001 is complete');
205
202
 
206
203
  const m002 = getMilestone('M002');
207
- assertTrue(m002 !== null, 'multi-ms: M002 exists');
208
- assertEq(m002!.status, 'active', 'multi-ms: M002 is active');
209
- assertEq(m002!.depends_on, ['M001'], 'multi-ms: M002 depends on M001');
204
+ assert.ok(m002 !== null, 'multi-ms: M002 exists');
205
+ assert.deepStrictEqual(m002!.status, 'active', 'multi-ms: M002 is active');
206
+ assert.deepStrictEqual(m002!.depends_on, ['M001'], 'multi-ms: M002 depends on M001');
210
207
 
211
208
  // Active milestone should be M002
212
209
  const active = getActiveMilestoneFromDb();
213
- assertEq(active?.id, 'M002', 'multi-ms: active milestone is M002');
210
+ assert.deepStrictEqual(active?.id, 'M002', 'multi-ms: active milestone is M002');
214
211
 
215
212
  // Active slice in M002 should be S01 (S02 depends on S01)
216
213
  const activeSlice = getActiveSliceFromDb('M002');
217
- assertEq(activeSlice?.id, 'S01', 'multi-ms: active slice is S01');
214
+ assert.deepStrictEqual(activeSlice?.id, 'S01', 'multi-ms: active slice is S01');
218
215
 
219
216
  closeDatabase();
220
217
  } finally {
221
218
  closeDatabase();
222
219
  cleanup(base);
223
220
  }
224
- }
221
+ });
225
222
 
226
223
  // ─── Test (c): Partially-completed slice — some tasks [x], some [ ] ───
227
- console.log('\n=== migrate-hier: partially-completed slice ===');
228
- {
224
+
225
+ test('migrate-hier: partially-completed slice', () => {
229
226
  const base = createFixtureBase();
230
227
  try {
231
228
  const roadmap = `# M001: Partial
@@ -260,25 +257,25 @@ Depends on M001 completion.
260
257
  migrateHierarchyToDb(base);
261
258
 
262
259
  const tasks = getSliceTasks('M001', 'S01');
263
- assertEq(tasks.length, 3, 'partial: 3 tasks');
264
- assertEq(tasks[0]!.status, 'complete', 'partial: T01 is complete');
265
- assertEq(tasks[1]!.status, 'complete', 'partial: T02 is complete');
266
- assertEq(tasks[2]!.status, 'pending', 'partial: T03 is pending');
260
+ assert.deepStrictEqual(tasks.length, 3, 'partial: 3 tasks');
261
+ assert.deepStrictEqual(tasks[0]!.status, 'complete', 'partial: T01 is complete');
262
+ assert.deepStrictEqual(tasks[1]!.status, 'complete', 'partial: T02 is complete');
263
+ assert.deepStrictEqual(tasks[2]!.status, 'pending', 'partial: T03 is pending');
267
264
 
268
265
  // Active task should be T03
269
266
  const activeTask = getActiveTaskFromDb('M001', 'S01');
270
- assertEq(activeTask?.id, 'T03', 'partial: active task is T03');
267
+ assert.deepStrictEqual(activeTask?.id, 'T03', 'partial: active task is T03');
271
268
 
272
269
  closeDatabase();
273
270
  } finally {
274
271
  closeDatabase();
275
272
  cleanup(base);
276
273
  }
277
- }
274
+ });
278
275
 
279
276
  // ─── Test (d): Ghost milestone skipped ────────────────────────────────
280
- console.log('\n=== migrate-hier: ghost milestone skipped ===');
281
- {
277
+
278
+ test('migrate-hier: ghost milestone skipped', () => {
282
279
  const base = createFixtureBase();
283
280
  try {
284
281
  // M001: real milestone
@@ -289,21 +286,21 @@ Depends on M001 completion.
289
286
  openDatabase(':memory:');
290
287
  const counts = migrateHierarchyToDb(base);
291
288
 
292
- assertEq(counts.milestones, 1, 'ghost: only 1 milestone inserted');
289
+ assert.deepStrictEqual(counts.milestones, 1, 'ghost: only 1 milestone inserted');
293
290
  const milestones = getAllMilestones();
294
- assertEq(milestones.length, 1, 'ghost: 1 milestone in DB');
295
- assertEq(milestones[0]!.id, 'M001', 'ghost: only M001 in DB');
291
+ assert.deepStrictEqual(milestones.length, 1, 'ghost: 1 milestone in DB');
292
+ assert.deepStrictEqual(milestones[0]!.id, 'M001', 'ghost: only M001 in DB');
296
293
 
297
294
  closeDatabase();
298
295
  } finally {
299
296
  closeDatabase();
300
297
  cleanup(base);
301
298
  }
302
- }
299
+ });
303
300
 
304
301
  // ─── Test (e): Idempotent re-run — calling twice doesn't duplicate ────
305
- console.log('\n=== migrate-hier: idempotent re-run ===');
306
- {
302
+
303
+ test('migrate-hier: idempotent re-run', () => {
307
304
  const base = createFixtureBase();
308
305
  try {
309
306
  writeFile(base, 'milestones/M001/M001-ROADMAP.md', ROADMAP_2_SLICES);
@@ -313,31 +310,31 @@ Depends on M001 completion.
313
310
 
314
311
  // First run
315
312
  const counts1 = migrateHierarchyToDb(base);
316
- assertEq(counts1.milestones, 1, 'idempotent-1: 1 milestone first run');
317
- assertEq(counts1.slices, 2, 'idempotent-1: 2 slices first run');
318
- assertEq(counts1.tasks, 3, 'idempotent-1: 3 tasks first run');
313
+ assert.deepStrictEqual(counts1.milestones, 1, 'idempotent-1: 1 milestone first run');
314
+ assert.deepStrictEqual(counts1.slices, 2, 'idempotent-1: 2 slices first run');
315
+ assert.deepStrictEqual(counts1.tasks, 3, 'idempotent-1: 3 tasks first run');
319
316
 
320
317
  // Second run — INSERT OR IGNORE means no duplicates
321
318
  const counts2 = migrateHierarchyToDb(base);
322
319
  // Counts reflect attempts, not actual inserts (INSERT OR IGNORE silently skips)
323
320
  // The important thing: DB doesn't have duplicates
324
321
  const milestones = getAllMilestones();
325
- assertEq(milestones.length, 1, 'idempotent-2: still 1 milestone after second run');
322
+ assert.deepStrictEqual(milestones.length, 1, 'idempotent-2: still 1 milestone after second run');
326
323
  const slices = getMilestoneSlices('M001');
327
- assertEq(slices.length, 2, 'idempotent-2: still 2 slices after second run');
324
+ assert.deepStrictEqual(slices.length, 2, 'idempotent-2: still 2 slices after second run');
328
325
  const tasks = getSliceTasks('M001', 'S01');
329
- assertEq(tasks.length, 3, 'idempotent-2: still 3 tasks for S01 after second run');
326
+ assert.deepStrictEqual(tasks.length, 3, 'idempotent-2: still 3 tasks for S01 after second run');
330
327
 
331
328
  closeDatabase();
332
329
  } finally {
333
330
  closeDatabase();
334
331
  cleanup(base);
335
332
  }
336
- }
333
+ });
337
334
 
338
335
  // ─── Test (f): Empty roadmap — milestone inserted but no slices ───────
339
- console.log('\n=== migrate-hier: empty roadmap, no slices ===');
340
- {
336
+
337
+ test('migrate-hier: empty roadmap, no slices', () => {
341
338
  const base = createFixtureBase();
342
339
  try {
343
340
  const emptyRoadmap = `# M001: Empty Milestone
@@ -353,27 +350,27 @@ Depends on M001 completion.
353
350
  openDatabase(':memory:');
354
351
  const counts = migrateHierarchyToDb(base);
355
352
 
356
- assertEq(counts.milestones, 1, 'empty-roadmap: 1 milestone inserted');
357
- assertEq(counts.slices, 0, 'empty-roadmap: 0 slices inserted');
358
- assertEq(counts.tasks, 0, 'empty-roadmap: 0 tasks inserted');
353
+ assert.deepStrictEqual(counts.milestones, 1, 'empty-roadmap: 1 milestone inserted');
354
+ assert.deepStrictEqual(counts.slices, 0, 'empty-roadmap: 0 slices inserted');
355
+ assert.deepStrictEqual(counts.tasks, 0, 'empty-roadmap: 0 tasks inserted');
359
356
 
360
357
  const milestones = getAllMilestones();
361
- assertEq(milestones.length, 1, 'empty-roadmap: 1 milestone in DB');
362
- assertEq(milestones[0]!.title, 'M001: Empty Milestone', 'empty-roadmap: title correct');
358
+ assert.deepStrictEqual(milestones.length, 1, 'empty-roadmap: 1 milestone in DB');
359
+ assert.deepStrictEqual(milestones[0]!.title, 'M001: Empty Milestone', 'empty-roadmap: title correct');
363
360
 
364
361
  const slices = getMilestoneSlices('M001');
365
- assertEq(slices.length, 0, 'empty-roadmap: no slices in DB');
362
+ assert.deepStrictEqual(slices.length, 0, 'empty-roadmap: no slices in DB');
366
363
 
367
364
  closeDatabase();
368
365
  } finally {
369
366
  closeDatabase();
370
367
  cleanup(base);
371
368
  }
372
- }
369
+ });
373
370
 
374
371
  // ─── Test (g): Slice depends parsed correctly ─────────────────────────
375
- console.log('\n=== migrate-hier: slice depends parsed ===');
376
- {
372
+
373
+ test('migrate-hier: slice depends parsed', () => {
377
374
  const base = createFixtureBase();
378
375
  try {
379
376
  const roadmap = `# M001: Deps Test
@@ -397,21 +394,21 @@ Depends on M001 completion.
397
394
  migrateHierarchyToDb(base);
398
395
 
399
396
  const slices = getMilestoneSlices('M001');
400
- assertEq(slices.length, 3, 'depends: 3 slices');
401
- assertEq(slices[0]!.depends, [], 'depends: S01 has no deps');
402
- assertEq(slices[1]!.depends, ['S01'], 'depends: S02 depends on S01');
403
- assertEq(slices[2]!.depends, ['S01', 'S02'], 'depends: S03 depends on S01,S02');
397
+ assert.deepStrictEqual(slices.length, 3, 'depends: 3 slices');
398
+ assert.deepStrictEqual(slices[0]!.depends, [], 'depends: S01 has no deps');
399
+ assert.deepStrictEqual(slices[1]!.depends, ['S01'], 'depends: S02 depends on S01');
400
+ assert.deepStrictEqual(slices[2]!.depends, ['S01', 'S02'], 'depends: S03 depends on S01,S02');
404
401
 
405
402
  closeDatabase();
406
403
  } finally {
407
404
  closeDatabase();
408
405
  cleanup(base);
409
406
  }
410
- }
407
+ });
411
408
 
412
409
  // ─── Test (h): Demo text extracted from roadmap ───────────────────────
413
- console.log('\n=== migrate-hier: demo text extracted ===');
414
- {
410
+
411
+ test('migrate-hier: demo text extracted', () => {
415
412
  const base = createFixtureBase();
416
413
  try {
417
414
  writeFile(base, 'milestones/M001/M001-ROADMAP.md', ROADMAP_2_SLICES);
@@ -420,20 +417,13 @@ Depends on M001 completion.
420
417
  migrateHierarchyToDb(base);
421
418
 
422
419
  const slices = getMilestoneSlices('M001');
423
- assertEq(slices[0]!.demo, 'First slice done.', 'demo: S01 demo text correct');
424
- assertEq(slices[1]!.demo, 'All slices done.', 'demo: S02 demo text correct');
420
+ assert.deepStrictEqual(slices[0]!.demo, 'First slice done.', 'demo: S01 demo text correct');
421
+ assert.deepStrictEqual(slices[1]!.demo, 'All slices done.', 'demo: S02 demo text correct');
425
422
 
426
423
  closeDatabase();
427
424
  } finally {
428
425
  closeDatabase();
429
426
  cleanup(base);
430
427
  }
431
- }
432
-
433
- report();
434
- }
435
-
436
- main().catch((error) => {
437
- console.error(error);
438
- process.exit(1);
439
428
  });
429
+