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
@@ -66,7 +66,7 @@ function createFixture(): string {
66
66
  return base;
67
67
  }
68
68
 
69
- test("dispatch uat targets last completed slice, not activeSlice (#1693)", async (t) => {
69
+ test("dispatch uat targets last completed slice, not activeSlice (#1693)", async () => {
70
70
  const base = createFixture();
71
71
  invalidateStateCache();
72
72
 
@@ -88,29 +88,31 @@ test("dispatch uat targets last completed slice, not activeSlice (#1693)", async
88
88
  },
89
89
  } as any;
90
90
 
91
- t.after(() => rmSync(base, { recursive: true, force: true }));
92
-
93
- await dispatchDirectPhase(ctx, pi, "uat", base);
94
-
95
- // Should have dispatched (sendMessage called)
96
- assert.ok(sentPrompt, "sendMessage should have been called with a prompt");
97
-
98
- // The dispatch notification should reference M001/S01 (completed), not M001/S02 (active)
99
- const dispatchNotification = notifications.find(n => n.message.startsWith("Dispatching"));
100
- assert.ok(dispatchNotification, "dispatch notification should be present");
101
- assert.match(
102
- dispatchNotification.message,
103
- /M001\/S01/,
104
- "dispatch should target completed slice S01, not active slice S02",
105
- );
106
- assert.doesNotMatch(
107
- dispatchNotification.message,
108
- /M001\/S02/,
109
- "dispatch should NOT target active (next incomplete) slice S02",
110
- );
91
+ try {
92
+ await dispatchDirectPhase(ctx, pi, "uat", base);
93
+
94
+ // Should have dispatched (sendMessage called)
95
+ assert.ok(sentPrompt, "sendMessage should have been called with a prompt");
96
+
97
+ // The dispatch notification should reference M001/S01 (completed), not M001/S02 (active)
98
+ const dispatchNotification = notifications.find(n => n.message.startsWith("Dispatching"));
99
+ assert.ok(dispatchNotification, "dispatch notification should be present");
100
+ assert.match(
101
+ dispatchNotification.message,
102
+ /M001\/S01/,
103
+ "dispatch should target completed slice S01, not active slice S02",
104
+ );
105
+ assert.doesNotMatch(
106
+ dispatchNotification.message,
107
+ /M001\/S02/,
108
+ "dispatch should NOT target active (next incomplete) slice S02",
109
+ );
110
+ } finally {
111
+ rmSync(base, { recursive: true, force: true });
112
+ }
111
113
  });
112
114
 
113
- test("dispatch uat warns when no completed slices exist", async (t) => {
115
+ test("dispatch uat warns when no completed slices exist", async () => {
114
116
  const base = mkdtempSync(join(tmpdir(), "gsd-dispatch-uat-none-"));
115
117
  invalidateStateCache();
116
118
 
@@ -162,11 +164,13 @@ test("dispatch uat warns when no completed slices exist", async (t) => {
162
164
  },
163
165
  } as any;
164
166
 
165
- t.after(() => rmSync(base, { recursive: true, force: true }));
166
-
167
- await dispatchDirectPhase(ctx, pi, "uat", base);
167
+ try {
168
+ await dispatchDirectPhase(ctx, pi, "uat", base);
168
169
 
169
- const warning = notifications.find(n => n.level === "warning");
170
- assert.ok(warning, "should show a warning notification");
171
- assert.match(warning.message, /no completed slices/, "warning should mention no completed slices");
170
+ const warning = notifications.find(n => n.level === "warning");
171
+ assert.ok(warning, "should show a warning notification");
172
+ assert.match(warning.message, /no completed slices/, "warning should mention no completed slices");
173
+ } finally {
174
+ rmSync(base, { recursive: true, force: true });
175
+ }
172
176
  });
@@ -56,33 +56,35 @@ Done.
56
56
  `);
57
57
  }
58
58
 
59
- test("doctor does not report any reconciliation issue codes", async (t) => {
59
+ test("doctor does not report any reconciliation issue codes", async () => {
60
60
  const tmp = makeTmp("no-reconciliation");
61
- t.after(() => rmSync(tmp, { recursive: true, force: true }));
62
-
63
- buildScaffold(tmp);
64
-
65
- const report = await runGSDDoctor(tmp, { fix: true, fixLevel: "task" });
66
-
67
- const REMOVED_CODES = [
68
- "task_done_missing_summary",
69
- "task_summary_without_done_checkbox",
70
- "all_tasks_done_missing_slice_summary",
71
- "all_tasks_done_missing_slice_uat",
72
- "all_tasks_done_roadmap_not_checked",
73
- "slice_checked_missing_summary",
74
- "slice_checked_missing_uat",
75
- ];
76
-
77
- const codes = report.issues.map(i => i.code);
78
- for (const removed of REMOVED_CODES) {
79
- assert.ok(!codes.includes(removed as any), `should NOT report removed code: ${removed}`);
61
+ try {
62
+ buildScaffold(tmp);
63
+
64
+ const report = await runGSDDoctor(tmp, { fix: true, fixLevel: "task" });
65
+
66
+ const REMOVED_CODES = [
67
+ "task_done_missing_summary",
68
+ "task_summary_without_done_checkbox",
69
+ "all_tasks_done_missing_slice_summary",
70
+ "all_tasks_done_missing_slice_uat",
71
+ "all_tasks_done_roadmap_not_checked",
72
+ "slice_checked_missing_summary",
73
+ "slice_checked_missing_uat",
74
+ ];
75
+
76
+ const codes = report.issues.map(i => i.code);
77
+ for (const removed of REMOVED_CODES) {
78
+ assert.ok(!codes.includes(removed as any), `should NOT report removed code: ${removed}`);
79
+ }
80
+
81
+ // No summary or UAT stubs should be created
82
+ const sliceSummaryPath = join(tmp, ".gsd", "milestones", "M001", "slices", "S01", "S01-SUMMARY.md");
83
+ assert.ok(!existsSync(sliceSummaryPath), "should NOT have created summary stub");
84
+
85
+ const sliceUatPath = join(tmp, ".gsd", "milestones", "M001", "slices", "S01", "S01-UAT.md");
86
+ assert.ok(!existsSync(sliceUatPath), "should NOT have created UAT stub");
87
+ } finally {
88
+ rmSync(tmp, { recursive: true, force: true });
80
89
  }
81
-
82
- // No summary or UAT stubs should be created
83
- const sliceSummaryPath = join(tmp, ".gsd", "milestones", "M001", "slices", "S01", "S01-SUMMARY.md");
84
- assert.ok(!existsSync(sliceSummaryPath), "should NOT have created summary stub");
85
-
86
- const sliceUatPath = join(tmp, ".gsd", "milestones", "M001", "slices", "S01", "S01-UAT.md");
87
- assert.ok(!existsSync(sliceUatPath), "should NOT have created UAT stub");
88
90
  });
@@ -12,7 +12,7 @@ import { join } from "node:path";
12
12
  import { tmpdir } from "node:os";
13
13
  import { runGSDDoctor } from "../doctor.js";
14
14
 
15
- test("doctor fix=true sanitizes em-dash in milestone title", async (t) => {
15
+ test("doctor fix=true sanitizes em-dash in milestone title", async () => {
16
16
  const tmpBase = mkdtempSync(join(tmpdir(), "gsd-doctor-delim-"));
17
17
  const gsd = join(tmpBase, ".gsd");
18
18
  const mDir = join(gsd, "milestones", "M001");
@@ -34,31 +34,33 @@ test("doctor fix=true sanitizes em-dash in milestone title", async (t) => {
34
34
  writeFileSync(join(sDir, "S01-PLAN.md"), `# S01: Initial Setup\n\n## Tasks\n- [ ] **T01: Scaffold** \`est:15m\`\n`);
35
35
  writeFileSync(join(tDir, "T01-PLAN.md"), "# T01: Scaffold\n");
36
36
 
37
- t.after(() => rmSync(tmpBase, { recursive: true, force: true }));
38
-
39
- // Run doctor with fix=true
40
- const report = await runGSDDoctor(tmpBase, { fix: true });
41
-
42
- // The em-dash should have been replaced
43
- const fixed = readFileSync(join(mDir, "M001-ROADMAP.md"), "utf-8");
44
- const h1 = fixed.split("\n").find(l => l.startsWith("# "))!;
45
- assert.ok(h1, "H1 line should exist");
46
- assert.ok(!h1.includes("\u2014"), "em-dash should be replaced");
47
- assert.ok(!h1.includes("\u2013"), "en-dash should be replaced");
48
- assert.ok(h1.includes("-"), "should contain ASCII hyphen as replacement");
49
-
50
- // Should have recorded the fix
51
- assert.ok(
52
- report.fixesApplied.some(f => f.includes("sanitized")),
53
- `fixesApplied should mention sanitization, got: ${JSON.stringify(report.fixesApplied)}`,
54
- );
55
-
56
- // The issue should NOT appear in the report (it was fixed)
57
- const delimIssues = report.issues.filter(i => i.code === "delimiter_in_title" && i.unitId === "M001");
58
- assert.equal(delimIssues.length, 0, "fixed issue should not appear in issues list");
37
+ try {
38
+ // Run doctor with fix=true
39
+ const report = await runGSDDoctor(tmpBase, { fix: true });
40
+
41
+ // The em-dash should have been replaced
42
+ const fixed = readFileSync(join(mDir, "M001-ROADMAP.md"), "utf-8");
43
+ const h1 = fixed.split("\n").find(l => l.startsWith("# "))!;
44
+ assert.ok(h1, "H1 line should exist");
45
+ assert.ok(!h1.includes("\u2014"), "em-dash should be replaced");
46
+ assert.ok(!h1.includes("\u2013"), "en-dash should be replaced");
47
+ assert.ok(h1.includes("-"), "should contain ASCII hyphen as replacement");
48
+
49
+ // Should have recorded the fix
50
+ assert.ok(
51
+ report.fixesApplied.some(f => f.includes("sanitized")),
52
+ `fixesApplied should mention sanitization, got: ${JSON.stringify(report.fixesApplied)}`,
53
+ );
54
+
55
+ // The issue should NOT appear in the report (it was fixed)
56
+ const delimIssues = report.issues.filter(i => i.code === "delimiter_in_title" && i.unitId === "M001");
57
+ assert.equal(delimIssues.length, 0, "fixed issue should not appear in issues list");
58
+ } finally {
59
+ rmSync(tmpBase, { recursive: true, force: true });
60
+ }
59
61
  });
60
62
 
61
- test("doctor fix=false still reports delimiter_in_title as warning", async (t) => {
63
+ test("doctor fix=false still reports delimiter_in_title as warning", async () => {
62
64
  const tmpBase = mkdtempSync(join(tmpdir(), "gsd-doctor-delim-nf-"));
63
65
  const gsd = join(tmpBase, ".gsd");
64
66
  const mDir = join(gsd, "milestones", "M001");
@@ -70,14 +72,16 @@ test("doctor fix=false still reports delimiter_in_title as warning", async (t) =
70
72
  writeFileSync(join(sDir, "S01-PLAN.md"), `# S01: Setup\n\n## Tasks\n- [ ] **T01: Init** \`est:10m\`\n`);
71
73
  writeFileSync(join(tDir, "T01-PLAN.md"), "# T01: Init\n");
72
74
 
73
- t.after(() => rmSync(tmpBase, { recursive: true, force: true }));
74
-
75
- const report = await runGSDDoctor(tmpBase, { fix: false });
76
- const delimIssues = report.issues.filter(i => i.code === "delimiter_in_title");
77
- assert.ok(delimIssues.length > 0, "should report delimiter_in_title as issue when fix=false");
78
- assert.equal(delimIssues[0].severity, "warning");
79
-
80
- // File should be unchanged
81
- const content = readFileSync(join(mDir, "M001-ROADMAP.md"), "utf-8");
82
- assert.ok(content.includes("\u2014"), "file should not be modified when fix=false");
75
+ try {
76
+ const report = await runGSDDoctor(tmpBase, { fix: false });
77
+ const delimIssues = report.issues.filter(i => i.code === "delimiter_in_title");
78
+ assert.ok(delimIssues.length > 0, "should report delimiter_in_title as issue when fix=false");
79
+ assert.equal(delimIssues[0].severity, "warning");
80
+
81
+ // File should be unchanged
82
+ const content = readFileSync(join(mDir, "M001-ROADMAP.md"), "utf-8");
83
+ assert.ok(content.includes("\u2014"), "file should not be modified when fix=false");
84
+ } finally {
85
+ rmSync(tmpBase, { recursive: true, force: true });
86
+ }
83
87
  });
@@ -1,11 +1,13 @@
1
- import { describe, test } from 'node:test';
2
- import assert from 'node:assert/strict';
3
1
  import { mkdtempSync, mkdirSync, rmSync, writeFileSync, existsSync } from "node:fs";
4
2
  import { join } from "node:path";
5
3
  import { tmpdir } from "node:os";
6
4
 
7
5
  import { runGSDDoctor } from "../doctor.js";
8
6
  import { formatDoctorReportJson } from "../doctor-format.js";
7
+ import { createTestContext } from "./test-helpers.ts";
8
+
9
+ const { assertEq, assertTrue, assertMatch, report } = createTestContext();
10
+
9
11
  // ── Helpers ─────────────────────────────────────────────────────────────────
10
12
 
11
13
  function makeBase(): { base: string; gsd: string; mDir: string } {
@@ -28,38 +30,41 @@ function writeSlice(mDir: string, sliceId: string, planContent: string): string
28
30
  return sDir;
29
31
  }
30
32
 
31
- describe('doctor-enhancements', async () => {
33
+ async function main(): Promise<void> {
32
34
  // ── 1. Circular dependency detection ──────────────────────────────────────
33
- test('circular dependency detection', async () => {
35
+ console.log("\n=== circular dependency detection ===");
36
+ {
34
37
  const { base, mDir } = makeBase();
35
38
  writeRoadmap(mDir, `# M001: Circular Test\n\n## Slices\n- [ ] **S01: Slice A** \`risk:low\` \`depends:[S02]\`\n > After this: done\n- [ ] **S02: Slice B** \`risk:low\` \`depends:[S01]\`\n > After this: done\n`);
36
39
  writeSlice(mDir, "S01", "# S01: Slice A\n\n**Goal:** A\n**Demo:** A\n\n## Tasks\n- [ ] **T01: Task** `est:10m`\n Pending.\n");
37
40
  writeSlice(mDir, "S02", "# S02: Slice B\n\n**Goal:** B\n**Demo:** B\n\n## Tasks\n- [ ] **T01: Task** `est:10m`\n Pending.\n");
38
41
 
39
42
  const result = await runGSDDoctor(base, { fix: false });
40
- assert.ok(
43
+ assertTrue(
41
44
  result.issues.some(i => i.code === "circular_slice_dependency"),
42
45
  "detects circular dependency S01 → S02 → S01",
43
46
  );
44
47
  rmSync(base, { recursive: true, force: true });
45
- });
48
+ }
46
49
 
47
50
  // ── 2. Duplicate task IDs ──────────────────────────────────────────────────
48
- test('duplicate task IDs', async () => {
51
+ console.log("\n=== duplicate task IDs ===");
52
+ {
49
53
  const { base, mDir } = makeBase();
50
54
  writeRoadmap(mDir, `# M001: Dup Test\n\n## Slices\n- [ ] **S01: Slice** \`risk:low\` \`depends:[]\`\n > After this: done\n`);
51
55
  writeSlice(mDir, "S01", "# S01: Slice\n\n**Goal:** G\n**Demo:** D\n\n## Tasks\n- [ ] **T01: First** `est:10m`\n Task one.\n- [ ] **T01: Duplicate** `est:10m`\n Task dup.\n");
52
56
 
53
57
  const result = await runGSDDoctor(base, { fix: false });
54
- assert.ok(
58
+ assertTrue(
55
59
  result.issues.some(i => i.code === "duplicate_task_id"),
56
60
  "detects duplicate task ID T01",
57
61
  );
58
62
  rmSync(base, { recursive: true, force: true });
59
- });
63
+ }
60
64
 
61
65
  // ── 3. Orphaned slice directory ──────────────────────────────────────────
62
- test('orphaned slice directory', async () => {
66
+ console.log("\n=== orphaned slice directory ===");
67
+ {
63
68
  const { base, mDir } = makeBase();
64
69
  writeRoadmap(mDir, `# M001: Orphan Test\n\n## Slices\n- [ ] **S01: Slice** \`risk:low\` \`depends:[]\`\n > After this: done\n`);
65
70
  writeSlice(mDir, "S01", "# S01: Slice\n\n**Goal:** G\n**Demo:** D\n\n## Tasks\n- [ ] **T01: Task** `est:10m`\n Pending.\n");
@@ -67,15 +72,16 @@ describe('doctor-enhancements', async () => {
67
72
  mkdirSync(join(mDir, "slices", "S99"), { recursive: true });
68
73
 
69
74
  const result = await runGSDDoctor(base, { fix: false });
70
- assert.ok(
75
+ assertTrue(
71
76
  result.issues.some(i => i.code === "orphaned_slice_directory" && i.message.includes("S99")),
72
77
  "detects orphaned slice directory S99",
73
78
  );
74
79
  rmSync(base, { recursive: true, force: true });
75
- });
80
+ }
76
81
 
77
82
  // ── 4. Task file not in plan ───────────────────────────────────────────────
78
- test('task file not in plan', async () => {
83
+ console.log("\n=== task file not in plan ===");
84
+ {
79
85
  const { base, mDir } = makeBase();
80
86
  writeRoadmap(mDir, `# M001: Extra Task Test\n\n## Slices\n- [ ] **S01: Slice** \`risk:low\` \`depends:[]\`\n > After this: done\n`);
81
87
  const sDir = writeSlice(mDir, "S01", "# S01: Slice\n\n**Goal:** G\n**Demo:** D\n\n## Tasks\n- [x] **T01: Task** `est:10m`\n Done.\n");
@@ -85,15 +91,16 @@ describe('doctor-enhancements', async () => {
85
91
  writeFileSync(join(sDir, "tasks", "T99-SUMMARY.md"), "---\nstatus: done\n---\n# T99\nExtra.\n");
86
92
 
87
93
  const result = await runGSDDoctor(base, { fix: false });
88
- assert.ok(
94
+ assertTrue(
89
95
  result.issues.some(i => i.code === "task_file_not_in_plan" && i.message.includes("T99")),
90
96
  "detects task summary T99 not in plan",
91
97
  );
92
98
  rmSync(base, { recursive: true, force: true });
93
- });
99
+ }
94
100
 
95
101
  // ── 5. Stale REPLAN file ────────────────────────────────────────────────────
96
- test('stale REPLAN detection', async () => {
102
+ console.log("\n=== stale REPLAN detection ===");
103
+ {
97
104
  const { base, mDir } = makeBase();
98
105
  writeRoadmap(mDir, `# M001: Replan Test\n\n## Slices\n- [ ] **S01: Slice** \`risk:low\` \`depends:[]\`\n > After this: done\n`);
99
106
  const sDir = writeSlice(mDir, "S01", "# S01: Slice\n\n**Goal:** G\n**Demo:** D\n\n## Tasks\n- [x] **T01: Task** `est:10m`\n Done.\n");
@@ -102,15 +109,16 @@ describe('doctor-enhancements', async () => {
102
109
  writeFileSync(join(sDir, "S01-REPLAN.md"), "# S01 REPLAN\nSomething changed.\n");
103
110
 
104
111
  const result = await runGSDDoctor(base, { fix: false });
105
- assert.ok(
112
+ assertTrue(
106
113
  result.issues.some(i => i.code === "stale_replan_file"),
107
114
  "detects stale REPLAN when all tasks are done",
108
115
  );
109
116
  rmSync(base, { recursive: true, force: true });
110
- });
117
+ }
111
118
 
112
119
  // ── 6. Metrics ledger corrupt ───────────────────────────────────────────────
113
- test('metrics ledger corrupt', async () => {
120
+ console.log("\n=== metrics ledger corrupt ===");
121
+ {
114
122
  const { base, gsd, mDir } = makeBase();
115
123
  writeRoadmap(mDir, `# M001: Metrics Test\n\n## Slices\n- [ ] **S01: Slice** \`risk:low\` \`depends:[]\`\n > After this: done\n`);
116
124
  writeSlice(mDir, "S01", "# S01: Slice\n\n**Goal:** G\n**Demo:** D\n\n## Tasks\n- [ ] **T01: Task** `est:10m`\n Pending.\n");
@@ -118,15 +126,16 @@ describe('doctor-enhancements', async () => {
118
126
  writeFileSync(join(gsd, "metrics.json"), '{"version":2,"data":[]}');
119
127
 
120
128
  const result = await runGSDDoctor(base, { fix: false });
121
- assert.ok(
129
+ assertTrue(
122
130
  result.issues.some(i => i.code === "metrics_ledger_corrupt"),
123
131
  "detects corrupt metrics ledger (version != 1)",
124
132
  );
125
133
  rmSync(base, { recursive: true, force: true });
126
- });
134
+ }
127
135
 
128
136
  // ── 7. Large planning file ──────────────────────────────────────────────────
129
- test('large planning file', async () => {
137
+ console.log("\n=== large planning file ===");
138
+ {
130
139
  const { base, mDir } = makeBase();
131
140
  writeRoadmap(mDir, `# M001: Large File Test\n\n## Slices\n- [ ] **S01: Slice** \`risk:low\` \`depends:[]\`\n > After this: done\n`);
132
141
  const sDir = writeSlice(mDir, "S01", "# S01: Slice\n\n**Goal:** G\n**Demo:** D\n\n## Tasks\n- [ ] **T01: Task** `est:10m`\n Pending.\n");
@@ -135,15 +144,16 @@ describe('doctor-enhancements', async () => {
135
144
  writeFileSync(join(sDir, "BIGFILE.md"), bigContent);
136
145
 
137
146
  const result = await runGSDDoctor(base, { fix: false });
138
- assert.ok(
147
+ assertTrue(
139
148
  result.issues.some(i => i.code === "large_planning_file"),
140
149
  "detects large planning file over 100KB",
141
150
  );
142
151
  rmSync(base, { recursive: true, force: true });
143
- });
152
+ }
144
153
 
145
154
  // ── 8. Future timestamp ─────────────────────────────────────────────────────
146
- test('future timestamp', async () => {
155
+ console.log("\n=== future timestamp ===");
156
+ {
147
157
  const { base, mDir } = makeBase();
148
158
  writeRoadmap(mDir, `# M001: Timestamp Test\n\n## Slices\n- [ ] **S01: Slice** \`risk:low\` \`depends:[]\`\n > After this: done\n`);
149
159
  const sDir = writeSlice(mDir, "S01", "# S01: Slice\n\n**Goal:** G\n**Demo:** D\n\n## Tasks\n- [x] **T01: Task** `est:10m`\n Done.\n");
@@ -155,15 +165,16 @@ describe('doctor-enhancements', async () => {
155
165
  );
156
166
 
157
167
  const result = await runGSDDoctor(base, { fix: false });
158
- assert.ok(
168
+ assertTrue(
159
169
  result.issues.some(i => i.code === "future_timestamp"),
160
170
  "detects future completed_at timestamp",
161
171
  );
162
172
  rmSync(base, { recursive: true, force: true });
163
- });
173
+ }
164
174
 
165
175
  // ── 9. JSON output format ───────────────────────────────────────────────────
166
- test('JSON output format', async () => {
176
+ console.log("\n=== JSON output format ===");
177
+ {
167
178
  const { base, mDir } = makeBase();
168
179
  writeRoadmap(mDir, `# M001: JSON Test\n\n## Slices\n- [ ] **S01: Slice** \`risk:low\` \`depends:[]\`\n > After this: done\n`);
169
180
  writeSlice(mDir, "S01", "# S01: Slice\n\n**Goal:** G\n**Demo:** D\n\n## Tasks\n- [ ] **T01: Task** `est:10m`\n Pending.\n");
@@ -178,18 +189,19 @@ describe('doctor-enhancements', async () => {
178
189
  parsed = null;
179
190
  }
180
191
 
181
- assert.ok(parsed !== null, "formatDoctorReportJson produces valid JSON");
182
- assert.ok(typeof (parsed as Record<string, unknown>)?.ok === "boolean", "JSON has ok field");
183
- assert.ok(Array.isArray((parsed as Record<string, unknown>)?.issues), "JSON has issues array");
184
- assert.ok(Array.isArray((parsed as Record<string, unknown>)?.fixesApplied), "JSON has fixesApplied array");
185
- assert.ok(typeof (parsed as Record<string, unknown>)?.generatedAt === "string", "JSON has generatedAt field");
186
- assert.ok(typeof (parsed as Record<string, unknown>)?.summary === "object", "JSON has summary object");
192
+ assertTrue(parsed !== null, "formatDoctorReportJson produces valid JSON");
193
+ assertTrue(typeof (parsed as Record<string, unknown>)?.ok === "boolean", "JSON has ok field");
194
+ assertTrue(Array.isArray((parsed as Record<string, unknown>)?.issues), "JSON has issues array");
195
+ assertTrue(Array.isArray((parsed as Record<string, unknown>)?.fixesApplied), "JSON has fixesApplied array");
196
+ assertTrue(typeof (parsed as Record<string, unknown>)?.generatedAt === "string", "JSON has generatedAt field");
197
+ assertTrue(typeof (parsed as Record<string, unknown>)?.summary === "object", "JSON has summary object");
187
198
 
188
199
  rmSync(base, { recursive: true, force: true });
189
- });
200
+ }
190
201
 
191
202
  // ── 10. Dry-run mode ────────────────────────────────────────────────────────
192
- test('dry-run mode', async () => {
203
+ console.log("\n=== dry-run mode ===");
204
+ {
193
205
  const { base, mDir } = makeBase();
194
206
  writeRoadmap(mDir, `# M001: Dry Run Test\n\n## Slices\n- [ ] **S01: Slice** \`risk:low\` \`depends:[]\`\n > After this: done\n`);
195
207
  writeSlice(mDir, "S01", "# S01: Slice\n\n**Goal:** G\n**Demo:** D\n\n## Tasks\n- [ ] **T01: Task** `est:10m`\n Pending.\n");
@@ -197,30 +209,32 @@ describe('doctor-enhancements', async () => {
197
209
  const result = await runGSDDoctor(base, { fix: true, dryRun: true });
198
210
  // dry-run with fix:true still runs the doctor; shouldFix() returns false
199
211
  // so no reconciliation fixes are applied through that path
200
- assert.ok(result.issues !== undefined, "dry-run still produces issue list");
201
- assert.ok(Array.isArray(result.fixesApplied), "dry-run report has fixesApplied array");
212
+ assertTrue(result.issues !== undefined, "dry-run still produces issue list");
213
+ assertTrue(Array.isArray(result.fixesApplied), "dry-run report has fixesApplied array");
202
214
 
203
215
  rmSync(base, { recursive: true, force: true });
204
- });
216
+ }
205
217
 
206
218
  // ── 11. Per-check timing ─────────────────────────────────────────────────────
207
- test('per-check timing', async () => {
219
+ console.log("\n=== per-check timing ===");
220
+ {
208
221
  const { base, mDir } = makeBase();
209
222
  writeRoadmap(mDir, `# M001: Timing Test\n\n## Slices\n- [ ] **S01: Slice** \`risk:low\` \`depends:[]\`\n > After this: done\n`);
210
223
  writeSlice(mDir, "S01", "# S01: Slice\n\n**Goal:** G\n**Demo:** D\n\n## Tasks\n- [ ] **T01: Task** `est:10m`\n Pending.\n");
211
224
 
212
225
  const result = await runGSDDoctor(base, { fix: false });
213
- assert.ok(result.timing !== undefined, "report includes timing");
214
- assert.ok(typeof result.timing?.git === "number", "timing.git is a number");
215
- assert.ok(typeof result.timing?.runtime === "number", "timing.runtime is a number");
216
- assert.ok(typeof result.timing?.environment === "number", "timing.environment is a number");
217
- assert.ok(typeof result.timing?.gsdState === "number", "timing.gsdState is a number");
226
+ assertTrue(result.timing !== undefined, "report includes timing");
227
+ assertTrue(typeof result.timing?.git === "number", "timing.git is a number");
228
+ assertTrue(typeof result.timing?.runtime === "number", "timing.runtime is a number");
229
+ assertTrue(typeof result.timing?.environment === "number", "timing.environment is a number");
230
+ assertTrue(typeof result.timing?.gsdState === "number", "timing.gsdState is a number");
218
231
 
219
232
  rmSync(base, { recursive: true, force: true });
220
- });
233
+ }
221
234
 
222
235
  // ── 12. Doctor history ───────────────────────────────────────────────────────
223
- test('doctor history', async () => {
236
+ console.log("\n=== doctor history ===");
237
+ {
224
238
  const { base, gsd, mDir } = makeBase();
225
239
  writeRoadmap(mDir, `# M001: History Test\n\n## Slices\n- [ ] **S01: Slice** \`risk:low\` \`depends:[]\`\n > After this: done\n`);
226
240
  writeSlice(mDir, "S01", "# S01: Slice\n\n**Goal:** G\n**Demo:** D\n\n## Tasks\n- [ ] **T01: Task** `est:10m`\n Pending.\n");
@@ -228,16 +242,23 @@ describe('doctor-enhancements', async () => {
228
242
  await runGSDDoctor(base, { fix: false });
229
243
 
230
244
  const historyPath = join(gsd, "doctor-history.jsonl");
231
- assert.ok(existsSync(historyPath), "doctor-history.jsonl is created after run");
245
+ assertTrue(existsSync(historyPath), "doctor-history.jsonl is created after run");
232
246
 
233
247
  const { readDoctorHistory } = await import("../doctor.js");
234
248
  const history = await readDoctorHistory(base);
235
- assert.ok(history.length >= 1, "history has at least one entry");
236
- assert.ok(typeof history[0]?.ts === "string", "history entry has ts field");
237
- assert.ok(typeof history[0]?.ok === "boolean", "history entry has ok field");
238
- assert.ok(typeof history[0]?.errors === "number", "history entry has errors count");
239
- assert.ok(Array.isArray(history[0]?.codes), "history entry has codes array");
249
+ assertTrue(history.length >= 1, "history has at least one entry");
250
+ assertTrue(typeof history[0]?.ts === "string", "history entry has ts field");
251
+ assertTrue(typeof history[0]?.ok === "boolean", "history entry has ok field");
252
+ assertTrue(typeof history[0]?.errors === "number", "history entry has errors count");
253
+ assertTrue(Array.isArray(history[0]?.codes), "history entry has codes array");
240
254
 
241
255
  rmSync(base, { recursive: true, force: true });
242
- });
256
+ }
257
+
258
+ report();
259
+ }
260
+
261
+ main().catch(err => {
262
+ console.error(err);
263
+ process.exit(1);
243
264
  });