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,3 +1,4 @@
1
+ import { createTestContext } from './test-helpers.ts';
1
2
  import * as fs from 'node:fs';
2
3
  import * as path from 'node:path';
3
4
  import * as os from 'node:os';
@@ -16,8 +17,8 @@ import {
16
17
  parseRequirementsSections,
17
18
  migrateFromMarkdown,
18
19
  } from '../md-importer.ts';
19
- import { describe, test, beforeEach, afterEach } from 'node:test';
20
- import assert from 'node:assert/strict';
20
+
21
+ const { assertEq, assertTrue, report } = createTestContext();
21
22
 
22
23
  // ═══════════════════════════════════════════════════════════════════════════
23
24
  // Fixtures
@@ -134,37 +135,43 @@ function cleanupDir(dir: string): void {
134
135
  // md-importer: parseDecisionsTable
135
136
  // ═══════════════════════════════════════════════════════════════════════════
136
137
 
137
- test('md-importer: parseDecisionsTable', () => {
138
+ console.log('\n=== md-importer: parseDecisionsTable ===');
139
+
140
+ {
138
141
  const decisions = parseDecisionsTable(DECISIONS_MD);
139
- assert.deepStrictEqual(decisions.length, 4, 'should parse 4 decisions');
140
- assert.deepStrictEqual(decisions[0].id, 'D001', 'first decision should be D001');
141
- assert.deepStrictEqual(decisions[0].decision, 'SQLite library', 'D001 decision text');
142
- assert.deepStrictEqual(decisions[0].choice, 'better-sqlite3', 'D001 choice');
143
- assert.deepStrictEqual(decisions[0].scope, 'library', 'D001 scope');
144
- assert.deepStrictEqual(decisions[0].revisable, 'No', 'D001 revisable');
145
- });
146
-
147
- test('md-importer: supersession detection', () => {
142
+ assertEq(decisions.length, 4, 'should parse 4 decisions');
143
+ assertEq(decisions[0].id, 'D001', 'first decision should be D001');
144
+ assertEq(decisions[0].decision, 'SQLite library', 'D001 decision text');
145
+ assertEq(decisions[0].choice, 'better-sqlite3', 'D001 choice');
146
+ assertEq(decisions[0].scope, 'library', 'D001 scope');
147
+ assertEq(decisions[0].revisable, 'No', 'D001 revisable');
148
+ }
149
+
150
+ console.log('=== md-importer: supersession detection ===');
151
+
152
+ {
148
153
  const decisions = parseDecisionsTable(DECISIONS_MD);
149
154
 
150
155
  // D010 amends D001 → D001.superseded_by = D010
151
156
  const d001 = decisions.find(d => d.id === 'D001');
152
- assert.deepStrictEqual(d001?.superseded_by, 'D010', 'D001 should be superseded by D010');
157
+ assertEq(d001?.superseded_by, 'D010', 'D001 should be superseded by D010');
153
158
 
154
159
  // D020 amends D010 → D010.superseded_by = D020
155
160
  const d010 = decisions.find(d => d.id === 'D010');
156
- assert.deepStrictEqual(d010?.superseded_by, 'D020', 'D010 should be superseded by D020');
161
+ assertEq(d010?.superseded_by, 'D020', 'D010 should be superseded by D020');
157
162
 
158
163
  // D002 is not amended
159
164
  const d002 = decisions.find(d => d.id === 'D002');
160
- assert.deepStrictEqual(d002?.superseded_by, null, 'D002 should not be superseded');
165
+ assertEq(d002?.superseded_by, null, 'D002 should not be superseded');
161
166
 
162
167
  // D020 is the latest in chain, not superseded
163
168
  const d020 = decisions.find(d => d.id === 'D020');
164
- assert.deepStrictEqual(d020?.superseded_by, null, 'D020 should not be superseded');
165
- });
169
+ assertEq(d020?.superseded_by, null, 'D020 should not be superseded');
170
+ }
166
171
 
167
- test('md-importer: malformed/empty rows skipped', () => {
172
+ console.log('=== md-importer: malformed/empty rows skipped ===');
173
+
174
+ {
168
175
  const malformedInput = `# Decisions
169
176
 
170
177
  | # | When | Scope | Decision | Choice | Rationale | Revisable? |
@@ -175,20 +182,24 @@ test('md-importer: malformed/empty rows skipped', () => {
175
182
  | D003 | M001 | arch | Config | JSON | Simple | Yes |
176
183
  `;
177
184
  const decisions = parseDecisionsTable(malformedInput);
178
- assert.deepStrictEqual(decisions.length, 2, 'should skip rows without D-prefix IDs');
179
- assert.deepStrictEqual(decisions[0].id, 'D001', 'first valid row');
180
- assert.deepStrictEqual(decisions[1].id, 'D003', 'second valid row (skipping malformed)');
181
- });
185
+ assertEq(decisions.length, 2, 'should skip rows without D-prefix IDs');
186
+ assertEq(decisions[0].id, 'D001', 'first valid row');
187
+ assertEq(decisions[1].id, 'D003', 'second valid row (skipping malformed)');
188
+ }
189
+
190
+ console.log('=== md-importer: made_by backward compatibility (old 7-column format) ===');
182
191
 
183
- test('md-importer: made_by backward compatibility (old 7-column format)', () => {
192
+ {
184
193
  const decisions = parseDecisionsTable(DECISIONS_MD);
185
194
  // Old format has no Made By column — should default to 'agent'
186
195
  for (const d of decisions) {
187
- assert.deepStrictEqual(d.made_by, 'agent', `${d.id} made_by defaults to agent for legacy format`);
196
+ assertEq(d.made_by, 'agent', `${d.id} made_by defaults to agent for legacy format`);
188
197
  }
189
- });
198
+ }
199
+
200
+ console.log('=== md-importer: made_by column parsing (new 8-column format) ===');
190
201
 
191
- test('md-importer: made_by column parsing (new 8-column format)', () => {
202
+ {
192
203
  const newFormatMd = `# Decisions Register
193
204
 
194
205
  | # | When | Scope | Decision | Choice | Rationale | Revisable? | Made By |
@@ -199,58 +210,62 @@ test('md-importer: made_by column parsing (new 8-column format)', () => {
199
210
  | D004 | M002 | impl | Cache strategy | LRU | Predictable | No | bogus |
200
211
  `;
201
212
  const decisions = parseDecisionsTable(newFormatMd);
202
- assert.deepStrictEqual(decisions.length, 4, 'should parse 4 decisions with new format');
203
- assert.deepStrictEqual(decisions[0].made_by, 'human', 'D001 made_by = human');
204
- assert.deepStrictEqual(decisions[1].made_by, 'agent', 'D002 made_by = agent');
205
- assert.deepStrictEqual(decisions[2].made_by, 'collaborative', 'D003 made_by = collaborative');
206
- assert.deepStrictEqual(decisions[3].made_by, 'agent', 'D004 invalid made_by defaults to agent');
207
- });
213
+ assertEq(decisions.length, 4, 'should parse 4 decisions with new format');
214
+ assertEq(decisions[0].made_by, 'human', 'D001 made_by = human');
215
+ assertEq(decisions[1].made_by, 'agent', 'D002 made_by = agent');
216
+ assertEq(decisions[2].made_by, 'collaborative', 'D003 made_by = collaborative');
217
+ assertEq(decisions[3].made_by, 'agent', 'D004 invalid made_by defaults to agent');
218
+ }
208
219
 
209
220
  // ═══════════════════════════════════════════════════════════════════════════
210
221
  // md-importer: parseRequirementsSections
211
222
  // ═══════════════════════════════════════════════════════════════════════════
212
223
 
213
- test('md-importer: parseRequirementsSections', () => {
224
+ console.log('=== md-importer: parseRequirementsSections ===');
225
+
226
+ {
214
227
  const reqs = parseRequirementsSections(REQUIREMENTS_MD);
215
- assert.deepStrictEqual(reqs.length, 5, 'should parse 5 unique requirements');
228
+ assertEq(reqs.length, 5, 'should parse 5 unique requirements');
216
229
 
217
230
  const r001 = reqs.find(r => r.id === 'R001');
218
- assert.ok(!!r001, 'R001 should exist');
219
- assert.deepStrictEqual(r001?.class, 'core-capability', 'R001 class');
220
- assert.deepStrictEqual(r001?.status, 'active', 'R001 status');
221
- assert.deepStrictEqual(r001?.description, 'A SQLite database with typed wrappers', 'R001 description');
222
- assert.deepStrictEqual(r001?.why, 'Foundation for storage', 'R001 why');
223
- assert.deepStrictEqual(r001?.source, 'user', 'R001 source');
224
- assert.deepStrictEqual(r001?.primary_owner, 'M001/S01', 'R001 primary_owner');
225
- assert.deepStrictEqual(r001?.supporting_slices, 'none', 'R001 supporting_slices');
226
- assert.deepStrictEqual(r001?.validation, 'unmapped', 'R001 validation');
227
- assert.deepStrictEqual(r001?.notes, 'WAL mode enabled', 'R001 notes');
228
- assert.ok(r001?.full_content?.includes('### R001') ?? false, 'R001 full_content should have heading');
231
+ assertTrue(!!r001, 'R001 should exist');
232
+ assertEq(r001?.class, 'core-capability', 'R001 class');
233
+ assertEq(r001?.status, 'active', 'R001 status');
234
+ assertEq(r001?.description, 'A SQLite database with typed wrappers', 'R001 description');
235
+ assertEq(r001?.why, 'Foundation for storage', 'R001 why');
236
+ assertEq(r001?.source, 'user', 'R001 source');
237
+ assertEq(r001?.primary_owner, 'M001/S01', 'R001 primary_owner');
238
+ assertEq(r001?.supporting_slices, 'none', 'R001 supporting_slices');
239
+ assertEq(r001?.validation, 'unmapped', 'R001 validation');
240
+ assertEq(r001?.notes, 'WAL mode enabled', 'R001 notes');
241
+ assertTrue(r001?.full_content?.includes('### R001') ?? false, 'R001 full_content should have heading');
229
242
 
230
243
  // Validated section — R017 (abbreviated format with "Validated by" / "Proof" bullets)
231
244
  const r017 = reqs.find(r => r.id === 'R017');
232
- assert.ok(!!r017, 'R017 should exist');
233
- assert.deepStrictEqual(r017?.status, 'validated', 'R017 status from validated section');
234
- assert.deepStrictEqual(r017?.validation, 'M001/S01', 'R017 validation (from "Validated by" bullet)');
235
- assert.deepStrictEqual(r017?.notes, '50 decisions queried in 0.62ms', 'R017 notes (from "Proof" bullet)');
245
+ assertTrue(!!r017, 'R017 should exist');
246
+ assertEq(r017?.status, 'validated', 'R017 status from validated section');
247
+ assertEq(r017?.validation, 'M001/S01', 'R017 validation (from "Validated by" bullet)');
248
+ assertEq(r017?.notes, '50 decisions queried in 0.62ms', 'R017 notes (from "Proof" bullet)');
236
249
 
237
250
  // Deferred requirement
238
251
  const r030 = reqs.find(r => r.id === 'R030');
239
- assert.deepStrictEqual(r030?.status, 'deferred', 'R030 status should be deferred');
240
- assert.deepStrictEqual(r030?.class, 'differentiator', 'R030 class');
241
- assert.deepStrictEqual(r030?.description, 'Rust crate for embeddings', 'R030 description');
252
+ assertEq(r030?.status, 'deferred', 'R030 status should be deferred');
253
+ assertEq(r030?.class, 'differentiator', 'R030 class');
254
+ assertEq(r030?.description, 'Rust crate for embeddings', 'R030 description');
242
255
 
243
256
  // Out of scope
244
257
  const r040 = reqs.find(r => r.id === 'R040');
245
- assert.deepStrictEqual(r040?.status, 'out-of-scope', 'R040 status should be out-of-scope');
246
- assert.deepStrictEqual(r040?.class, 'anti-feature', 'R040 class');
247
- });
258
+ assertEq(r040?.status, 'out-of-scope', 'R040 status should be out-of-scope');
259
+ assertEq(r040?.class, 'anti-feature', 'R040 class');
260
+ }
248
261
 
249
262
  // ═══════════════════════════════════════════════════════════════════════════
250
263
  // md-importer: migrateFromMarkdown orchestrator
251
264
  // ═══════════════════════════════════════════════════════════════════════════
252
265
 
253
- test('md-importer: migrateFromMarkdown orchestrator', () => {
266
+ console.log('=== md-importer: migrateFromMarkdown orchestrator ===');
267
+
268
+ {
254
269
  const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'gsd-import-test-'));
255
270
  createFixtureTree(tmpDir);
256
271
 
@@ -258,51 +273,53 @@ test('md-importer: migrateFromMarkdown orchestrator', () => {
258
273
  openDatabase(':memory:');
259
274
  const result = migrateFromMarkdown(tmpDir);
260
275
 
261
- assert.deepStrictEqual(result.decisions, 4, 'should import 4 decisions');
262
- assert.deepStrictEqual(result.requirements, 5, 'should import 5 requirements');
263
- assert.ok(result.artifacts > 0, 'should import some artifacts');
276
+ assertEq(result.decisions, 4, 'should import 4 decisions');
277
+ assertEq(result.requirements, 5, 'should import 5 requirements');
278
+ assertTrue(result.artifacts > 0, 'should import some artifacts');
264
279
 
265
280
  // Verify decisions queryable
266
281
  const d001 = getDecisionById('D001');
267
- assert.ok(!!d001, 'D001 should be queryable');
268
- assert.deepStrictEqual(d001?.superseded_by, 'D010', 'D001 superseded_by should be D010');
282
+ assertTrue(!!d001, 'D001 should be queryable');
283
+ assertEq(d001?.superseded_by, 'D010', 'D001 superseded_by should be D010');
269
284
 
270
285
  // Verify requirements queryable
271
286
  const r001 = getRequirementById('R001');
272
- assert.ok(!!r001, 'R001 should be queryable');
273
- assert.deepStrictEqual(r001?.status, 'active', 'R001 status from DB');
287
+ assertTrue(!!r001, 'R001 should be queryable');
288
+ assertEq(r001?.status, 'active', 'R001 status from DB');
274
289
 
275
290
  // Verify active views
276
291
  const activeD = getActiveDecisions();
277
- assert.deepStrictEqual(activeD.length, 2, 'should have 2 active decisions (D002, D020)');
292
+ assertEq(activeD.length, 2, 'should have 2 active decisions (D002, D020)');
278
293
 
279
294
  // Verify artifacts table
280
295
  const adapter = _getAdapter();
281
296
  const artifacts = adapter?.prepare('SELECT count(*) as c FROM artifacts').get();
282
- assert.ok((artifacts?.c as number) > 0, 'artifacts table should have rows');
297
+ assertTrue((artifacts?.c as number) > 0, 'artifacts table should have rows');
283
298
 
284
299
  // Verify hierarchy correctness
285
300
  const roadmap = adapter?.prepare('SELECT * FROM artifacts WHERE artifact_type = :type').get({ ':type': 'ROADMAP' });
286
- assert.ok(!!roadmap, 'ROADMAP artifact should exist');
287
- assert.deepStrictEqual(roadmap?.milestone_id, 'M001', 'ROADMAP should be in M001');
301
+ assertTrue(!!roadmap, 'ROADMAP artifact should exist');
302
+ assertEq(roadmap?.milestone_id, 'M001', 'ROADMAP should be in M001');
288
303
 
289
304
  const taskPlan = adapter?.prepare('SELECT * FROM artifacts WHERE task_id = :taskId AND artifact_type = :type').get({
290
305
  ':taskId': 'T01',
291
306
  ':type': 'PLAN',
292
307
  });
293
- assert.ok(!!taskPlan, 'T01-PLAN artifact should exist');
308
+ assertTrue(!!taskPlan, 'T01-PLAN artifact should exist');
294
309
 
295
310
  closeDatabase();
296
311
  } finally {
297
312
  cleanupDir(tmpDir);
298
313
  }
299
- });
314
+ }
300
315
 
