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
@@ -5,7 +5,8 @@
5
5
  // (b) Helpers fall back to non-null output when DB unavailable
6
6
  // (c) Scoped filtering actually reduces content
7
7
 
8
- import { createTestContext } from './test-helpers.ts';
8
+ import { describe, test } from 'node:test';
9
+ import assert from 'node:assert/strict';
9
10
  import {
10
11
  openDatabase,
11
12
  closeDatabase,
@@ -22,8 +23,6 @@ import {
22
23
  formatRequirementsForPrompt,
23
24
  } from '../context-store.ts';
24
25
 
25
- const { assertEq, assertTrue, assertMatch, assertNoMatch, report } = createTestContext();
26
-
27
26
  // ═══════════════════════════════════════════════════════════════════════════
28
27
  // prompt-db: DB-aware decisions helper returns scoped content
29
28
  // ═══════════════════════════════════════════════════════════════════════════
@@ -50,23 +49,23 @@ console.log('\n=== prompt-db: scoped decisions from DB ===');
50
49
 
51
50
  // Query scoped to M001
52
51
  const m001Decisions = queryDecisions({ milestoneId: 'M001' });
53
- assertTrue(m001Decisions.length > 0, 'M001 decisions should exist');
54
- assertTrue(m001Decisions.length < 10, `scoped query should return fewer than 10 (got ${m001Decisions.length})`);
52
+ assert.ok(m001Decisions.length > 0, 'M001 decisions should exist');
53
+ assert.ok(m001Decisions.length < 10, `scoped query should return fewer than 10 (got ${m001Decisions.length})`);
55
54
 
56
55
  // Verify all returned decisions are for M001
57
56
  for (const d of m001Decisions) {
58
- assertMatch(d.when_context, /M001/, `decision ${d.id} should be for M001`);
57
+ assert.match(d.when_context, /M001/, `decision ${d.id} should be for M001`);
59
58
  }
60
59
 
61
60
  // Format and verify wrapping
62
61
  const formatted = formatDecisionsForPrompt(m001Decisions);
63
- assertTrue(formatted.length > 0, 'formatted decisions should be non-empty');
64
- assertMatch(formatted, /\| # \| When \| Scope/, 'formatted decisions have table header');
62
+ assert.ok(formatted.length > 0, 'formatted decisions should be non-empty');
63
+ assert.match(formatted, /\| # \| When \| Scope/, 'formatted decisions have table header');
65
64
 
66
65
  // Verify the expected wrapper format that inlineDecisionsFromDb would produce
67
66
  const wrapped = `### Decisions\nSource: \`.gsd/DECISIONS.md\`\n\n${formatted}`;
68
- assertMatch(wrapped, /^### Decisions/, 'wrapped decisions start with ### Decisions');
69
- assertMatch(wrapped, /Source:.*DECISIONS\.md/, 'wrapped decisions have source path');
67
+ assert.match(wrapped, /^### Decisions/, 'wrapped decisions start with ### Decisions');
68
+ assert.match(wrapped, /Source:.*DECISIONS\.md/, 'wrapped decisions have source path');
70
69
 
71
70
  closeDatabase();
72
71
  }
@@ -101,25 +100,25 @@ console.log('\n=== prompt-db: scoped requirements from DB ===');
101
100
 
102
101
  // Query scoped to S01 — should get R001 (primary) and R002 (supporting)
103
102
  const s01Reqs = queryRequirements({ sliceId: 'S01' });
104
- assertEq(s01Reqs.length, 2, 'S01 requirements should be 2 (primary + supporting)');
103
+ assert.deepStrictEqual(s01Reqs.length, 2, 'S01 requirements should be 2 (primary + supporting)');
105
104
  const ids = s01Reqs.map(r => r.id).sort();
106
- assertEq(ids, ['R001', 'R002'], 'S01 owns R001 and supports R002');
105
+ assert.deepStrictEqual(ids, ['R001', 'R002'], 'S01 owns R001 and supports R002');
107
106
 
108
107
  // Unscoped query returns all 3
109
108
  const allReqs = queryRequirements();
110
- assertEq(allReqs.length, 3, 'unscoped requirements should return all 3');
109
+ assert.deepStrictEqual(allReqs.length, 3, 'unscoped requirements should return all 3');
111
110
 
112
111
  // Format and verify wrapping
113
112
  const formatted = formatRequirementsForPrompt(s01Reqs);
114
- assertTrue(formatted.length > 0, 'formatted requirements should be non-empty');
115
- assertMatch(formatted, /### R001/, 'formatted requirements include R001');
116
- assertMatch(formatted, /### R002/, 'formatted requirements include R002');
117
- assertNoMatch(formatted, /### R003/, 'formatted requirements exclude R003');
113
+ assert.ok(formatted.length > 0, 'formatted requirements should be non-empty');
114
+ assert.match(formatted, /### R001/, 'formatted requirements include R001');
115
+ assert.match(formatted, /### R002/, 'formatted requirements include R002');
116
+ assert.doesNotMatch(formatted, /### R003/, 'formatted requirements exclude R003');
118
117
 
119
118
  // Verify the expected wrapper format that inlineRequirementsFromDb would produce
120
119
  const wrapped = `### Requirements\nSource: \`.gsd/REQUIREMENTS.md\`\n\n${formatted}`;
121
- assertMatch(wrapped, /^### Requirements/, 'wrapped requirements start with ### Requirements');
122
- assertMatch(wrapped, /Source:.*REQUIREMENTS\.md/, 'wrapped requirements have source path');
120
+ assert.match(wrapped, /^### Requirements/, 'wrapped requirements start with ### Requirements');
121
+ assert.match(wrapped, /Source:.*REQUIREMENTS\.md/, 'wrapped requirements have source path');
123
122
 
124
123
  closeDatabase();
125
124
  }
@@ -142,13 +141,13 @@ console.log('\n=== prompt-db: project content from DB ===');
142
141
  });
143
142
 
144
143
  const content = queryProject();
145
- assertEq(content, '# Test Project\n\nThis is the project description.', 'queryProject returns content');
144
+ assert.deepStrictEqual(content, '# Test Project\n\nThis is the project description.', 'queryProject returns content');
146
145
 
147
146
  // Verify the expected wrapper format that inlineProjectFromDb would produce
148
147
  const wrapped = `### Project\nSource: \`.gsd/PROJECT.md\`\n\n${content}`;
149
- assertMatch(wrapped, /^### Project/, 'wrapped project starts with ### Project');
150
- assertMatch(wrapped, /Source:.*PROJECT\.md/, 'wrapped project has source path');
151
- assertMatch(wrapped, /# Test Project/, 'wrapped project includes content');
148
+ assert.match(wrapped, /^### Project/, 'wrapped project starts with ### Project');
149
+ assert.match(wrapped, /Source:.*PROJECT\.md/, 'wrapped project has source path');
150
+ assert.match(wrapped, /# Test Project/, 'wrapped project includes content');
152
151
 
153
152
  closeDatabase();
154
153
  }
@@ -160,27 +159,27 @@ console.log('\n=== prompt-db: project content from DB ===');
160
159
  console.log('\n=== prompt-db: fallback when DB unavailable ===');
161
160
  {
162
161
  closeDatabase();
163
- assertTrue(!isDbAvailable(), 'DB should not be available');
162
+ assert.ok(!isDbAvailable(), 'DB should not be available');
164
163
 
165
164
  // queryDecisions returns [] when DB closed — helper would fall back
166
165
  const decisions = queryDecisions({ milestoneId: 'M001' });
167
- assertEq(decisions, [], 'queryDecisions returns [] when DB closed');
166
+ assert.deepStrictEqual(decisions, [], 'queryDecisions returns [] when DB closed');
168
167
 
169
168
  // queryRequirements returns [] when DB closed — helper would fall back
170
169
  const requirements = queryRequirements({ sliceId: 'S01' });
171
- assertEq(requirements, [], 'queryRequirements returns [] when DB closed');
170
+ assert.deepStrictEqual(requirements, [], 'queryRequirements returns [] when DB closed');
172
171
 
173
172
  // queryProject returns null when DB closed — helper would fall back
174
173
  const project = queryProject();
175
- assertEq(project, null, 'queryProject returns null when DB closed');
174
+ assert.deepStrictEqual(project, null, 'queryProject returns null when DB closed');
176
175
 
177
176
  // formatDecisionsForPrompt returns '' for empty input
178
177
  const formatted = formatDecisionsForPrompt([]);
179
- assertEq(formatted, '', 'formatDecisionsForPrompt returns empty for empty input');
178
+ assert.deepStrictEqual(formatted, '', 'formatDecisionsForPrompt returns empty for empty input');
180
179
 
181
180
  // formatRequirementsForPrompt returns '' for empty input
182
181
  const formattedReqs = formatRequirementsForPrompt([]);
183
- assertEq(formattedReqs, '', 'formatRequirementsForPrompt returns empty for empty input');
182
+ assert.deepStrictEqual(formattedReqs, '', 'formatRequirementsForPrompt returns empty for empty input');
184
183
  }
185
184
 
186
185
  // ═══════════════════════════════════════════════════════════════════════════
@@ -210,15 +209,15 @@ console.log('\n=== prompt-db: scoped filtering reduces content ===');
210
209
  const allDecisions = queryDecisions();
211
210
  const m001Decisions = queryDecisions({ milestoneId: 'M001' });
212
211
 
213
- assertEq(allDecisions.length, 10, 'unscoped returns all 10 decisions');
214
- assertTrue(m001Decisions.length < 10, `M001-scoped returns fewer than 10 (got ${m001Decisions.length})`);
215
- assertTrue(m001Decisions.length > 0, 'M001-scoped returns at least 1');
212
+ assert.deepStrictEqual(allDecisions.length, 10, 'unscoped returns all 10 decisions');
213
+ assert.ok(m001Decisions.length < 10, `M001-scoped returns fewer than 10 (got ${m001Decisions.length})`);
214
+ assert.ok(m001Decisions.length > 0, 'M001-scoped returns at least 1');
216
215
 
217
216
  // Format both and compare sizes — scoped should be shorter
218
217
  const allFormatted = formatDecisionsForPrompt(allDecisions);
219
218
  const scopedFormatted = formatDecisionsForPrompt(m001Decisions);
220
219
 
221
- assertTrue(
220
+ assert.ok(
222
221
  scopedFormatted.length < allFormatted.length,
223
222
  `scoped content (${scopedFormatted.length} chars) should be shorter than unscoped (${allFormatted.length} chars)`,
224
223
  );
@@ -245,14 +244,14 @@ console.log('\n=== prompt-db: scoped filtering reduces content ===');
245
244
  const allReqs = queryRequirements();
246
245
  const s01Reqs = queryRequirements({ sliceId: 'S01' });
247
246
 
248
- assertEq(allReqs.length, 8, 'unscoped returns all 8 requirements');
249
- assertTrue(s01Reqs.length < 8, `S01-scoped returns fewer than 8 (got ${s01Reqs.length})`);
250
- assertTrue(s01Reqs.length > 0, 'S01-scoped returns at least 1');
247
+ assert.deepStrictEqual(allReqs.length, 8, 'unscoped returns all 8 requirements');
248
+ assert.ok(s01Reqs.length < 8, `S01-scoped returns fewer than 8 (got ${s01Reqs.length})`);
249
+ assert.ok(s01Reqs.length > 0, 'S01-scoped returns at least 1');
251
250
 
252
251
  const allReqsFormatted = formatRequirementsForPrompt(allReqs);
253
252
  const scopedReqsFormatted = formatRequirementsForPrompt(s01Reqs);
254
253
 
255
- assertTrue(
254
+ assert.ok(
256
255
  scopedReqsFormatted.length < allReqsFormatted.length,
257
256
  `scoped requirements (${scopedReqsFormatted.length} chars) should be shorter than unscoped (${allReqsFormatted.length} chars)`,
258
257
  );
@@ -292,23 +291,23 @@ console.log('\n=== prompt-db: DB helpers wrapper format matches expected pattern
292
291
 
293
292
  // Simulate what inlineDecisionsFromDb does
294
293
  const decisions = queryDecisions({ milestoneId: 'M001' });
295
- assertTrue(decisions.length === 1, 'got 1 decision for M001');
294
+ assert.ok(decisions.length === 1, 'got 1 decision for M001');
296
295
  const dFormatted = formatDecisionsForPrompt(decisions);
297
296
  const dWrapped = `### Decisions\nSource: \`.gsd/DECISIONS.md\`\n\n${dFormatted}`;
298
- assertMatch(dWrapped, /^### Decisions\nSource: `.gsd\/DECISIONS\.md`\n\n\| #/, 'decisions wrapper format correct');
297
+ assert.match(dWrapped, /^### Decisions\nSource: `.gsd\/DECISIONS\.md`\n\n\| #/, 'decisions wrapper format correct');
299
298
 
300
299
  // Simulate what inlineRequirementsFromDb does
301
300
  const reqs = queryRequirements({ sliceId: 'S01' });
302
- assertTrue(reqs.length === 1, 'got 1 requirement for S01');
301
+ assert.ok(reqs.length === 1, 'got 1 requirement for S01');
303
302
  const rFormatted = formatRequirementsForPrompt(reqs);
304
303
  const rWrapped = `### Requirements\nSource: \`.gsd/REQUIREMENTS.md\`\n\n${rFormatted}`;
305
- assertMatch(rWrapped, /^### Requirements\nSource: `.gsd\/REQUIREMENTS\.md`\n\n### R001/, 'requirements wrapper format correct');
304
+ assert.match(rWrapped, /^### Requirements\nSource: `.gsd\/REQUIREMENTS\.md`\n\n### R001/, 'requirements wrapper format correct');
306
305
 
307
306
  // Simulate what inlineProjectFromDb does
308
307
  const project = queryProject();
309
- assertTrue(project !== null, 'project content exists');
308
+ assert.ok(project !== null, 'project content exists');
310
309
  const pWrapped = `### Project\nSource: \`.gsd/PROJECT.md\`\n\n${project}`;
311
- assertMatch(pWrapped, /^### Project\nSource: `.gsd\/PROJECT\.md`\n\n# Project Name/, 'project wrapper format correct');
310
+ assert.match(pWrapped, /^### Project\nSource: `.gsd\/PROJECT\.md`\n\n# Project Name/, 'project wrapper format correct');
312
311
 
313
312
  closeDatabase();
314
313
  }
@@ -322,8 +321,9 @@ import { join } from 'node:path';
322
321
  import { tmpdir } from 'node:os';
323
322
  import { migrateFromMarkdown } from '../md-importer.ts';
324
323
 
325
- console.log('\n=== prompt-db: re-import updates DB when source markdown changes ===');
326
- {
324
+
325
+ describe('prompt-db', () => {
326
+ test('prompt-db: re-import updates DB when source markdown changes', () => {
327
327
  // Create a temp dir simulating a project with .gsd/DECISIONS.md
328
328
  const tmpDir = mkdtempSync(join(tmpdir(), 'prompt-db-reimport-'));
329
329
  const gsdDir = join(tmpDir, '.gsd');
@@ -345,9 +345,9 @@ console.log('\n=== prompt-db: re-import updates DB when source markdown changes
345
345
 
346
346
  // Verify initial state: 2 decisions
347
347
  const initial = queryDecisions();
348
- assertEq(initial.length, 2, 're-import: initial import has 2 decisions');
348
+ assert.deepStrictEqual(initial.length, 2, 're-import: initial import has 2 decisions');
349
349
  const initialIds = initial.map(d => d.id).sort();
350
- assertEq(initialIds, ['D001', 'D002'], 're-import: initial decisions are D001, D002');
350
+ assert.deepStrictEqual(initialIds, ['D001', 'D002'], 're-import: initial decisions are D001, D002');
351
351
 
352
352
  // Now "the LLM modifies DECISIONS.md" — add a third decision
353
353
  const updatedDecisions = `# Decisions Register
@@ -365,23 +365,23 @@ console.log('\n=== prompt-db: re-import updates DB when source markdown changes
365
365
 
366
366
  // Verify DB now has 3 decisions
367
367
  const afterReimport = queryDecisions();
368
- assertEq(afterReimport.length, 3, 're-import: after re-import has 3 decisions');
368
+ assert.deepStrictEqual(afterReimport.length, 3, 're-import: after re-import has 3 decisions');
369
369
  const afterIds = afterReimport.map(d => d.id).sort();
370
- assertEq(afterIds, ['D001', 'D002', 'D003'], 're-import: decisions are D001, D002, D003');
370
+ assert.deepStrictEqual(afterIds, ['D001', 'D002', 'D003'], 're-import: decisions are D001, D002, D003');
371
371
 
372
372
  // Verify the new decision has correct data
373
373
  const d003 = afterReimport.find(d => d.id === 'D003');
374
- assertTrue(d003 !== undefined, 're-import: D003 exists');
375
- assertEq(d003!.when_context, 'M001/S02', 're-import: D003 when_context is M001/S02');
376
- assertEq(d003!.scope, 'runtime', 're-import: D003 scope is runtime');
377
- assertEq(d003!.choice, 'D014 pattern', 're-import: D003 choice is D014 pattern');
374
+ assert.ok(d003 !== undefined, 're-import: D003 exists');
375
+ assert.deepStrictEqual(d003!.when_context, 'M001/S02', 're-import: D003 when_context is M001/S02');
376
+ assert.deepStrictEqual(d003!.scope, 'runtime', 're-import: D003 scope is runtime');
377
+ assert.deepStrictEqual(d003!.choice, 'D014 pattern', 're-import: D003 choice is D014 pattern');
378
378
 
379
379
  // Verify scoped query picks up the new decision
380
380
  const m001Scoped = queryDecisions({ milestoneId: 'M001' });
381
- assertTrue(m001Scoped.length === 3, 're-import: all 3 decisions are for M001');
381
+ assert.ok(m001Scoped.length === 3, 're-import: all 3 decisions are for M001');
382
382
 
383
383
  closeDatabase();
384
- }
384
+ });
385
385
 
386
386
  // ─── Final Report ──────────────────────────────────────────────────────────
387
- report();
387
+ });
@@ -1,3 +1,5 @@
1
+ import { describe, test } from 'node:test';
2
+ import assert from 'node:assert/strict';
1
3
  import { mkdtempSync, mkdirSync, rmSync, writeFileSync } from "node:fs";
2
4
  import { join } from "node:path";
3
5
  import { tmpdir } from "node:os";
@@ -5,122 +7,94 @@ import { tmpdir } from "node:os";
5
7
  import { deriveState } from "../state.js";
6
8
  import { buildExistingMilestonesContext } from "../guided-flow.js";
7
9
 
8
- let passed = 0;
9
- let failed = 0;
10
-
11
- function assert(condition: boolean, message: string): void {
12
- if (condition) {
13
- passed++;
14
- } else {
15
- failed++;
16
- console.error(` FAIL: ${message}`);
17
- }
18
- }
19
-
20
- // ─── Fixture setup ──────────────────────────────────────────────────────
21
-
22
- const tmpBase = mkdtempSync(join(tmpdir(), "gsd-queue-draft-test-"));
23
- const gsd = join(tmpBase, ".gsd");
24
-
25
- // M001: has only CONTEXT-DRAFT.md (draft milestone)
26
- mkdirSync(join(gsd, "milestones", "M001"), { recursive: true });
27
- writeFileSync(
28
- join(gsd, "milestones", "M001", "M001-CONTEXT-DRAFT.md"),
29
- "# M001: Draft Milestone\n\nSeed material from prior discussion.\n",
30
- );
31
-
32
- // M002: has full CONTEXT.md (ready milestone)
33
- mkdirSync(join(gsd, "milestones", "M002"), { recursive: true });
34
- writeFileSync(
35
- join(gsd, "milestones", "M002", "M002-CONTEXT.md"),
36
- "# M002: Ready Milestone\n\nFull context from deep discussion.\n",
37
- );
38
-
39
- // M003: has both CONTEXT.md and CONTEXT-DRAFT.md (CONTEXT wins)
40
- mkdirSync(join(gsd, "milestones", "M003"), { recursive: true });
41
- writeFileSync(
42
- join(gsd, "milestones", "M003", "M003-CONTEXT.md"),
43
- "# M003: Full Context\n\nThis is the real context.\n",
44
- );
45
- writeFileSync(
46
- join(gsd, "milestones", "M003", "M003-CONTEXT-DRAFT.md"),
47
- "# M003: Draft\n\nThis should be ignored.\n",
48
- );
49
-
50
- // M004: has neither (empty milestone dir)
51
- mkdirSync(join(gsd, "milestones", "M004"), { recursive: true });
52
-
53
- // ─── Build context ──────────────────────────────────────────────────────
54
-
55
- const state = await deriveState(tmpBase);
56
- const milestoneIds = ["M001", "M002", "M003", "M004"];
57
- const context = await buildExistingMilestonesContext(tmpBase, milestoneIds, state);
58
-
59
- // ─── Test: draft-only milestone includes "Draft context available" ──────
60
-
61
- assert(
62
- context.includes("Draft context available"),
63
- "M001 (draft-only) should include 'Draft context available' label",
64
- );
65
-
66
- assert(
67
- context.includes("Seed material from prior discussion"),
68
- "M001 draft content should be included in context output",
69
- );
70
-
71
- // ─── Test: full-context milestone uses "Context:" label ────────────────
72
-
73
- assert(
74
- context.includes("**Context:**"),
75
- "M002 (full context) should use 'Context:' label",
76
- );
77
-
78
- assert(
79
- context.includes("Full context from deep discussion"),
80
- "M002 context content should be included",
81
- );
82
-
83
- // ─── Test: both files → CONTEXT.md wins, no draft label ────────────────
84
-
85
- // Find M003's section and check it has Context: but not Draft
86
- const m003Idx = context.indexOf("M003:");
87
- const m003Section = context.slice(m003Idx, m003Idx + 500);
88
-
89
- assert(
90
- m003Section.includes("**Context:**"),
91
- "M003 (both files) should use 'Context:' label (CONTEXT.md wins)",
92
- );
93
-
94
- assert(
95
- !m003Section.includes("Draft context available"),
96
- "M003 (both files) should NOT show draft label — CONTEXT.md takes precedence",
97
- );
98
-
99
- assert(
100
- m003Section.includes("This is the real context"),
101
- "M003 should show CONTEXT.md content, not draft content",
102
- );
103
-
104
- // ─── Test: neither file → no context section ───────────────────────────
105
-
106
- const m004Idx = context.indexOf("M004:");
107
- const m004Section = context.slice(m004Idx, m004Idx + 500);
108
-
109
- assert(
110
- !m004Section.includes("**Context:**"),
111
- "M004 (neither file) should not have Context: label",
112
- );
113
-
114
- assert(
115
- !m004Section.includes("Draft context available"),
116
- "M004 (neither file) should not have Draft label",
117
- );
118
-
119
- // ─── Cleanup ──────────────────────────────────────────────────────────
120
-
121
- rmSync(tmpBase, { recursive: true, force: true });
122
-
123
- // ─── Results ──────────────────────────────────────────────────────────
124
-
125
- console.log(`\nqueue-draft-detection: ${passed} passed, ${failed} failed`);
126
- if (failed > 0) process.exit(1);
10
+ describe('queue-draft-detection', () => {
11
+ test('draft and context milestone detection', async () => {
12
+ const tmpBase = mkdtempSync(join(tmpdir(), "gsd-queue-draft-test-"));
13
+ const gsd = join(tmpBase, ".gsd");
14
+
15
+ try {
16
+ // M001: has only CONTEXT-DRAFT.md (draft milestone)
17
+ mkdirSync(join(gsd, "milestones", "M001"), { recursive: true });
18
+ writeFileSync(
19
+ join(gsd, "milestones", "M001", "M001-CONTEXT-DRAFT.md"),
20
+ "# M001: Draft Milestone\n\nSeed material from prior discussion.\n",
21
+ );
22
+
23
+ // M002: has full CONTEXT.md (ready milestone)
24
+ mkdirSync(join(gsd, "milestones", "M002"), { recursive: true });
25
+ writeFileSync(
26
+ join(gsd, "milestones", "M002", "M002-CONTEXT.md"),
27
+ "# M002: Ready Milestone\n\nFull context from deep discussion.\n",
28
+ );
29
+
30
+ // M003: has both CONTEXT.md and CONTEXT-DRAFT.md (CONTEXT wins)
31
+ mkdirSync(join(gsd, "milestones", "M003"), { recursive: true });
32
+ writeFileSync(
33
+ join(gsd, "milestones", "M003", "M003-CONTEXT.md"),
34
+ "# M003: Full Context\n\nThis is the real context.\n",
35
+ );
36
+ writeFileSync(
37
+ join(gsd, "milestones", "M003", "M003-CONTEXT-DRAFT.md"),
38
+ "# M003: Draft\n\nThis should be ignored.\n",
39
+ );
40
+
41
+ // M004: has neither (empty milestone dir)
42
+ mkdirSync(join(gsd, "milestones", "M004"), { recursive: true });
43
+
44
+ // Build context
45
+ const state = await deriveState(tmpBase);
46
+ const milestoneIds = ["M001", "M002", "M003", "M004"];
47
+ const context = await buildExistingMilestonesContext(tmpBase, milestoneIds, state);
48
+
49
+ // draft-only milestone includes "Draft context available"
50
+ assert.ok(
51
+ context.includes("Draft context available"),
52
+ "M001 (draft-only) should include 'Draft context available' label",
53
+ );
54
+ assert.ok(
55
+ context.includes("Seed material from prior discussion"),
56
+ "M001 draft content should be included in context output",
57
+ );
58
+
59
+ // full-context milestone uses "Context:" label
60
+ assert.ok(
61
+ context.includes("**Context:**"),
62
+ "M002 (full context) should use 'Context:' label",
63
+ );
64
+ assert.ok(
65
+ context.includes("Full context from deep discussion"),
66
+ "M002 context content should be included",
67
+ );
68
+
69
+ // both files: CONTEXT.md wins, no draft label
70
+ const m003Idx = context.indexOf("M003:");
71
+ const m003Section = context.slice(m003Idx, m003Idx + 500);
72
+ assert.ok(
73
+ m003Section.includes("**Context:**"),
74
+ "M003 (both files) should use 'Context:' label (CONTEXT.md wins)",
75
+ );
76
+ assert.ok(
77
+ !m003Section.includes("Draft context available"),
78
+ "M003 (both files) should NOT show draft label — CONTEXT.md takes precedence",
79
+ );
80
+ assert.ok(
81
+ m003Section.includes("This is the real context"),
82
+ "M003 should show CONTEXT.md content, not draft content",
83
+ );
84
+
85
+ // neither file: no context section
86
+ const m004Idx = context.indexOf("M004:");
87
+ const m004Section = context.slice(m004Idx, m004Idx + 500);
88
+ assert.ok(
89
+ !m004Section.includes("**Context:**"),
90
+ "M004 (neither file) should not have Context: label",
91
+ );
92
+ assert.ok(
93
+ !m004Section.includes("Draft context available"),
94
+ "M004 (neither file) should not have Draft label",
95
+ );
96
+ } finally {
97
+ rmSync(tmpBase, { recursive: true, force: true });
98
+ }
99
+ });
100
+ });