gsd-pi 2.44.0-dev.848dd4c → 2.44.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (298) hide show
  1. package/README.md +12 -30
  2. package/dist/resources/extensions/gsd/auto-start.js +0 -10
  3. package/dist/resources/extensions/gsd/commands/handlers/workflow.js +0 -5
  4. package/dist/web/standalone/.next/BUILD_ID +1 -1
  5. package/dist/web/standalone/.next/app-path-routes-manifest.json +14 -14
  6. package/dist/web/standalone/.next/build-manifest.json +3 -3
  7. package/dist/web/standalone/.next/prerender-manifest.json +3 -3
  8. package/dist/web/standalone/.next/required-server-files.json +3 -3
  9. package/dist/web/standalone/.next/server/app/_global-error/page.js +3 -3
  10. package/dist/web/standalone/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
  11. package/dist/web/standalone/.next/server/app/_global-error.html +2 -2
  12. package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
  13. package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  14. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
  15. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
  16. package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  17. package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  18. package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  19. package/dist/web/standalone/.next/server/app/_not-found/page.js +2 -2
  20. package/dist/web/standalone/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  21. package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
  22. package/dist/web/standalone/.next/server/app/_not-found.rsc +3 -3
  23. package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +3 -3
  24. package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  25. package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +3 -3
  26. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  27. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  28. package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
  29. package/dist/web/standalone/.next/server/app/api/boot/route.js +1 -1
  30. package/dist/web/standalone/.next/server/app/api/boot/route_client-reference-manifest.js +1 -1
  31. package/dist/web/standalone/.next/server/app/api/bridge-terminal/input/route.js +1 -1
  32. package/dist/web/standalone/.next/server/app/api/bridge-terminal/input/route_client-reference-manifest.js +1 -1
  33. package/dist/web/standalone/.next/server/app/api/bridge-terminal/resize/route.js +1 -1
  34. package/dist/web/standalone/.next/server/app/api/bridge-terminal/resize/route_client-reference-manifest.js +1 -1
  35. package/dist/web/standalone/.next/server/app/api/bridge-terminal/stream/route.js +2 -2
  36. package/dist/web/standalone/.next/server/app/api/bridge-terminal/stream/route_client-reference-manifest.js +1 -1
  37. package/dist/web/standalone/.next/server/app/api/browse-directories/route.js +1 -1
  38. package/dist/web/standalone/.next/server/app/api/browse-directories/route_client-reference-manifest.js +1 -1
  39. package/dist/web/standalone/.next/server/app/api/captures/route.js +1 -1
  40. package/dist/web/standalone/.next/server/app/api/captures/route_client-reference-manifest.js +1 -1
  41. package/dist/web/standalone/.next/server/app/api/cleanup/route.js +1 -1
  42. package/dist/web/standalone/.next/server/app/api/cleanup/route_client-reference-manifest.js +1 -1
  43. package/dist/web/standalone/.next/server/app/api/dev-mode/route.js +1 -1
  44. package/dist/web/standalone/.next/server/app/api/dev-mode/route_client-reference-manifest.js +1 -1
  45. package/dist/web/standalone/.next/server/app/api/doctor/route.js +1 -1
  46. package/dist/web/standalone/.next/server/app/api/doctor/route_client-reference-manifest.js +1 -1
  47. package/dist/web/standalone/.next/server/app/api/export-data/route.js +1 -1
  48. package/dist/web/standalone/.next/server/app/api/export-data/route_client-reference-manifest.js +1 -1
  49. package/dist/web/standalone/.next/server/app/api/files/route.js +1 -1
  50. package/dist/web/standalone/.next/server/app/api/files/route_client-reference-manifest.js +1 -1
  51. package/dist/web/standalone/.next/server/app/api/forensics/route.js +1 -1
  52. package/dist/web/standalone/.next/server/app/api/forensics/route_client-reference-manifest.js +1 -1
  53. package/dist/web/standalone/.next/server/app/api/git/route.js +1 -1
  54. package/dist/web/standalone/.next/server/app/api/git/route_client-reference-manifest.js +1 -1
  55. package/dist/web/standalone/.next/server/app/api/history/route.js +1 -1
  56. package/dist/web/standalone/.next/server/app/api/history/route_client-reference-manifest.js +1 -1
  57. package/dist/web/standalone/.next/server/app/api/hooks/route.js +1 -1
  58. package/dist/web/standalone/.next/server/app/api/hooks/route_client-reference-manifest.js +1 -1
  59. package/dist/web/standalone/.next/server/app/api/inspect/route.js +1 -1
  60. package/dist/web/standalone/.next/server/app/api/inspect/route_client-reference-manifest.js +1 -1
  61. package/dist/web/standalone/.next/server/app/api/knowledge/route.js +1 -1
  62. package/dist/web/standalone/.next/server/app/api/knowledge/route_client-reference-manifest.js +1 -1
  63. package/dist/web/standalone/.next/server/app/api/live-state/route.js +1 -1
  64. package/dist/web/standalone/.next/server/app/api/live-state/route_client-reference-manifest.js +1 -1
  65. package/dist/web/standalone/.next/server/app/api/onboarding/route.js +1 -1
  66. package/dist/web/standalone/.next/server/app/api/onboarding/route_client-reference-manifest.js +1 -1
  67. package/dist/web/standalone/.next/server/app/api/preferences/route.js +1 -1
  68. package/dist/web/standalone/.next/server/app/api/preferences/route_client-reference-manifest.js +1 -1
  69. package/dist/web/standalone/.next/server/app/api/projects/route.js +1 -1
  70. package/dist/web/standalone/.next/server/app/api/projects/route_client-reference-manifest.js +1 -1
  71. package/dist/web/standalone/.next/server/app/api/recovery/route.js +1 -1
  72. package/dist/web/standalone/.next/server/app/api/recovery/route_client-reference-manifest.js +1 -1
  73. package/dist/web/standalone/.next/server/app/api/remote-questions/route.js +5 -5
  74. package/dist/web/standalone/.next/server/app/api/remote-questions/route_client-reference-manifest.js +1 -1
  75. package/dist/web/standalone/.next/server/app/api/session/browser/route.js +1 -1
  76. package/dist/web/standalone/.next/server/app/api/session/browser/route_client-reference-manifest.js +1 -1
  77. package/dist/web/standalone/.next/server/app/api/session/command/route.js +1 -1
  78. package/dist/web/standalone/.next/server/app/api/session/command/route_client-reference-manifest.js +1 -1
  79. package/dist/web/standalone/.next/server/app/api/session/events/route.js +2 -2
  80. package/dist/web/standalone/.next/server/app/api/session/events/route_client-reference-manifest.js +1 -1
  81. package/dist/web/standalone/.next/server/app/api/session/manage/route.js +1 -1
  82. package/dist/web/standalone/.next/server/app/api/session/manage/route_client-reference-manifest.js +1 -1
  83. package/dist/web/standalone/.next/server/app/api/settings-data/route.js +1 -1
  84. package/dist/web/standalone/.next/server/app/api/settings-data/route_client-reference-manifest.js +1 -1
  85. package/dist/web/standalone/.next/server/app/api/shutdown/route.js +1 -1
  86. package/dist/web/standalone/.next/server/app/api/shutdown/route_client-reference-manifest.js +1 -1
  87. package/dist/web/standalone/.next/server/app/api/skill-health/route.js +1 -1
  88. package/dist/web/standalone/.next/server/app/api/skill-health/route_client-reference-manifest.js +1 -1
  89. package/dist/web/standalone/.next/server/app/api/steer/route.js +1 -1
  90. package/dist/web/standalone/.next/server/app/api/steer/route_client-reference-manifest.js +1 -1
  91. package/dist/web/standalone/.next/server/app/api/switch-root/route.js +1 -1
  92. package/dist/web/standalone/.next/server/app/api/switch-root/route_client-reference-manifest.js +1 -1
  93. package/dist/web/standalone/.next/server/app/api/terminal/input/route.js +2 -2
  94. package/dist/web/standalone/.next/server/app/api/terminal/input/route_client-reference-manifest.js +1 -1
  95. package/dist/web/standalone/.next/server/app/api/terminal/resize/route.js +2 -2
  96. package/dist/web/standalone/.next/server/app/api/terminal/resize/route_client-reference-manifest.js +1 -1
  97. package/dist/web/standalone/.next/server/app/api/terminal/sessions/route.js +2 -2
  98. package/dist/web/standalone/.next/server/app/api/terminal/sessions/route_client-reference-manifest.js +1 -1
  99. package/dist/web/standalone/.next/server/app/api/terminal/stream/route.js +4 -4
  100. package/dist/web/standalone/.next/server/app/api/terminal/stream/route_client-reference-manifest.js +1 -1
  101. package/dist/web/standalone/.next/server/app/api/terminal/upload/route.js +1 -1
  102. package/dist/web/standalone/.next/server/app/api/terminal/upload/route_client-reference-manifest.js +1 -1
  103. package/dist/web/standalone/.next/server/app/api/undo/route.js +1 -1
  104. package/dist/web/standalone/.next/server/app/api/undo/route_client-reference-manifest.js +1 -1
  105. package/dist/web/standalone/.next/server/app/api/update/route.js +1 -1
  106. package/dist/web/standalone/.next/server/app/api/update/route_client-reference-manifest.js +1 -1
  107. package/dist/web/standalone/.next/server/app/api/visualizer/route.js +1 -1
  108. package/dist/web/standalone/.next/server/app/api/visualizer/route_client-reference-manifest.js +1 -1
  109. package/dist/web/standalone/.next/server/app/index.html +1 -1
  110. package/dist/web/standalone/.next/server/app/index.rsc +4 -4
  111. package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +2 -2
  112. package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +4 -4
  113. package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
  114. package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +3 -3
  115. package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
  116. package/dist/web/standalone/.next/server/app/page.js +2 -2
  117. package/dist/web/standalone/.next/server/app/page_client-reference-manifest.js +1 -1
  118. package/dist/web/standalone/.next/server/app-paths-manifest.json +14 -14
  119. package/dist/web/standalone/.next/server/chunks/229.js +1 -1
  120. package/dist/web/standalone/.next/server/chunks/471.js +3 -3
  121. package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
  122. package/dist/web/standalone/.next/server/middleware.js +2 -2
  123. package/dist/web/standalone/.next/server/next-font-manifest.js +1 -1
  124. package/dist/web/standalone/.next/server/next-font-manifest.json +1 -1
  125. package/dist/web/standalone/.next/server/pages/404.html +1 -1
  126. package/dist/web/standalone/.next/server/pages/500.html +2 -2
  127. package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
  128. package/dist/web/standalone/.next/static/chunks/app/_not-found/{page-f2a7482d42a5614b.js → page-2f24283c162b6ab3.js} +1 -1
  129. package/dist/web/standalone/.next/static/chunks/app/{layout-a16c7a7ecdf0c2cf.js → layout-9ecfd95f343793f0.js} +1 -1
  130. package/dist/web/standalone/.next/static/chunks/app/page-7e9530a7122506c5.js +1 -0
  131. package/dist/web/standalone/.next/static/chunks/main-app-d3d4c336195465f9.js +1 -0
  132. package/dist/web/standalone/.next/static/chunks/next/dist/client/components/builtin/global-error-ab5a8926e07ec673.js +1 -0
  133. package/dist/web/standalone/node_modules/node-pty/build/Makefile +2 -2
  134. package/dist/web/standalone/node_modules/node-pty/build/Release/pty.node +0 -0
  135. package/dist/web/standalone/node_modules/node-pty/build/pty.target.mk +14 -14
  136. package/dist/web/standalone/node_modules/node-pty/node-addon-api/node_addon_api.target.mk +14 -14
  137. package/dist/web/standalone/node_modules/node-pty/node-addon-api/node_addon_api_except.target.mk +14 -14
  138. package/dist/web/standalone/node_modules/node-pty/node-addon-api/node_addon_api_maybe.target.mk +14 -14
  139. package/dist/web/standalone/server.js +1 -1
  140. package/package.json +1 -1
  141. package/packages/pi-coding-agent/dist/core/auth-storage.test.js +8 -6
  142. package/packages/pi-coding-agent/dist/core/auth-storage.test.js.map +1 -1
  143. package/packages/pi-coding-agent/dist/core/extensions/runner.test.js +26 -24
  144. package/packages/pi-coding-agent/dist/core/extensions/runner.test.js.map +1 -1
  145. package/packages/pi-coding-agent/dist/core/fs-utils.test.js +48 -29
  146. package/packages/pi-coding-agent/dist/core/fs-utils.test.js.map +1 -1
  147. package/packages/pi-coding-agent/dist/core/resolve-config-value.test.js +44 -34
  148. package/packages/pi-coding-agent/dist/core/resolve-config-value.test.js.map +1 -1
  149. package/packages/pi-coding-agent/dist/core/session-manager.test.js +34 -30
  150. package/packages/pi-coding-agent/dist/core/session-manager.test.js.map +1 -1
  151. package/packages/pi-coding-agent/dist/core/tools/edit-diff.test.js +12 -10
  152. package/packages/pi-coding-agent/dist/core/tools/edit-diff.test.js.map +1 -1
  153. package/packages/pi-coding-agent/dist/resources/extensions/memory/storage.test.js +47 -43
  154. package/packages/pi-coding-agent/dist/resources/extensions/memory/storage.test.js.map +1 -1
  155. package/packages/pi-coding-agent/src/core/auth-storage.test.ts +7 -7
  156. package/packages/pi-coding-agent/src/core/extensions/runner.test.ts +26 -26
  157. package/packages/pi-coding-agent/src/core/fs-utils.test.ts +43 -31
  158. package/packages/pi-coding-agent/src/core/resolve-config-value.test.ts +45 -40
  159. package/packages/pi-coding-agent/src/core/session-manager.test.ts +33 -33
  160. package/packages/pi-coding-agent/src/core/tools/edit-diff.test.ts +17 -17
  161. package/packages/pi-coding-agent/src/resources/extensions/memory/storage.test.ts +74 -74
  162. package/src/resources/extensions/gsd/auto-start.ts +0 -14
  163. package/src/resources/extensions/gsd/commands/handlers/workflow.ts +0 -8
  164. package/src/resources/extensions/gsd/tests/all-milestones-complete-merge.test.ts +99 -99
  165. package/src/resources/extensions/gsd/tests/auto-lock-creation.test.ts +16 -14
  166. package/src/resources/extensions/gsd/tests/auto-paused-session-validation.test.ts +57 -43
  167. package/src/resources/extensions/gsd/tests/auto-preflight.test.ts +13 -11
  168. package/src/resources/extensions/gsd/tests/auto-recovery.test.ts +523 -465
  169. package/src/resources/extensions/gsd/tests/auto-secrets-gate.test.ts +75 -73
  170. package/src/resources/extensions/gsd/tests/auto-start-needs-discussion.test.ts +56 -34
  171. package/src/resources/extensions/gsd/tests/auto-worktree-milestone-merge.test.ts +656 -533
  172. package/src/resources/extensions/gsd/tests/auto-worktree.test.ts +143 -165
  173. package/src/resources/extensions/gsd/tests/cache-staleness-regression.test.ts +52 -29
  174. package/src/resources/extensions/gsd/tests/captures.test.ts +176 -148
  175. package/src/resources/extensions/gsd/tests/claude-import-tui.test.ts +33 -32
  176. package/src/resources/extensions/gsd/tests/collect-from-manifest.test.ts +143 -141
  177. package/src/resources/extensions/gsd/tests/commands-inspect-open-db.test.ts +25 -25
  178. package/src/resources/extensions/gsd/tests/commands-logs.test.ts +81 -81
  179. package/src/resources/extensions/gsd/tests/complete-milestone.test.ts +59 -38
  180. package/src/resources/extensions/gsd/tests/complete-slice.test.ts +263 -228
  181. package/src/resources/extensions/gsd/tests/complete-task.test.ts +302 -250
  182. package/src/resources/extensions/gsd/tests/context-store.test.ts +367 -354
  183. package/src/resources/extensions/gsd/tests/continue-here.test.ts +72 -68
  184. package/src/resources/extensions/gsd/tests/cost-projection.test.ts +106 -92
  185. package/src/resources/extensions/gsd/tests/crash-recovery.test.ts +35 -27
  186. package/src/resources/extensions/gsd/tests/dashboard-budget.test.ts +237 -220
  187. package/src/resources/extensions/gsd/tests/db-writer.test.ts +420 -390
  188. package/src/resources/extensions/gsd/tests/definition-loader.test.ts +92 -76
  189. package/src/resources/extensions/gsd/tests/derive-state-crossval.test.ts +83 -68
  190. package/src/resources/extensions/gsd/tests/derive-state-db.test.ts +183 -152
  191. package/src/resources/extensions/gsd/tests/derive-state-deps.test.ts +101 -78
  192. package/src/resources/extensions/gsd/tests/derive-state.test.ts +227 -192
  193. package/src/resources/extensions/gsd/tests/detection.test.ts +278 -232
  194. package/src/resources/extensions/gsd/tests/dev-engine-wrapper.test.ts +34 -30
  195. package/src/resources/extensions/gsd/tests/dispatch-guard.test.ts +180 -164
  196. package/src/resources/extensions/gsd/tests/dispatch-missing-task-plans.test.ts +49 -43
  197. package/src/resources/extensions/gsd/tests/dispatch-uat-last-completed.test.ts +32 -28
  198. package/src/resources/extensions/gsd/tests/doctor-completion-deferral.test.ts +29 -27
  199. package/src/resources/extensions/gsd/tests/doctor-delimiter-fix.test.ts +38 -34
  200. package/src/resources/extensions/gsd/tests/doctor-enhancements.test.ts +75 -54
  201. package/src/resources/extensions/gsd/tests/doctor-environment-worktree.test.ts +32 -21
  202. package/src/resources/extensions/gsd/tests/doctor-environment.test.ts +97 -72
  203. package/src/resources/extensions/gsd/tests/doctor-fixlevel.test.ts +44 -38
  204. package/src/resources/extensions/gsd/tests/doctor-git.test.ts +145 -104
  205. package/src/resources/extensions/gsd/tests/doctor-proactive.test.ts +106 -84
  206. package/src/resources/extensions/gsd/tests/doctor-roadmap-summary-atomicity.test.ts +60 -54
  207. package/src/resources/extensions/gsd/tests/doctor-runtime.test.ts +93 -72
  208. package/src/resources/extensions/gsd/tests/doctor.test.ts +134 -104
  209. package/src/resources/extensions/gsd/tests/ensure-db-open.test.ts +131 -123
  210. package/src/resources/extensions/gsd/tests/exit-command.test.ts +24 -20
  211. package/src/resources/extensions/gsd/tests/feature-branch-lifecycle-integration.test.ts +57 -48
  212. package/src/resources/extensions/gsd/tests/files-loadfile-eisdir.test.ts +7 -5
  213. package/src/resources/extensions/gsd/tests/flag-file-db.test.ts +42 -30
  214. package/src/resources/extensions/gsd/tests/freeform-decisions.test.ts +206 -198
  215. package/src/resources/extensions/gsd/tests/git-locale.test.ts +27 -13
  216. package/src/resources/extensions/gsd/tests/git-service.test.ts +388 -285
  217. package/src/resources/extensions/gsd/tests/gitignore-tracked-gsd.test.ts +39 -31
  218. package/src/resources/extensions/gsd/tests/graph-operations.test.ts +69 -63
  219. package/src/resources/extensions/gsd/tests/gsd-db.test.ts +264 -255
  220. package/src/resources/extensions/gsd/tests/gsd-inspect.test.ts +119 -108
  221. package/src/resources/extensions/gsd/tests/gsd-recover.test.ts +103 -81
  222. package/src/resources/extensions/gsd/tests/gsd-tools.test.ts +262 -229
  223. package/src/resources/extensions/gsd/tests/headless-answers.test.ts +13 -13
  224. package/src/resources/extensions/gsd/tests/health-widget.test.ts +37 -29
  225. package/src/resources/extensions/gsd/tests/idle-recovery.test.ts +102 -81
  226. package/src/resources/extensions/gsd/tests/init-wizard.test.ts +18 -16
  227. package/src/resources/extensions/gsd/tests/integration-edge.test.ts +46 -41
  228. package/src/resources/extensions/gsd/tests/integration-lifecycle.test.ts +53 -42
  229. package/src/resources/extensions/gsd/tests/integration-mixed-milestones.test.ts +91 -75
  230. package/src/resources/extensions/gsd/tests/integration-proof.test.ts +18 -18
  231. package/src/resources/extensions/gsd/tests/markdown-renderer.test.ts +194 -150
  232. package/src/resources/extensions/gsd/tests/md-importer.test.ts +125 -101
  233. package/src/resources/extensions/gsd/tests/memory-extractor.test.ts +54 -45
  234. package/src/resources/extensions/gsd/tests/memory-store.test.ts +93 -80
  235. package/src/resources/extensions/gsd/tests/migrate-command.test.ts +66 -57
  236. package/src/resources/extensions/gsd/tests/migrate-hierarchy.test.ts +93 -83
  237. package/src/resources/extensions/gsd/tests/migrate-parser.test.ts +170 -161
  238. package/src/resources/extensions/gsd/tests/migrate-transformer.test.ts +141 -125
  239. package/src/resources/extensions/gsd/tests/migrate-validator-parsers.test.ts +131 -107
  240. package/src/resources/extensions/gsd/tests/migrate-writer-integration.test.ts +96 -87
  241. package/src/resources/extensions/gsd/tests/migrate-writer.test.ts +164 -125
  242. package/src/resources/extensions/gsd/tests/must-have-parser.test.ts +94 -81
  243. package/src/resources/extensions/gsd/tests/none-mode-gates.test.ts +36 -35
  244. package/src/resources/extensions/gsd/tests/overrides.test.ts +106 -99
  245. package/src/resources/extensions/gsd/tests/parallel-crash-recovery.test.ts +47 -40
  246. package/src/resources/extensions/gsd/tests/parallel-worker-monitoring.test.ts +28 -25
  247. package/src/resources/extensions/gsd/tests/parallel-workers-multi-milestone-e2e.test.ts +83 -66
  248. package/src/resources/extensions/gsd/tests/park-edge-cases.test.ts +77 -54
  249. package/src/resources/extensions/gsd/tests/park-milestone.test.ts +115 -68
  250. package/src/resources/extensions/gsd/tests/parsers.test.ts +611 -546
  251. package/src/resources/extensions/gsd/tests/paths.test.ts +87 -72
  252. package/src/resources/extensions/gsd/tests/post-unit-hooks.test.ts +117 -77
  253. package/src/resources/extensions/gsd/tests/prompt-db.test.ts +56 -56
  254. package/src/resources/extensions/gsd/tests/queue-draft-detection.test.ts +119 -93
  255. package/src/resources/extensions/gsd/tests/queue-order.test.ts +82 -70
  256. package/src/resources/extensions/gsd/tests/queue-reorder-e2e.test.ts +55 -42
  257. package/src/resources/extensions/gsd/tests/quick-branch-lifecycle.test.ts +73 -45
  258. package/src/resources/extensions/gsd/tests/reassess-prompt.test.ts +38 -28
  259. package/src/resources/extensions/gsd/tests/replan-slice.test.ts +80 -73
  260. package/src/resources/extensions/gsd/tests/repo-identity-worktree.test.ts +74 -71
  261. package/src/resources/extensions/gsd/tests/requirements.test.ts +75 -70
  262. package/src/resources/extensions/gsd/tests/retry-state-reset.test.ts +66 -44
  263. package/src/resources/extensions/gsd/tests/roadmap-parse-regression.test.ts +181 -114
  264. package/src/resources/extensions/gsd/tests/rule-registry.test.ts +65 -63
  265. package/src/resources/extensions/gsd/tests/run-uat.test.ts +128 -66
  266. package/src/resources/extensions/gsd/tests/session-lock-multipath.test.ts +25 -18
  267. package/src/resources/extensions/gsd/tests/session-lock-regression.test.ts +44 -37
  268. package/src/resources/extensions/gsd/tests/shared-wal.test.ts +26 -19
  269. package/src/resources/extensions/gsd/tests/stalled-tool-recovery.test.ts +8 -6
  270. package/src/resources/extensions/gsd/tests/symlink-numbered-variants.test.ts +28 -22
  271. package/src/resources/extensions/gsd/tests/token-savings.test.ts +56 -54
  272. package/src/resources/extensions/gsd/tests/tool-call-loop-guard.test.ts +25 -23
  273. package/src/resources/extensions/gsd/tests/tool-naming.test.ts +11 -9
  274. package/src/resources/extensions/gsd/tests/unique-milestone-ids.test.ts +82 -66
  275. package/src/resources/extensions/gsd/tests/unit-runtime.test.ts +47 -46
  276. package/src/resources/extensions/gsd/tests/visualizer-critical-path.test.ts +22 -20
  277. package/src/resources/extensions/gsd/tests/visualizer-data.test.ts +86 -84
  278. package/src/resources/extensions/gsd/tests/visualizer-overlay.test.ts +43 -41
  279. package/src/resources/extensions/gsd/tests/visualizer-views.test.ts +96 -94
  280. package/src/resources/extensions/gsd/tests/windows-path-normalization.test.ts +13 -11
  281. package/src/resources/extensions/gsd/tests/worker-registry.test.ts +29 -27
  282. package/src/resources/extensions/gsd/tests/workflow-templates.test.ts +52 -50
  283. package/src/resources/extensions/gsd/tests/worktree-bugfix.test.ts +13 -10
  284. package/src/resources/extensions/gsd/tests/worktree-db-integration.test.ts +18 -14
  285. package/src/resources/extensions/gsd/tests/worktree-db.test.ts +39 -38
  286. package/src/resources/extensions/gsd/tests/worktree-e2e.test.ts +21 -17
  287. package/src/resources/extensions/gsd/tests/worktree-health.test.ts +30 -25
  288. package/src/resources/extensions/gsd/tests/worktree-integration.test.ts +37 -30
  289. package/src/resources/extensions/gsd/tests/worktree-symlink-removal.test.ts +22 -15
  290. package/src/resources/extensions/gsd/tests/worktree-sync-milestones.test.ts +66 -59
  291. package/src/resources/extensions/gsd/tests/worktree.test.ts +50 -44
  292. package/dist/web/standalone/.next/static/chunks/app/page-b9367c5ae13b99c6.js +0 -1
  293. package/dist/web/standalone/.next/static/chunks/main-app-fdab67f7802d7832.js +0 -1
  294. package/dist/web/standalone/.next/static/chunks/next/dist/client/components/builtin/global-error-459824ffb8c323dd.js +0 -1
  295. package/src/resources/extensions/gsd/tests/quick-auto-guard.test.ts +0 -100
  296. package/src/resources/extensions/gsd/tests/sqlite-unavailable-gate.test.ts +0 -63
  297. /package/dist/web/standalone/.next/static/{-zps1Q9mQmioAKLcQiCr8 → mgkxN0mGP6gSUmGPEzbk_}/_buildManifest.js +0 -0
  298. /package/dist/web/standalone/.next/static/{-zps1Q9mQmioAKLcQiCr8 → mgkxN0mGP6gSUmGPEzbk_}/_ssgManifest.js +0 -0