301
316
  // ═══════════════════════════════════════════════════════════════════════════
302
317
  // md-importer: idempotent re-import
303
318
  // ═══════════════════════════════════════════════════════════════════════════
304
319
 
305
- test('md-importer: idempotent re-import', () => {
320
+ console.log('=== md-importer: idempotent re-import ===');
321
+
322
+ {
306
323
  const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'gsd-idemp-test-'));
307
324
  createFixtureTree(tmpDir);
308
325
 
@@ -311,9 +328,9 @@ test('md-importer: idempotent re-import', () => {
311
328
  const r1 = migrateFromMarkdown(tmpDir);
312
329
  const r2 = migrateFromMarkdown(tmpDir);
313
330
 
314
- assert.deepStrictEqual(r1.decisions, r2.decisions, 'double import should produce same decision count');
315
- assert.deepStrictEqual(r1.requirements, r2.requirements, 'double import should produce same requirement count');
316
- assert.deepStrictEqual(r1.artifacts, r2.artifacts, 'double import should produce same artifact count');
331
+ assertEq(r1.decisions, r2.decisions, 'double import should produce same decision count');
332
+ assertEq(r1.requirements, r2.requirements, 'double import should produce same requirement count');
333
+ assertEq(r1.artifacts, r2.artifacts, 'double import should produce same artifact count');
317
334
 
318
335
  // Verify no duplicates
319
336
  const adapter = _getAdapter();
@@ -321,21 +338,23 @@ test('md-importer: idempotent re-import', () => {
321
338
  const rc = adapter?.prepare('SELECT count(*) as c FROM requirements').get()?.c as number;
322
339
  const ac = adapter?.prepare('SELECT count(*) as c FROM artifacts').get()?.c as number;
323
340
 
324
- assert.deepStrictEqual(dc, r1.decisions, 'DB decision count matches import count');
325
- assert.deepStrictEqual(rc, r1.requirements, 'DB requirement count matches import count');
326
- assert.deepStrictEqual(ac, r1.artifacts, 'DB artifact count matches import count');
341
+ assertEq(dc, r1.decisions, 'DB decision count matches import count');
342
+ assertEq(rc, r1.requirements, 'DB requirement count matches import count');
343
+ assertEq(ac, r1.artifacts, 'DB artifact count matches import count');
327
344
 
328
345
  closeDatabase();
329
346
  } finally {
330
347
  cleanupDir(tmpDir);
331
348
  }
332
- });
349
+ }
333
350
 
334
351
  // ═══════════════════════════════════════════════════════════════════════════
335
352
  // md-importer: missing file graceful handling
336
353
  // ═══════════════════════════════════════════════════════════════════════════
337
354
 
338
- test('md-importer: missing file handling', () => {
355
+ console.log('=== md-importer: missing file handling ===');
356
+
357
+ {
339
358
  const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'gsd-empty-test-'));
340
359
  // Create empty .gsd/ with no files
341
360
  fs.mkdirSync(path.join(tmpDir, '.gsd'), { recursive: true });
@@ -344,39 +363,43 @@ test('md-importer: missing file handling', () => {
344
363
  openDatabase(':memory:');
345
364
  const result = migrateFromMarkdown(tmpDir);
346
365
 
347
- assert.deepStrictEqual(result.decisions, 0, 'missing DECISIONS.md → 0 decisions');
348
- assert.deepStrictEqual(result.requirements, 0, 'missing REQUIREMENTS.md → 0 requirements');
349
- assert.deepStrictEqual(result.artifacts, 0, 'empty tree → 0 artifacts');
366
+ assertEq(result.decisions, 0, 'missing DECISIONS.md → 0 decisions');
367
+ assertEq(result.requirements, 0, 'missing REQUIREMENTS.md → 0 requirements');
368
+ assertEq(result.artifacts, 0, 'empty tree → 0 artifacts');
350
369
 
351
370
  closeDatabase();
352
371
  } finally {
353
372
  cleanupDir(tmpDir);
354
373
  }
355
- });
374
+ }
356
375
 
357
376
  // ═══════════════════════════════════════════════════════════════════════════
358
377
  // md-importer: schema v1→v2 migration on existing DBs
359
378
  // ═══════════════════════════════════════════════════════════════════════════
360
379
 
361
- test('md-importer: schema v1→v2 migration', () => {
380
+ console.log('=== md-importer: schema v1→v2 migration ===');
381
+
382
+ {
362
383
  // This test verifies that opening a fresh DB auto-migrates to current schema version
363
384
  openDatabase(':memory:');
364
385
  const adapter = _getAdapter();
365
386
  const version = adapter?.prepare('SELECT MAX(version) as v FROM schema_version').get();
366
- assert.deepStrictEqual(version?.v, 10, 'new DB should be at schema version 10');
387
+ assertEq(version?.v, 10, 'new DB should be at schema version 10');
367
388
 
368
389
  // Artifacts table should exist
369
390
  const tableCheck = adapter?.prepare("SELECT count(*) as c FROM sqlite_master WHERE type='table' AND name='artifacts'").get();
370
- assert.deepStrictEqual(tableCheck?.c, 1, 'artifacts table should exist');
391
+ assertEq(tableCheck?.c, 1, 'artifacts table should exist');
371
392
 
372
393
  closeDatabase();
373
- });
394
+ }
374
395
 