@@ -1,5 +1,4 @@
1
- import { describe, test, afterEach } from "node:test";
2
- import assert from "node:assert/strict";
1
+ import { createTestContext } from './test-helpers.ts';
3
2
  import {
4
3
  openDatabase,
5
4
  closeDatabase,
@@ -17,438 +16,452 @@ import {
17
16
  queryProject,
18
17
  } from '../context-store.ts';
19
18
 
19
+ const { assertEq, assertTrue, assertMatch, report } = createTestContext();
20
+
20
21
  // ═══════════════════════════════════════════════════════════════════════════
21
22
  // context-store: fallback when DB not open
22
23
  // ═══════════════════════════════════════════════════════════════════════════
23
24
 
24
- describe("context-store: fallback when DB not open", () => {
25
- test("returns empty when DB not open", () => {
26
- closeDatabase();
27
- assert.ok(!isDbAvailable(), 'DB should not be available');
25
+ console.log('\n=== context-store: fallback returns empty when DB not open ===');
26
+ {
27
+ closeDatabase();
28
+ assertTrue(!isDbAvailable(), 'DB should not be available');
28
29
 
29
- const d = queryDecisions();
30
- assert.deepStrictEqual(d, [], 'queryDecisions returns [] when DB closed');
30
+ const d = queryDecisions();
31
+ assertEq(d, [], 'queryDecisions returns [] when DB closed');
31
32
 
32
- const r = queryRequirements();
33
- assert.deepStrictEqual(r, [], 'queryRequirements returns [] when DB closed');
33
+ const r = queryRequirements();
34
+ assertEq(r, [], 'queryRequirements returns [] when DB closed');
34
35
 
35
- const df = queryDecisions({ milestoneId: 'M001' });
36
- assert.deepStrictEqual(df, [], 'queryDecisions with opts returns [] when DB closed');
36
+ const df = queryDecisions({ milestoneId: 'M001' });
37
+ assertEq(df, [], 'queryDecisions with opts returns [] when DB closed');
37
38
 
38
- const rf = queryRequirements({ sliceId: 'S01' });
39
- assert.deepStrictEqual(rf, [], 'queryRequirements with opts returns [] when DB closed');
40
- });
41
- });
39
+ const rf = queryRequirements({ sliceId: 'S01' });
40
+ assertEq(rf, [], 'queryRequirements with opts returns [] when DB closed');
41
+ }
42
42
 
43
43
  // ═══════════════════════════════════════════════════════════════════════════
44
44
  // context-store: query decisions
45
45
  // ═══════════════════════════════════════════════════════════════════════════
46
46
 
47
- describe("context-store: query decisions", () => {
48
- afterEach(() => closeDatabase());
47
+ console.log('\n=== context-store: query all active decisions ===');
48
+ {
49
+ openDatabase(':memory:');
49
50
 
50
- test("query all active decisions", () => {
51
- openDatabase(':memory:');
52
-
53
- insertDecision({
54
- id: 'D001', when_context: 'M001/S01', scope: 'architecture',
55
- decision: 'use SQLite', choice: 'node:sqlite', rationale: 'built-in',
56
- revisable: 'yes', made_by: 'agent', superseded_by: 'D003', // superseded!
57
- });
58
- insertDecision({
59
- id: 'D002', when_context: 'M001/S01', scope: 'architecture',
60
- decision: 'use WAL mode', choice: 'WAL', rationale: 'concurrent reads',
61
- revisable: 'no', made_by: 'agent', superseded_by: null,
62
- });
63
- insertDecision({
64
- id: 'D003', when_context: 'M002/S01', scope: 'performance',
65
- decision: 'use better-sqlite3', choice: 'better-sqlite3', rationale: 'faster',
66
- revisable: 'yes', made_by: 'agent', superseded_by: null,
67
- });
51
+ insertDecision({
52
+ id: 'D001', when_context: 'M001/S01', scope: 'architecture',
53
+ decision: 'use SQLite', choice: 'node:sqlite', rationale: 'built-in',
54
+ revisable: 'yes', made_by: 'agent', superseded_by: 'D003', // superseded!
55
+ });
56
+ insertDecision({
57
+ id: 'D002', when_context: 'M001/S01', scope: 'architecture',
58
+ decision: 'use WAL mode', choice: 'WAL', rationale: 'concurrent reads',
59
+ revisable: 'no', made_by: 'agent', superseded_by: null,
60
+ });
61
+ insertDecision({
62
+ id: 'D003', when_context: 'M002/S01', scope: 'performance',
63
+ decision: 'use better-sqlite3', choice: 'better-sqlite3', rationale: 'faster',
64
+ revisable: 'yes', made_by: 'agent', superseded_by: null,
65
+ });
68
66
 
69
- const all = queryDecisions();
70
- assert.strictEqual(all.length, 2, 'query all active decisions returns 2 (superseded excluded)');
71
- const ids = all.map(d => d.id);
72
- assert.ok(ids.includes('D002'), 'D002 should be in active results');
73
- assert.ok(ids.includes('D003'), 'D003 should be in active results');
74
- assert.ok(!ids.includes('D001'), 'D001 (superseded) should NOT be in active results');
67
+ const all = queryDecisions();
68
+ assertEq(all.length, 2, 'query all active decisions returns 2 (superseded excluded)');
69
+ const ids = all.map(d => d.id);
70
+ assertTrue(ids.includes('D002'), 'D002 should be in active results');
71
+ assertTrue(ids.includes('D003'), 'D003 should be in active results');
72
+ assertTrue(!ids.includes('D001'), 'D001 (superseded) should NOT be in active results');
73
+
74
+ closeDatabase();
75
+ }
76
+
77
+ console.log('\n=== context-store: query decisions by milestone ===');
78
+ {
79
+ openDatabase(':memory:');
80
+
81
+ insertDecision({
82
+ id: 'D001', when_context: 'M001/S01', scope: 'architecture',
83
+ decision: 'decision A', choice: 'A', rationale: 'r', revisable: 'yes',
84
+ made_by: 'agent',
85
+ superseded_by: null,
86
+ });
87
+ insertDecision({
88
+ id: 'D002', when_context: 'M002/S02', scope: 'architecture',
89
+ decision: 'decision B', choice: 'B', rationale: 'r', revisable: 'yes',
90
+ made_by: 'agent',
91
+ superseded_by: null,
75
92
  });
76
93
 
77
- test("query decisions by milestone", () => {
78
- openDatabase(':memory:');
94
+ const m1 = queryDecisions({ milestoneId: 'M001' });
95
+ assertEq(m1.length, 1, 'milestone filter M001 returns 1');
96
+ assertEq(m1[0]?.id, 'D001', 'milestone filter returns D001');
79
97
 
80
- insertDecision({
81
- id: 'D001', when_context: 'M001/S01', scope: 'architecture',
82
- decision: 'decision A', choice: 'A', rationale: 'r', revisable: 'yes',
83
- made_by: 'agent',
84
- superseded_by: null,
85
- });
86
- insertDecision({
87
- id: 'D002', when_context: 'M002/S02', scope: 'architecture',
88
- decision: 'decision B', choice: 'B', rationale: 'r', revisable: 'yes',
89
- made_by: 'agent',
90
- superseded_by: null,
91
- });
98
+ const m2 = queryDecisions({ milestoneId: 'M002' });
99
+ assertEq(m2.length, 1, 'milestone filter M002 returns 1');
100
+ assertEq(m2[0]?.id, 'D002', 'milestone filter returns D002');
92
101
 
93
- const m1 = queryDecisions({ milestoneId: 'M001' });
94
- assert.strictEqual(m1.length, 1, 'milestone filter M001 returns 1');
95
- assert.strictEqual(m1[0]?.id, 'D001', 'milestone filter returns D001');
102
+ closeDatabase();
103
+ }
96
104
 
97
- const m2 = queryDecisions({ milestoneId: 'M002' });
98
- assert.strictEqual(m2.length, 1, 'milestone filter M002 returns 1');
99
- assert.strictEqual(m2[0]?.id, 'D002', 'milestone filter returns D002');
100
- });
105
+ console.log('\n=== context-store: query decisions by scope ===');
106
+ {
107
+ openDatabase(':memory:');
101
108
 
102
- test("query decisions by scope", () => {
103
- openDatabase(':memory:');
109
+ insertDecision({
110
+ id: 'D001', when_context: 'M001/S01', scope: 'architecture',
111
+ decision: 'decision A', choice: 'A', rationale: 'r', revisable: 'yes',
112
+ made_by: 'agent',
113
+ superseded_by: null,
114
+ });
115
+ insertDecision({
116
+ id: 'D002', when_context: 'M001/S01', scope: 'performance',
117
+ decision: 'decision B', choice: 'B', rationale: 'r', revisable: 'yes',
118
+ made_by: 'agent',
119
+ superseded_by: null,
120
+ });
104
121
 
105
- insertDecision({
106
- id: 'D001', when_context: 'M001/S01', scope: 'architecture',
107
- decision: 'decision A', choice: 'A', rationale: 'r', revisable: 'yes',
108
- made_by: 'agent',
109
- superseded_by: null,
110
- });
111
- insertDecision({
112
- id: 'D002', when_context: 'M001/S01', scope: 'performance',
113
- decision: 'decision B', choice: 'B', rationale: 'r', revisable: 'yes',
114
- made_by: 'agent',
115
- superseded_by: null,
116
- });
122
+ const arch = queryDecisions({ scope: 'architecture' });
123
+ assertEq(arch.length, 1, 'scope filter architecture returns 1');
124
+ assertEq(arch[0]?.id, 'D001', 'scope filter returns D001');
117
125
 
118
- const arch = queryDecisions({ scope: 'architecture' });
119
- assert.strictEqual(arch.length, 1, 'scope filter architecture returns 1');
120
- assert.strictEqual(arch[0]?.id, 'D001', 'scope filter returns D001');
126
+ const perf = queryDecisions({ scope: 'performance' });
127
+ assertEq(perf.length, 1, 'scope filter performance returns 1');
128
+ assertEq(perf[0]?.id, 'D002', 'scope filter returns D002');
121
129
 
122
- const perf = queryDecisions({ scope: 'performance' });
123
- assert.strictEqual(perf.length, 1, 'scope filter performance returns 1');
124
- assert.strictEqual(perf[0]?.id, 'D002', 'scope filter returns D002');
130
+ const none = queryDecisions({ scope: 'nonexistent' });
131
+ assertEq(none.length, 0, 'scope filter nonexistent returns 0');
125
132
 
126
- const none = queryDecisions({ scope: 'nonexistent' });
127
- assert.strictEqual(none.length, 0, 'scope filter nonexistent returns 0');
128
- });
129
- });
133
+ closeDatabase();
134
+ }
130
135
 
131
136
  // ═══════════════════════════════════════════════════════════════════════════
132
137
  // context-store: query requirements
133
138
  // ═══════════════════════════════════════════════════════════════════════════
134
139
 
135
- describe("context-store: query requirements", () => {
136
- afterEach(() => closeDatabase());
140
+ console.log('\n=== context-store: query all active requirements ===');
141
+ {
142
+ openDatabase(':memory:');
137
143
 
138
- test("query all active requirements", () => {
139
- openDatabase(':memory:');
140
-
141
- insertRequirement({
142
- id: 'R001', class: 'functional', status: 'active',
143
- description: 'req A', why: 'w', source: 'M001', primary_owner: 'S01',
144
- supporting_slices: 'S02', validation: 'v', notes: '', full_content: '',
145
- superseded_by: 'R003', // superseded!
146
- });
147
- insertRequirement({
148
- id: 'R002', class: 'non-functional', status: 'active',
149
- description: 'req B', why: 'w', source: 'M001', primary_owner: 'S01',
150
- supporting_slices: '', validation: 'v', notes: '', full_content: '',
151
- superseded_by: null,
152
- });
153
- insertRequirement({
154
- id: 'R003', class: 'functional', status: 'validated',
155
- description: 'req C', why: 'w', source: 'M001', primary_owner: 'S02',
156
- supporting_slices: 'S01', validation: 'v', notes: '', full_content: '',
157
- superseded_by: null,
158
- });
144
+ insertRequirement({
145
+ id: 'R001', class: 'functional', status: 'active',
146
+ description: 'req A', why: 'w', source: 'M001', primary_owner: 'S01',
147
+ supporting_slices: 'S02', validation: 'v', notes: '', full_content: '',
148
+ superseded_by: 'R003', // superseded!
149
+ });
150
+ insertRequirement({
151
+ id: 'R002', class: 'non-functional', status: 'active',
152
+ description: 'req B', why: 'w', source: 'M001', primary_owner: 'S01',
153
+ supporting_slices: '', validation: 'v', notes: '', full_content: '',
154
+ superseded_by: null,
155
+ });
156
+ insertRequirement({
157
+ id: 'R003', class: 'functional', status: 'validated',
158
+ description: 'req C', why: 'w', source: 'M001', primary_owner: 'S02',
159
+ supporting_slices: 'S01', validation: 'v', notes: '', full_content: '',
160
+ superseded_by: null,
161
+ });
159
162
 
160
- const all = queryRequirements();
161
- assert.strictEqual(all.length, 2, 'query all active requirements returns 2 (superseded excluded)');
162
- const ids = all.map(r => r.id);
163
- assert.ok(ids.includes('R002'), 'R002 should be active');
164
- assert.ok(ids.includes('R003'), 'R003 should be active');
165
- assert.ok(!ids.includes('R001'), 'R001 (superseded) should NOT be active');
163
+ const all = queryRequirements();
164
+ assertEq(all.length, 2, 'query all active requirements returns 2 (superseded excluded)');
165
+ const ids = all.map(r => r.id);
166
+ assertTrue(ids.includes('R002'), 'R002 should be active');
167
+ assertTrue(ids.includes('R003'), 'R003 should be active');
168
+ assertTrue(!ids.includes('R001'), 'R001 (superseded) should NOT be active');
169
+
170
+ closeDatabase();
171
+ }
172
+
173
+ console.log('\n=== context-store: query requirements by slice ===');
174
+ {
175
+ openDatabase(':memory:');
176
+
177
+ insertRequirement({
178
+ id: 'R001', class: 'functional', status: 'active',
179
+ description: 'req A', why: 'w', source: 'M001', primary_owner: 'S01',
180
+ supporting_slices: '', validation: 'v', notes: '', full_content: '',
181
+ superseded_by: null,
182
+ });
183
+ insertRequirement({
184
+ id: 'R002', class: 'functional', status: 'active',
185
+ description: 'req B', why: 'w', source: 'M001', primary_owner: 'S02',
186
+ supporting_slices: 'S01', validation: 'v', notes: '', full_content: '',
187
+ superseded_by: null,
188
+ });
189
+ insertRequirement({
190
+ id: 'R003', class: 'functional', status: 'active',
191
+ description: 'req C', why: 'w', source: 'M001', primary_owner: 'S03',
192
+ supporting_slices: '', validation: 'v', notes: '', full_content: '',
193
+ superseded_by: null,
166
194
  });
167
195
 
168
- test("query requirements by slice", () => {
169
- openDatabase(':memory:');
196
+ const s01 = queryRequirements({ sliceId: 'S01' });
197
+ assertEq(s01.length, 2, 'slice filter S01 returns 2 (primary + supporting)');
198
+ const s01ids = s01.map(r => r.id).sort();
199
+ assertEq(s01ids, ['R001', 'R002'], 'S01 owns R001 and supports R002');
170
200
 
171
- insertRequirement({
172
- id: 'R001', class: 'functional', status: 'active',
173
- description: 'req A', why: 'w', source: 'M001', primary_owner: 'S01',
174
- supporting_slices: '', validation: 'v', notes: '', full_content: '',
175
- superseded_by: null,
176
- });
177
- insertRequirement({
178
- id: 'R002', class: 'functional', status: 'active',
179
- description: 'req B', why: 'w', source: 'M001', primary_owner: 'S02',
180
- supporting_slices: 'S01', validation: 'v', notes: '', full_content: '',
181
- superseded_by: null,
182
- });
183
- insertRequirement({
184
- id: 'R003', class: 'functional', status: 'active',
185
- description: 'req C', why: 'w', source: 'M001', primary_owner: 'S03',
186
- supporting_slices: '', validation: 'v', notes: '', full_content: '',
187
- superseded_by: null,
188
- });
201
+ const s03 = queryRequirements({ sliceId: 'S03' });
202
+ assertEq(s03.length, 1, 'slice filter S03 returns 1');
203
+ assertEq(s03[0]?.id, 'R003', 'S03 owns R003');
189
204
 
190
- const s01 = queryRequirements({ sliceId: 'S01' });
191
- assert.strictEqual(s01.length, 2, 'slice filter S01 returns 2 (primary + supporting)');
192
- const s01ids = s01.map(r => r.id).sort();
193
- assert.deepStrictEqual(s01ids, ['R001', 'R002'], 'S01 owns R001 and supports R002');
205
+ closeDatabase();
206
+ }
194
207
 
195
- const s03 = queryRequirements({ sliceId: 'S03' });
196
- assert.strictEqual(s03.length, 1, 'slice filter S03 returns 1');
197
- assert.strictEqual(s03[0]?.id, 'R003', 'S03 owns R003');
198
- });
208
+ console.log('\n=== context-store: query requirements by status ===');
209
+ {
210
+ openDatabase(':memory:');
199
211
 
200
- test("query requirements by status", () => {
201
- openDatabase(':memory:');
212
+ insertRequirement({
213
+ id: 'R001', class: 'functional', status: 'active',
214
+ description: 'req A', why: 'w', source: 'M001', primary_owner: 'S01',
215
+ supporting_slices: '', validation: 'v', notes: '', full_content: '',
216
+ superseded_by: null,
217
+ });
218
+ insertRequirement({
219
+ id: 'R002', class: 'functional', status: 'validated',
220
+ description: 'req B', why: 'w', source: 'M001', primary_owner: 'S01',
221
+ supporting_slices: '', validation: 'v', notes: '', full_content: '',
222
+ superseded_by: null,
223
+ });
224
+ insertRequirement({
225
+ id: 'R003', class: 'functional', status: 'deferred',
226
+ description: 'req C', why: 'w', source: 'M001', primary_owner: 'S01',
227
+ supporting_slices: '', validation: 'v', notes: '', full_content: '',
228
+ superseded_by: null,
229
+ });
202
230
 
203
- insertRequirement({
204
- id: 'R001', class: 'functional', status: 'active',
205
- description: 'req A', why: 'w', source: 'M001', primary_owner: 'S01',
206
- supporting_slices: '', validation: 'v', notes: '', full_content: '',
207
- superseded_by: null,
208
- });
209
- insertRequirement({
210
- id: 'R002', class: 'functional', status: 'validated',
211
- description: 'req B', why: 'w', source: 'M001', primary_owner: 'S01',
212
- supporting_slices: '', validation: 'v', notes: '', full_content: '',
213
- superseded_by: null,
214
- });
215
- insertRequirement({
216
- id: 'R003', class: 'functional', status: 'deferred',
217
- description: 'req C', why: 'w', source: 'M001', primary_owner: 'S01',
218
- supporting_slices: '', validation: 'v', notes: '', full_content: '',
219
- superseded_by: null,
220
- });
231
+ const active = queryRequirements({ status: 'active' });
232
+ assertEq(active.length, 1, 'status filter active returns 1');
233
+ assertEq(active[0]?.id, 'R001', 'active returns R001');
221
234
 
222
- const active = queryRequirements({ status: 'active' });
223
- assert.strictEqual(active.length, 1, 'status filter active returns 1');
224
- assert.strictEqual(active[0]?.id, 'R001', 'active returns R001');
235
+ const validated = queryRequirements({ status: 'validated' });
236
+ assertEq(validated.length, 1, 'status filter validated returns 1');
237
+ assertEq(validated[0]?.id, 'R002', 'validated returns R002');
225
238
 
226
- const validated = queryRequirements({ status: 'validated' });
227
- assert.strictEqual(validated.length, 1, 'status filter validated returns 1');
228
- assert.strictEqual(validated[0]?.id, 'R002', 'validated returns R002');
229
- });
230
- });
239
+ closeDatabase();
240
+ }
231
241
 
232
242
  // ═══════════════════════════════════════════════════════════════════════════
233
243
  // context-store: format decisions
234
244
  // ═══════════════════════════════════════════════════════════════════════════
235
245
 
236
- describe("context-store: formatDecisionsForPrompt", () => {
237
- test("empty input returns empty string", () => {
238
- const empty = formatDecisionsForPrompt([]);
239
- assert.strictEqual(empty, '', 'empty input returns empty string');
240
- });
246
+ console.log('\n=== context-store: formatDecisionsForPrompt ===');
247
+ {
248
+ const empty = formatDecisionsForPrompt([]);
249
+ assertEq(empty, '', 'empty input returns empty string');
241
250
 
242
- test("formats decisions as markdown table", () => {
243
- const result = formatDecisionsForPrompt([
244
- {
245
- seq: 1, id: 'D001', when_context: 'M001/S01', scope: 'architecture',
246
- decision: 'use SQLite', choice: 'node:sqlite', rationale: 'built-in',
247
- revisable: 'yes', made_by: 'agent', superseded_by: null,
248
- },
249
- {
250
- seq: 2, id: 'D002', when_context: 'M001/S02', scope: 'performance',
251
- decision: 'use WAL', choice: 'WAL', rationale: 'concurrent',
252
- revisable: 'no', made_by: 'human', superseded_by: null,
253
- },
254
- ]);
255
-
256
- // Should be a markdown table
257
- assert.match(result, /^\| # \| When \| Scope/, 'has table header');
258
- assert.match(result, /\|---\|/, 'has separator row');
259
- assert.match(result, /\| D001 \|/, 'has D001 row');
260
- assert.match(result, /\| D002 \|/, 'has D002 row');
261
- const lines = result.split('\n');
262
- assert.strictEqual(lines.length, 4, 'table has 4 lines (header + separator + 2 rows)');
263
- });
264
- });
251
+ const result = formatDecisionsForPrompt([
252
+ {
253
+ seq: 1, id: 'D001', when_context: 'M001/S01', scope: 'architecture',
254
+ decision: 'use SQLite', choice: 'node:sqlite', rationale: 'built-in',
255
+ revisable: 'yes', made_by: 'agent', superseded_by: null,
256
+ },
257
+ {
258
+ seq: 2, id: 'D002', when_context: 'M001/S02', scope: 'performance',
259
+ decision: 'use WAL', choice: 'WAL', rationale: 'concurrent',
260
+ revisable: 'no', made_by: 'human', superseded_by: null,
261
+ },
262
+ ]);
263
+
264
+ // Should be a markdown table
265
+ assertMatch(result, /^\| # \| When \| Scope/, 'has table header');
266
+ assertMatch(result, /\|---\|/, 'has separator row');
267
+ assertMatch(result, /\| D001 \|/, 'has D001 row');
268
+ assertMatch(result, /\| D002 \|/, 'has D002 row');
269
+ const lines = result.split('\n');
270
+ assertEq(lines.length, 4, 'table has 4 lines (header + separator + 2 rows)');
271
+ }
265
272
 
266
273
  // ═══════════════════════════════════════════════════════════════════════════
267
274
  // context-store: format requirements
268
275
  // ═══════════════════════════════════════════════════════════════════════════
269
276
 
270
- describe("context-store: formatRequirementsForPrompt", () => {
271
- test("empty input returns empty string", () => {
272
- const empty = formatRequirementsForPrompt([]);
273
- assert.strictEqual(empty, '', 'empty input returns empty string');
274
- });
277
+ console.log('\n=== context-store: formatRequirementsForPrompt ===');
278
+ {
279
+ const empty = formatRequirementsForPrompt([]);
280
+ assertEq(empty, '', 'empty input returns empty string');
275
281
 
276
- test("formats requirements as markdown sections", () => {
277
- const result = formatRequirementsForPrompt([
278
- {
279
- id: 'R001', class: 'functional', status: 'active',
280
- description: 'System must persist decisions', why: 'agent memory',
281
- source: 'M001', primary_owner: 'S01', supporting_slices: 'S02',
282
- validation: 'roundtrip test', notes: 'high priority',
283
- full_content: '', superseded_by: null,
284
- },
285
- {
286
- id: 'R002', class: 'non-functional', status: 'active',
287
- description: 'Sub-5ms query latency', why: 'prompt injection speed',
288
- source: 'M001', primary_owner: 'S01', supporting_slices: '',
289
- validation: 'timing test', notes: '',
290
- full_content: '', superseded_by: null,
291
- },
292
- ]);
293
-
294
- assert.match(result, /### R001: System must persist decisions/, 'has R001 section header');
295
- assert.match(result, /### R002: Sub-5ms query latency/, 'has R002 section header');
296
- assert.match(result, /\*\*Class:\*\* functional/, 'has class field');
297
- assert.match(result, /\*\*Status:\*\* active/, 'has status field');
298
- assert.match(result, /\*\*Supporting Slices:\*\* S02/, 'has supporting slices when present');
299
- // R002 has no supporting_slices — should not have that line
300
- // R002 has no notes should not have notes line
301
- const r002Section = result.split('### R002')[1] || '';
302
- assert.ok(!r002Section.includes('**Supporting Slices:**'), 'no supporting slices line when empty');
303
- assert.ok(!r002Section.includes('**Notes:**'), 'no notes line when empty');
304
- });
305
- });
282
+ const result = formatRequirementsForPrompt([
283
+ {
284
+ id: 'R001', class: 'functional', status: 'active',
285
+ description: 'System must persist decisions', why: 'agent memory',
286
+ source: 'M001', primary_owner: 'S01', supporting_slices: 'S02',
287
+ validation: 'roundtrip test', notes: 'high priority',
288
+ full_content: '', superseded_by: null,
289
+ },
290
+ {
291
+ id: 'R002', class: 'non-functional', status: 'active',
292
+ description: 'Sub-5ms query latency', why: 'prompt injection speed',
293
+ source: 'M001', primary_owner: 'S01', supporting_slices: '',
294
+ validation: 'timing test', notes: '',
295
+ full_content: '', superseded_by: null,
296
+ },
297
+ ]);
298
+
299
+ assertMatch(result, /### R001: System must persist decisions/, 'has R001 section header');
300
+ assertMatch(result, /### R002: Sub-5ms query latency/, 'has R002 section header');
301
+ assertMatch(result, /\*\*Class:\*\* functional/, 'has class field');
302
+ assertMatch(result, /\*\*Status:\*\* active/, 'has status field');
303
+ assertMatch(result, /\*\*Supporting Slices:\*\* S02/, 'has supporting slices when present');
304
+ // R002 has no supporting_slices should not have that line
305
+ // R002 has no notes — should not have notes line
306
+ const r002Section = result.split('### R002')[1] || '';
307
+ assertTrue(!r002Section.includes('**Supporting Slices:**'), 'no supporting slices line when empty');
308
+ assertTrue(!r002Section.includes('**Notes:**'), 'no notes line when empty');
309
+ }
306
310
 
307
311
  // ═══════════════════════════════════════════════════════════════════════════
308
312
  // context-store: sub-5ms timing assertion
309
313
  // ═══════════════════════════════════════════════════════════════════════════
310
314
 
311
- describe("context-store: sub-5ms query timing", () => {
312
- afterEach(() => closeDatabase());
313
-
314
- test("queries complete under 5ms for 50+50 rows", () => {
315
- openDatabase(':memory:');
316
-
317
- // Insert 50 decisions
318
- for (let i = 1; i <= 50; i++) {
319
- const id = `D${String(i).padStart(3, '0')}`;
320
- insertDecision({
321
- id,
322
- when_context: `M00${(i % 3) + 1}/S0${(i % 5) + 1}`,
323
- scope: i % 2 === 0 ? 'architecture' : 'performance',
324
- decision: `decision ${i}`,
325
- choice: `choice ${i}`,
326
- rationale: `rationale ${i}`,
327
- revisable: i % 3 === 0 ? 'no' : 'yes',
328
- made_by: 'agent',
329
- superseded_by: null,
330
- });
331
- }
332
-
333
- // Insert 50 requirements
334
- for (let i = 1; i <= 50; i++) {
335
- const id = `R${String(i).padStart(3, '0')}`;
336
- insertRequirement({
337
- id,
338
- class: i % 2 === 0 ? 'functional' : 'non-functional',
339
- status: i % 4 === 0 ? 'validated' : 'active',
340
- description: `requirement ${i}`,
341
- why: `why ${i}`,
342
- source: 'M001',
343
- primary_owner: `S0${(i % 5) + 1}`,
344
- supporting_slices: i % 3 === 0 ? 'S01, S02' : '',
345
- validation: `validation ${i}`,
346
- notes: '',
347
- full_content: '',
348
- superseded_by: null,
349
- });
350
- }
351
-
352
- // Time the queries — warm up first
353
- queryDecisions();
354
- queryRequirements();
355
-
356
- const start = performance.now();
357
- const decisions = queryDecisions();
358
- const requirements = queryRequirements();
359
- const elapsed = performance.now() - start;
360
-
361
- assert.strictEqual(decisions.length, 50, `got ${decisions.length} decisions (expected 50)`);
362
- assert.strictEqual(requirements.length, 50, `got ${requirements.length} requirements (expected 50)`);
363
- assert.ok(elapsed < 5, `query latency ${elapsed.toFixed(2)}ms should be < 5ms`);
364
- });
365
- });
315
+ console.log('\n=== context-store: sub-5ms query timing ===');
316
+ {
317
+ openDatabase(':memory:');
318
+
319
+ // Insert 50 decisions
320
+ for (let i = 1; i <= 50; i++) {
321
+ const id = `D${String(i).padStart(3, '0')}`;
322
+ insertDecision({
323
+ id,
324
+ when_context: `M00${(i % 3) + 1}/S0${(i % 5) + 1}`,
325
+ scope: i % 2 === 0 ? 'architecture' : 'performance',
326
+ decision: `decision ${i}`,
327
+ choice: `choice ${i}`,
328
+ rationale: `rationale ${i}`,
329
+ revisable: i % 3 === 0 ? 'no' : 'yes',
330
+ made_by: 'agent',
331
+ superseded_by: null,
332
+ });
333
+ }
334
+
335
+ // Insert 50 requirements
336
+ for (let i = 1; i <= 50; i++) {
337
+ const id = `R${String(i).padStart(3, '0')}`;
338
+ insertRequirement({
339
+ id,
340
+ class: i % 2 === 0 ? 'functional' : 'non-functional',
341
+ status: i % 4 === 0 ? 'validated' : 'active',
342
+ description: `requirement ${i}`,
343
+ why: `why ${i}`,
344
+ source: 'M001',
345
+ primary_owner: `S0${(i % 5) + 1}`,
346
+ supporting_slices: i % 3 === 0 ? 'S01, S02' : '',
347
+ validation: `validation ${i}`,
348
+ notes: '',
349
+ full_content: '',
350
+ superseded_by: null,
351
+ });
352
+ }
353
+
354
+ // Time the queries — warm up first
355
+ queryDecisions();
356
+ queryRequirements();
357
+
358
+ const start = performance.now();
359
+ const decisions = queryDecisions();
360
+ const requirements = queryRequirements();
361
+ const elapsed = performance.now() - start;
362
+
363
+ assertTrue(decisions.length === 50, `got ${decisions.length} decisions (expected 50)`);
364
+ assertTrue(requirements.length === 50, `got ${requirements.length} requirements (expected 50)`);
365
+ assertTrue(elapsed < 5, `query latency ${elapsed.toFixed(2)}ms should be < 5ms`);
366
+ console.log(` timing: ${elapsed.toFixed(2)}ms for 50+50 row queries`);
367
+
368
+ closeDatabase();
369
+ }
366
370
 
367
371
  // ═══════════════════════════════════════════════════════════════════════════
368
372
  // context-store: queryArtifact
369
373
  // ═══════════════════════════════════════════════════════════════════════════
370
374
 
371
- describe("context-store: queryArtifact", () => {
372
- afterEach(() => closeDatabase());
375
+ console.log('\n=== context-store: queryArtifact returns content for existing path ===');
376
+ {
377
+ openDatabase(':memory:');
378
+
379
+ insertArtifact({
380
+ path: 'PROJECT.md',
381
+ artifact_type: 'project',
382
+ milestone_id: null,
383
+ slice_id: null,
384
+ task_id: null,
385
+ full_content: '# My Project\n\nProject description here.',
386
+ });
387
+ insertArtifact({
388
+ path: '.gsd/milestones/M001/M001-PLAN.md',
389
+ artifact_type: 'milestone_plan',
390
+ milestone_id: 'M001',
391
+ slice_id: null,
392
+ task_id: null,
393
+ full_content: '# M001 Plan\n\nMilestone content.',
394
+ });
373
395
 
374
- test("returns content for existing path", () => {
375
- openDatabase(':memory:');
396
+ const project = queryArtifact('PROJECT.md');
397
+ assertEq(project, '# My Project\n\nProject description here.', 'queryArtifact returns full_content for PROJECT.md');
376
398
 
377
- insertArtifact({
378
- path: 'PROJECT.md',
379
- artifact_type: 'project',
380
- milestone_id: null,
381
- slice_id: null,
382
- task_id: null,
383
- full_content: '# My Project\n\nProject description here.',
384
- });
385
- insertArtifact({
386
- path: '.gsd/milestones/M001/M001-PLAN.md',
387
- artifact_type: 'milestone_plan',
388
- milestone_id: 'M001',
389
- slice_id: null,
390
- task_id: null,
391
- full_content: '# M001 Plan\n\nMilestone content.',
392
- });
399
+ const plan = queryArtifact('.gsd/milestones/M001/M001-PLAN.md');
400
+ assertEq(plan, '# M001 Plan\n\nMilestone content.', 'queryArtifact returns full_content for milestone plan');
393
401
 
394
- const project = queryArtifact('PROJECT.md');
395
- assert.strictEqual(project, '# My Project\n\nProject description here.', 'queryArtifact returns full_content for PROJECT.md');
402
+ closeDatabase();
403
+ }
396
404
 
397
- const plan = queryArtifact('.gsd/milestones/M001/M001-PLAN.md');
398
- assert.strictEqual(plan, '# M001 Plan\n\nMilestone content.', 'queryArtifact returns full_content for milestone plan');
399
- });
405
+ console.log('\n=== context-store: queryArtifact returns null for missing path ===');
406
+ {
407
+ openDatabase(':memory:');
400
408
 
401
- test("returns null for missing path", () => {
402
- openDatabase(':memory:');
409
+ const missing = queryArtifact('nonexistent.md');
410
+ assertEq(missing, null, 'queryArtifact returns null for path not in DB');
403
411
 
404
- const missing = queryArtifact('nonexistent.md');
405
- assert.strictEqual(missing, null, 'queryArtifact returns null for path not in DB');
406
- });
412
+ closeDatabase();
413
+ }
407
414
 
408
- test("returns null when DB unavailable", () => {
409
- closeDatabase();
410
- assert.ok(!isDbAvailable(), 'DB should not be available');
415
+ console.log('\n=== context-store: queryArtifact returns null when DB unavailable ===');
416
+ {
417
+ closeDatabase();
418
+ assertTrue(!isDbAvailable(), 'DB should not be available');
411
419
 
412
- const result = queryArtifact('PROJECT.md');
413
- assert.strictEqual(result, null, 'queryArtifact returns null when DB closed');
414
- });
415
- });
420
+ const result = queryArtifact('PROJECT.md');
421
+ assertEq(result, null, 'queryArtifact returns null when DB closed');
422
+ }
416
423
 
417
424
  // ═══════════════════════════════════════════════════════════════════════════
418
425
  // context-store: queryProject
419
426
  // ═══════════════════════════════════════════════════════════════════════════
420
427
 
421
- describe("context-store: queryProject", () => {
422
- afterEach(() => closeDatabase());
428
+ console.log('\n=== context-store: queryProject returns PROJECT.md content ===');
429
+ {
430
+ openDatabase(':memory:');
431
+
432
+ insertArtifact({
433
+ path: 'PROJECT.md',
434
+ artifact_type: 'project',
435
+ milestone_id: null,
436
+ slice_id: null,
437
+ task_id: null,
438
+ full_content: '# Test Project\n\nThis is the project description.',
439
+ });
423
440
 
424
- test("returns PROJECT.md content", () => {
425
- openDatabase(':memory:');
441
+ const content = queryProject();
442
+ assertEq(content, '# Test Project\n\nThis is the project description.', 'queryProject returns PROJECT.md content');
426
443
 
427
- insertArtifact({
428
- path: 'PROJECT.md',
429
- artifact_type: 'project',
430
- milestone_id: null,
431
- slice_id: null,
432
- task_id: null,
433
- full_content: '# Test Project\n\nThis is the project description.',
434
- });
444
+ closeDatabase();
445
+ }
435
446
 
436
- const content = queryProject();
437
- assert.strictEqual(content, '# Test Project\n\nThis is the project description.', 'queryProject returns PROJECT.md content');
438
- });
447
+ console.log('\n=== context-store: queryProject returns null when no PROJECT.md ===');
448
+ {
449
+ openDatabase(':memory:');
439
450
 
440
- test("returns null when no PROJECT.md", () => {
441
- openDatabase(':memory:');
451
+ const content = queryProject();
452
+ assertEq(content, null, 'queryProject returns null when PROJECT.md not imported');
442
453
 
443
- const content = queryProject();
444
- assert.strictEqual(content, null, 'queryProject returns null when PROJECT.md not imported');
445
- });
454
+ closeDatabase();
455
+ }
446
456
 
447
- test("returns null when DB unavailable", () => {
448
- closeDatabase();
449
- assert.ok(!isDbAvailable(), 'DB should not be available');
457
+ console.log('\n=== context-store: queryProject returns null when DB unavailable ===');
458
+ {
459
+ closeDatabase();
460
+ assertTrue(!isDbAvailable(), 'DB should not be available');
450
461
 
451
- const content = queryProject();
452
- assert.strictEqual(content, null, 'queryProject returns null when DB closed');
453
- });
454
- });
462
+ const content = queryProject();
463
+ assertEq(content, null, 'queryProject returns null when DB closed');
464
+ }
465
+
466
+ // ─── Final Report ──────────────────────────────────────────────────────────
467
+ report();