375
396
  // ═══════════════════════════════════════════════════════════════════════════
376
397
  // md-importer: round-trip fidelity
377
398
  // ═══════════════════════════════════════════════════════════════════════════
378
399
 
379
- test('md-importer: round-trip fidelity', () => {
400
+ console.log('=== md-importer: round-trip fidelity ===');
401
+
402
+ {
380
403
  const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'gsd-roundtrip-test-'));
381
404
  createFixtureTree(tmpDir);
382
405
 
@@ -386,31 +409,32 @@ test('md-importer: round-trip fidelity', () => {
386
409
 
387
410
  // Round-trip: verify imported field values match source
388
411
  const d002 = getDecisionById('D002');
389
- assert.deepStrictEqual(d002?.when_context, 'M001', 'D002 when_context round-trip');
390
- assert.deepStrictEqual(d002?.scope, 'arch', 'D002 scope round-trip');
391
- assert.deepStrictEqual(d002?.decision, 'DB location', 'D002 decision round-trip');
392
- assert.deepStrictEqual(d002?.choice, '.gsd/gsd.db', 'D002 choice round-trip');
393
- assert.deepStrictEqual(d002?.rationale, 'Derived state', 'D002 rationale round-trip');
412
+ assertEq(d002?.when_context, 'M001', 'D002 when_context round-trip');
413
+ assertEq(d002?.scope, 'arch', 'D002 scope round-trip');
414
+ assertEq(d002?.decision, 'DB location', 'D002 decision round-trip');
415
+ assertEq(d002?.choice, '.gsd/gsd.db', 'D002 choice round-trip');
416
+ assertEq(d002?.rationale, 'Derived state', 'D002 rationale round-trip');
394
417
 
395
418
  const r002 = getRequirementById('R002');
396
- assert.deepStrictEqual(r002?.class, 'failure-visibility', 'R002 class round-trip');
397
- assert.deepStrictEqual(r002?.description, 'Falls back to markdown if SQLite unavailable', 'R002 description round-trip');
398
- assert.deepStrictEqual(r002?.why, 'Must not break on exotic platforms', 'R002 why round-trip');
399
- assert.deepStrictEqual(r002?.primary_owner, 'M001/S01', 'R002 primary_owner round-trip');
400
- assert.deepStrictEqual(r002?.supporting_slices, 'M001/S03', 'R002 supporting_slices round-trip');
401
- assert.deepStrictEqual(r002?.notes, 'Transparent fallback', 'R002 notes round-trip');
402
- assert.deepStrictEqual(r002?.validation, 'unmapped', 'R002 validation round-trip');
419
+ assertEq(r002?.class, 'failure-visibility', 'R002 class round-trip');
420
+ assertEq(r002?.description, 'Falls back to markdown if SQLite unavailable', 'R002 description round-trip');
421
+ assertEq(r002?.why, 'Must not break on exotic platforms', 'R002 why round-trip');
422
+ assertEq(r002?.primary_owner, 'M001/S01', 'R002 primary_owner round-trip');
423
+ assertEq(r002?.supporting_slices, 'M001/S03', 'R002 supporting_slices round-trip');
424
+ assertEq(r002?.notes, 'Transparent fallback', 'R002 notes round-trip');
425
+ assertEq(r002?.validation, 'unmapped', 'R002 validation round-trip');
403
426
 
404
427
  // Verify artifact content is stored
405
428
  const adapter = _getAdapter();
406
429
  const project = adapter?.prepare("SELECT * FROM artifacts WHERE path = :path").get({ ':path': 'PROJECT.md' });
407
- assert.ok((project?.full_content as string)?.includes('Test Project'), 'PROJECT.md content round-trip');
430
+ assertTrue((project?.full_content as string)?.includes('Test Project'), 'PROJECT.md content round-trip');
408
431
 
409
432
  closeDatabase();
410
433
  } finally {
411
434
  cleanupDir(tmpDir);
412
435
  }
413
- });
436
+ }
414
437
 
415
438
  // ═══════════════════════════════════════════════════════════════════════════
416
439
 
440
+ report();
@@ -1,3 +1,4 @@
1
+ import { createTestContext } from './test-helpers.ts';
1
2
  import { parseMemoryResponse, _resetExtractionState } from '../memory-extractor.ts';
2
3
  import {
3
4
  openDatabase,
@@ -9,14 +10,15 @@ import {
9
10
  getActiveMemoriesRanked,
10
11
  } from '../memory-store.ts';
11
12
  import type { MemoryAction } from '../memory-store.ts';
12
- import { describe, test, beforeEach, afterEach } from 'node:test';
13
- import assert from 'node:assert/strict';
13
+
14
+ const { assertEq, assertTrue, report } = createTestContext();
14
15
 
15
16
  // ═══════════════════════════════════════════════════════════════════════════
16
17
  // memory-extractor: parse valid JSON response
17
18
  // ═══════════════════════════════════════════════════════════════════════════
18
19
 
19
- test('memory-extractor: parse valid JSON', () => {
20
+ console.log('\n=== memory-extractor: parse valid JSON ===');
21
+ {
20
22
  const response = JSON.stringify([
21
23
  { action: 'CREATE', category: 'gotcha', content: 'esbuild drops binaries', confidence: 0.85 },
22
24
  { action: 'REINFORCE', id: 'MEM001' },
@@ -25,52 +27,56 @@ test('memory-extractor: parse valid JSON', () => {
25
27
  ]);
26
28
 
27
29
  const actions = parseMemoryResponse(response);
28
- assert.deepStrictEqual(actions.length, 4, 'should parse 4 actions');
29
- assert.deepStrictEqual(actions[0].action, 'CREATE', 'first action should be CREATE');
30
- assert.deepStrictEqual((actions[0] as any).category, 'gotcha', 'CREATE category');
31
- assert.deepStrictEqual((actions[0] as any).confidence, 0.85, 'CREATE confidence');
32
- assert.deepStrictEqual(actions[1].action, 'REINFORCE', 'second action should be REINFORCE');
33
- assert.deepStrictEqual(actions[2].action, 'UPDATE', 'third action should be UPDATE');
34
- assert.deepStrictEqual(actions[3].action, 'SUPERSEDE', 'fourth action should be SUPERSEDE');
35
- });
30
+ assertEq(actions.length, 4, 'should parse 4 actions');
31
+ assertEq(actions[0].action, 'CREATE', 'first action should be CREATE');
32
+ assertEq((actions[0] as any).category, 'gotcha', 'CREATE category');
33
+ assertEq((actions[0] as any).confidence, 0.85, 'CREATE confidence');
34
+ assertEq(actions[1].action, 'REINFORCE', 'second action should be REINFORCE');
35
+ assertEq(actions[2].action, 'UPDATE', 'third action should be UPDATE');
36
+ assertEq(actions[3].action, 'SUPERSEDE', 'fourth action should be SUPERSEDE');
37
+ }
36
38
 
37
39
  // ═══════════════════════════════════════════════════════════════════════════
38
40
  // memory-extractor: parse fenced JSON response
39
41
  // ═══════════════════════════════════════════════════════════════════════════
40
42
 
41
- test('memory-extractor: parse fenced JSON', () => {
43
+ console.log('\n=== memory-extractor: parse fenced JSON ===');
44
+ {
42
45
  const response = '```json\n[\n {"action": "CREATE", "category": "convention", "content": "test memory"}\n]\n```';
43
46
 
44
47
  const actions = parseMemoryResponse(response);
45
- assert.deepStrictEqual(actions.length, 1, 'should parse 1 action from fenced JSON');
46
- assert.deepStrictEqual(actions[0].action, 'CREATE', 'action should be CREATE');
47
- });
48
+ assertEq(actions.length, 1, 'should parse 1 action from fenced JSON');
49
+ assertEq(actions[0].action, 'CREATE', 'action should be CREATE');
50
+ }
48
51
 
49
52
  // ═══════════════════════════════════════════════════════════════════════════
50
53
  // memory-extractor: parse empty array response
51
54
  // ═══════════════════════════════════════════════════════════════════════════
52
55
 
53
- test('memory-extractor: parse empty array', () => {
56
+ console.log('\n=== memory-extractor: parse empty array ===');
57
+ {
54
58
  const actions = parseMemoryResponse('[]');
55
- assert.deepStrictEqual(actions.length, 0, 'empty array should parse to empty actions');
56
- });
59
+ assertEq(actions.length, 0, 'empty array should parse to empty actions');
60
+ }
57
61
 
58
62
  // ═══════════════════════════════════════════════════════════════════════════
59
63
  // memory-extractor: parse malformed response
60
64
  // ═══════════════════════════════════════════════════════════════════════════
61
65
 
62
- test('memory-extractor: malformed responses', () => {
63
- assert.deepStrictEqual(parseMemoryResponse('not json at all'), [], 'garbage text should return []');
64
- assert.deepStrictEqual(parseMemoryResponse('{"action": "CREATE"}'), [], 'non-array should return []');
65
- assert.deepStrictEqual(parseMemoryResponse(''), [], 'empty string should return []');
66
- assert.deepStrictEqual(parseMemoryResponse('```\nbroken\n```'), [], 'fenced non-JSON should return []');
67
- });
66
+ console.log('\n=== memory-extractor: malformed responses ===');
67
+ {
68
+ assertEq(parseMemoryResponse('not json at all'), [], 'garbage text should return []');
69
+ assertEq(parseMemoryResponse('{"action": "CREATE"}'), [], 'non-array should return []');
70
+ assertEq(parseMemoryResponse(''), [], 'empty string should return []');
71
+ assertEq(parseMemoryResponse('```\nbroken\n```'), [], 'fenced non-JSON should return []');
72
+ }
68
73
 
69
74
  // ═══════════════════════════════════════════════════════════════════════════
70
75
  // memory-extractor: validation of required fields
71
76
  // ═══════════════════════════════════════════════════════════════════════════
72
77
 
73
- test('memory-extractor: field validation', () => {
78
+ console.log('\n=== memory-extractor: field validation ===');
79
+ {
74
80
  const response = JSON.stringify([
75
81
  // Valid CREATE
76
82
  { action: 'CREATE', category: 'gotcha', content: 'valid' },
@@ -97,18 +103,19 @@ test('memory-extractor: field validation', () => {
97
103
  ]);
98
104
 
99
105
  const actions = parseMemoryResponse(response);
100
- assert.deepStrictEqual(actions.length, 4, 'should only accept 4 valid actions');
101
- assert.deepStrictEqual(actions[0].action, 'CREATE', 'first valid is CREATE');
102
- assert.deepStrictEqual(actions[1].action, 'REINFORCE', 'second valid is REINFORCE');
103
- assert.deepStrictEqual(actions[2].action, 'UPDATE', 'third valid is UPDATE');
104
- assert.deepStrictEqual(actions[3].action, 'SUPERSEDE', 'fourth valid is SUPERSEDE');
105
- });
106
+ assertEq(actions.length, 4, 'should only accept 4 valid actions');
107
+ assertEq(actions[0].action, 'CREATE', 'first valid is CREATE');
108
+ assertEq(actions[1].action, 'REINFORCE', 'second valid is REINFORCE');
109
+ assertEq(actions[2].action, 'UPDATE', 'third valid is UPDATE');
110
+ assertEq(actions[3].action, 'SUPERSEDE', 'fourth valid is SUPERSEDE');
111
+ }
106
112
 
107
113
  // ═══════════════════════════════════════════════════════════════════════════
108
114
  // Integration: applyMemoryActions with mixed actions
109
115
  // ═══════════════════════════════════════════════════════════════════════════
110
116
 
111
- test('integration: mixed action lifecycle', () => {
117
+ console.log('\n=== integration: mixed action lifecycle ===');
118
+ {
112
119
  openDatabase(':memory:');
113
120
 
114
121
  // Phase 1: Create initial memories
@@ -119,7 +126,7 @@ test('integration: mixed action lifecycle', () => {
119
126
  ], 'plan-slice', 'M001/S01');
120
127
 
121
128
  let active = getActiveMemoriesRanked(30);
122
- assert.deepStrictEqual(active.length, 3, 'phase 1: 3 active memories');
129
+ assertEq(active.length, 3, 'phase 1: 3 active memories');
123
130
 
124
131
  // Phase 2: Reinforce one, update another, create new
125
132
  applyMemoryActions([
@@ -129,13 +136,13 @@ test('integration: mixed action lifecycle', () => {
129
136
  ], 'execute-task', 'M001/S01/T01');
130
137
 
131
138
  active = getActiveMemoriesRanked(30);
132
- assert.deepStrictEqual(active.length, 4, 'phase 2: 4 active memories');
133
- assert.deepStrictEqual(
139
+ assertEq(active.length, 4, 'phase 2: 4 active memories');
140
+ assertEq(
134
141
  active.find(m => m.id === 'MEM001')?.content,
135
142
  'npm run build requires tsc --noEmit first',
136
143
  'MEM001 content should be updated',
137
144
  );
138
- assert.deepStrictEqual(active.find(m => m.id === 'MEM002')?.hit_count, 1, 'MEM002 should be reinforced');
145
+ assertEq(active.find(m => m.id === 'MEM002')?.hit_count, 1, 'MEM002 should be reinforced');
139
146
 
140
147
  // Phase 3: Supersede MEM001 with MEM005
141
148
  applyMemoryActions([
@@ -144,28 +151,30 @@ test('integration: mixed action lifecycle', () => {
144
151
  ], 'execute-task', 'M001/S01/T02');
145
152
 
146
153
  active = getActiveMemoriesRanked(30);
147
- assert.deepStrictEqual(active.length, 4, 'phase 3: 4 active (1 superseded, 1 created)');
148
- assert.ok(!active.find(m => m.id === 'MEM001'), 'MEM001 should be superseded');
149
- assert.ok(!!active.find(m => m.id === 'MEM005'), 'MEM005 should be active');
154
+ assertEq(active.length, 4, 'phase 3: 4 active (1 superseded, 1 created)');
155
+ assertTrue(!active.find(m => m.id === 'MEM001'), 'MEM001 should be superseded');
156
+ assertTrue(!!active.find(m => m.id === 'MEM005'), 'MEM005 should be active');
150
157
 
151
158
  // Verify ranking: MEM003 (0.85) > MEM005 (0.9) but MEM002 has 1 hit
152
159
  // MEM002: 0.8 * (1 + 1*0.1) = 0.88
153
160
  // MEM003: 0.85 * 1.0 = 0.85
154
161
  // MEM005: 0.9 * 1.0 = 0.9
155
162
  // MEM004: 0.75 * 1.0 = 0.75
156
- assert.deepStrictEqual(active[0].id, 'MEM005', 'MEM005 should rank first (0.9)');
157
- assert.deepStrictEqual(active[1].id, 'MEM002', 'MEM002 should rank second (0.88)');
163
+ assertEq(active[0].id, 'MEM005', 'MEM005 should rank first (0.9)');
164
+ assertEq(active[1].id, 'MEM002', 'MEM002 should rank second (0.88)');
158
165
 
159
166
  closeDatabase();
160
- });
167
+ }
161
168
 
162
169
  // ═══════════════════════════════════════════════════════════════════════════
163
170
  // memory-extractor: _resetExtractionState
164
171
  // ═══════════════════════════════════════════════════════════════════════════
165
172
 
166
- test('memory-extractor: reset extraction state', () => {
173
+ console.log('\n=== memory-extractor: reset extraction state ===');
174
+ {
167
175
  // Just verify it doesn't throw
168
176
  _resetExtractionState();
169
- assert.ok(true, '_resetExtractionState should not throw');
170
- });
177
+ assertTrue(true, '_resetExtractionState should not throw');
178
+ }
171
179
 
180
+ report();