gsd-pi 2.44.0 → 2.45.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 (402) hide show
  1. package/README.md +30 -12
  2. package/dist/resources/extensions/gsd/activity-log.js +7 -0
  3. package/dist/resources/extensions/gsd/auto/infra-errors.js +3 -0
  4. package/dist/resources/extensions/gsd/auto/phases.js +37 -36
  5. package/dist/resources/extensions/gsd/auto-prompts.js +24 -1
  6. package/dist/resources/extensions/gsd/auto-start.js +31 -2
  7. package/dist/resources/extensions/gsd/auto-timers.js +57 -3
  8. package/dist/resources/extensions/gsd/auto-worktree-sync.js +4 -0
  9. package/dist/resources/extensions/gsd/auto-worktree.js +9 -6
  10. package/dist/resources/extensions/gsd/auto.js +30 -3
  11. package/dist/resources/extensions/gsd/bootstrap/db-tools.js +156 -0
  12. package/dist/resources/extensions/gsd/bootstrap/system-context.js +46 -12
  13. package/dist/resources/extensions/gsd/commands/catalog.js +7 -1
  14. package/dist/resources/extensions/gsd/commands/handlers/core.js +2 -0
  15. package/dist/resources/extensions/gsd/commands/handlers/ops.js +10 -0
  16. package/dist/resources/extensions/gsd/commands/handlers/workflow.js +5 -0
  17. package/dist/resources/extensions/gsd/commands-mcp-status.js +187 -0
  18. package/dist/resources/extensions/gsd/db-writer.js +34 -16
  19. package/dist/resources/extensions/gsd/doctor.js +8 -0
  20. package/dist/resources/extensions/gsd/git-service.js +8 -3
  21. package/dist/resources/extensions/gsd/gsd-db.js +12 -1
  22. package/dist/resources/extensions/gsd/markdown-renderer.js +1 -1
  23. package/dist/resources/extensions/gsd/preferences.js +9 -1
  24. package/dist/resources/extensions/gsd/prompts/complete-milestone.md +2 -4
  25. package/dist/resources/extensions/gsd/prompts/plan-slice.md +1 -1
  26. package/dist/resources/extensions/gsd/prompts/reassess-roadmap.md +6 -6
  27. package/dist/resources/extensions/gsd/prompts/replan-slice.md +3 -14
  28. package/dist/resources/extensions/gsd/prompts/rethink.md +78 -0
  29. package/dist/resources/extensions/gsd/prompts/validate-milestone.md +7 -37
  30. package/dist/resources/extensions/gsd/provider-error-pause.js +7 -0
  31. package/dist/resources/extensions/gsd/repo-identity.js +45 -7
  32. package/dist/resources/extensions/gsd/rethink.js +115 -0
  33. package/dist/resources/extensions/gsd/state.js +41 -3
  34. package/dist/resources/extensions/gsd/tools/plan-slice.js +1 -0
  35. package/dist/resources/extensions/gsd/tools/plan-task.js +1 -0
  36. package/dist/resources/extensions/gsd/tools/replan-slice.js +2 -0
  37. package/dist/resources/extensions/gsd/tools/validate-milestone.js +88 -0
  38. package/dist/resources/extensions/gsd/worktree-manager.js +32 -2
  39. package/dist/resources/extensions/gsd/worktree-resolver.js +6 -0
  40. package/dist/resources/extensions/mcp-client/index.js +14 -0
  41. package/dist/web/standalone/.next/BUILD_ID +1 -1
  42. package/dist/web/standalone/.next/app-path-routes-manifest.json +7 -7
  43. package/dist/web/standalone/.next/build-manifest.json +3 -3
  44. package/dist/web/standalone/.next/prerender-manifest.json +3 -3
  45. package/dist/web/standalone/.next/react-loadable-manifest.json +2 -2
  46. package/dist/web/standalone/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
  47. package/dist/web/standalone/.next/server/app/_global-error.html +2 -2
  48. package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
  49. package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  50. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
  51. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
  52. package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  53. package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  54. package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  55. package/dist/web/standalone/.next/server/app/_not-found/page.js +1 -1
  56. package/dist/web/standalone/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  57. package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
  58. package/dist/web/standalone/.next/server/app/_not-found.rsc +3 -3
  59. package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +3 -3
  60. package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  61. package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +2 -2
  62. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  63. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  64. package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +2 -2
  65. package/dist/web/standalone/.next/server/app/api/boot/route_client-reference-manifest.js +1 -1
  66. package/dist/web/standalone/.next/server/app/api/bridge-terminal/input/route_client-reference-manifest.js +1 -1
  67. package/dist/web/standalone/.next/server/app/api/bridge-terminal/resize/route_client-reference-manifest.js +1 -1
  68. package/dist/web/standalone/.next/server/app/api/bridge-terminal/stream/route_client-reference-manifest.js +1 -1
  69. package/dist/web/standalone/.next/server/app/api/browse-directories/route_client-reference-manifest.js +1 -1
  70. package/dist/web/standalone/.next/server/app/api/captures/route_client-reference-manifest.js +1 -1
  71. package/dist/web/standalone/.next/server/app/api/cleanup/route_client-reference-manifest.js +1 -1
  72. package/dist/web/standalone/.next/server/app/api/dev-mode/route_client-reference-manifest.js +1 -1
  73. package/dist/web/standalone/.next/server/app/api/doctor/route_client-reference-manifest.js +1 -1
  74. package/dist/web/standalone/.next/server/app/api/export-data/route_client-reference-manifest.js +1 -1
  75. package/dist/web/standalone/.next/server/app/api/files/route_client-reference-manifest.js +1 -1
  76. package/dist/web/standalone/.next/server/app/api/forensics/route_client-reference-manifest.js +1 -1
  77. package/dist/web/standalone/.next/server/app/api/git/route_client-reference-manifest.js +1 -1
  78. package/dist/web/standalone/.next/server/app/api/history/route_client-reference-manifest.js +1 -1
  79. package/dist/web/standalone/.next/server/app/api/hooks/route_client-reference-manifest.js +1 -1
  80. package/dist/web/standalone/.next/server/app/api/inspect/route_client-reference-manifest.js +1 -1
  81. package/dist/web/standalone/.next/server/app/api/knowledge/route_client-reference-manifest.js +1 -1
  82. package/dist/web/standalone/.next/server/app/api/live-state/route_client-reference-manifest.js +1 -1
  83. package/dist/web/standalone/.next/server/app/api/onboarding/route_client-reference-manifest.js +1 -1
  84. package/dist/web/standalone/.next/server/app/api/preferences/route_client-reference-manifest.js +1 -1
  85. package/dist/web/standalone/.next/server/app/api/projects/route_client-reference-manifest.js +1 -1
  86. package/dist/web/standalone/.next/server/app/api/recovery/route_client-reference-manifest.js +1 -1
  87. package/dist/web/standalone/.next/server/app/api/remote-questions/route_client-reference-manifest.js +1 -1
  88. package/dist/web/standalone/.next/server/app/api/session/browser/route_client-reference-manifest.js +1 -1
  89. package/dist/web/standalone/.next/server/app/api/session/command/route_client-reference-manifest.js +1 -1
  90. package/dist/web/standalone/.next/server/app/api/session/events/route_client-reference-manifest.js +1 -1
  91. package/dist/web/standalone/.next/server/app/api/session/manage/route_client-reference-manifest.js +1 -1
  92. package/dist/web/standalone/.next/server/app/api/settings-data/route_client-reference-manifest.js +1 -1
  93. package/dist/web/standalone/.next/server/app/api/shutdown/route_client-reference-manifest.js +1 -1
  94. package/dist/web/standalone/.next/server/app/api/skill-health/route_client-reference-manifest.js +1 -1
  95. package/dist/web/standalone/.next/server/app/api/steer/route_client-reference-manifest.js +1 -1
  96. package/dist/web/standalone/.next/server/app/api/switch-root/route_client-reference-manifest.js +1 -1
  97. package/dist/web/standalone/.next/server/app/api/terminal/input/route_client-reference-manifest.js +1 -1
  98. package/dist/web/standalone/.next/server/app/api/terminal/resize/route_client-reference-manifest.js +1 -1
  99. package/dist/web/standalone/.next/server/app/api/terminal/sessions/route_client-reference-manifest.js +1 -1
  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_client-reference-manifest.js +1 -1
  102. package/dist/web/standalone/.next/server/app/api/undo/route_client-reference-manifest.js +1 -1
  103. package/dist/web/standalone/.next/server/app/api/update/route_client-reference-manifest.js +1 -1
  104. package/dist/web/standalone/.next/server/app/api/visualizer/route_client-reference-manifest.js +1 -1
  105. package/dist/web/standalone/.next/server/app/index.html +1 -1
  106. package/dist/web/standalone/.next/server/app/index.rsc +4 -4
  107. package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +2 -2
  108. package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +4 -4
  109. package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
  110. package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +2 -2
  111. package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +2 -2
  112. package/dist/web/standalone/.next/server/app/page.js +1 -1
  113. package/dist/web/standalone/.next/server/app/page_client-reference-manifest.js +1 -1
  114. package/dist/web/standalone/.next/server/app-paths-manifest.json +7 -7
  115. package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
  116. package/dist/web/standalone/.next/server/middleware-react-loadable-manifest.js +1 -1
  117. package/dist/web/standalone/.next/server/pages/404.html +1 -1
  118. package/dist/web/standalone/.next/server/pages/500.html +2 -2
  119. package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
  120. package/dist/web/standalone/.next/static/chunks/4024.11ca5c01938e5948.js +9 -0
  121. package/dist/web/standalone/.next/static/chunks/{3721.bf31263de6d5fa46.js → 485.243af25f0cdf50d6.js} +2 -2
  122. package/dist/web/standalone/.next/static/chunks/app/{page-7e9530a7122506c5.js → page-12dd5ece0df4badc.js} +1 -1
  123. package/dist/web/standalone/.next/static/chunks/webpack-0a4cd455ec4197d2.js +1 -0
  124. package/dist/web/standalone/.next/static/css/dd4ae3f58ac9b600.css +1 -0
  125. package/package.json +1 -1
  126. package/packages/native/dist/stream-process/index.js +2 -2
  127. package/packages/native/src/__tests__/stream-process.test.mjs +34 -0
  128. package/packages/native/src/stream-process/index.ts +2 -2
  129. package/packages/pi-coding-agent/dist/core/auth-storage.d.ts +3 -1
  130. package/packages/pi-coding-agent/dist/core/auth-storage.d.ts.map +1 -1
  131. package/packages/pi-coding-agent/dist/core/auth-storage.js +15 -1
  132. package/packages/pi-coding-agent/dist/core/auth-storage.js.map +1 -1
  133. package/packages/pi-coding-agent/dist/core/auth-storage.test.js +6 -8
  134. package/packages/pi-coding-agent/dist/core/auth-storage.test.js.map +1 -1
  135. package/packages/pi-coding-agent/dist/core/extensions/runner.test.js +24 -26
  136. package/packages/pi-coding-agent/dist/core/extensions/runner.test.js.map +1 -1
  137. package/packages/pi-coding-agent/dist/core/fs-utils.test.js +29 -48
  138. package/packages/pi-coding-agent/dist/core/fs-utils.test.js.map +1 -1
  139. package/packages/pi-coding-agent/dist/core/local-model-check.d.ts +15 -0
  140. package/packages/pi-coding-agent/dist/core/local-model-check.d.ts.map +1 -0
  141. package/packages/pi-coding-agent/dist/core/local-model-check.js +41 -0
  142. package/packages/pi-coding-agent/dist/core/local-model-check.js.map +1 -0
  143. package/packages/pi-coding-agent/dist/core/model-registry.d.ts +11 -0
  144. package/packages/pi-coding-agent/dist/core/model-registry.d.ts.map +1 -1
  145. package/packages/pi-coding-agent/dist/core/model-registry.js +20 -1
  146. package/packages/pi-coding-agent/dist/core/model-registry.js.map +1 -1
  147. package/packages/pi-coding-agent/dist/core/resolve-config-value.test.js +34 -44
  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 +30 -34
  150. package/packages/pi-coding-agent/dist/core/session-manager.test.js.map +1 -1
  151. package/packages/pi-coding-agent/dist/core/settings-manager.d.ts +3 -0
  152. package/packages/pi-coding-agent/dist/core/settings-manager.d.ts.map +1 -1
  153. package/packages/pi-coding-agent/dist/core/settings-manager.js +6 -0
  154. package/packages/pi-coding-agent/dist/core/settings-manager.js.map +1 -1
  155. package/packages/pi-coding-agent/dist/core/tools/edit-diff.test.js +10 -12
  156. package/packages/pi-coding-agent/dist/core/tools/edit-diff.test.js.map +1 -1
  157. package/packages/pi-coding-agent/dist/main.d.ts.map +1 -1
  158. package/packages/pi-coding-agent/dist/main.js +17 -0
  159. package/packages/pi-coding-agent/dist/main.js.map +1 -1
  160. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/timestamp.test.d.ts +2 -0
  161. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/timestamp.test.d.ts.map +1 -0
  162. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/timestamp.test.js +32 -0
  163. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/timestamp.test.js.map +1 -0
  164. package/packages/pi-coding-agent/dist/modes/interactive/components/assistant-message.d.ts +3 -1
  165. package/packages/pi-coding-agent/dist/modes/interactive/components/assistant-message.d.ts.map +1 -1
  166. package/packages/pi-coding-agent/dist/modes/interactive/components/assistant-message.js +8 -1
  167. package/packages/pi-coding-agent/dist/modes/interactive/components/assistant-message.js.map +1 -1
  168. package/packages/pi-coding-agent/dist/modes/interactive/components/settings-selector.d.ts +2 -0
  169. package/packages/pi-coding-agent/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
  170. package/packages/pi-coding-agent/dist/modes/interactive/components/settings-selector.js +12 -0
  171. package/packages/pi-coding-agent/dist/modes/interactive/components/settings-selector.js.map +1 -1
  172. package/packages/pi-coding-agent/dist/modes/interactive/components/timestamp.d.ts +15 -0
  173. package/packages/pi-coding-agent/dist/modes/interactive/components/timestamp.d.ts.map +1 -0
  174. package/packages/pi-coding-agent/dist/modes/interactive/components/timestamp.js +40 -0
  175. package/packages/pi-coding-agent/dist/modes/interactive/components/timestamp.js.map +1 -0
  176. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
  177. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.js +4 -1
  178. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.js.map +1 -1
  179. package/packages/pi-coding-agent/dist/modes/interactive/components/user-message.d.ts +5 -2
  180. package/packages/pi-coding-agent/dist/modes/interactive/components/user-message.d.ts.map +1 -1
  181. package/packages/pi-coding-agent/dist/modes/interactive/components/user-message.js +13 -2
  182. package/packages/pi-coding-agent/dist/modes/interactive/components/user-message.js.map +1 -1
  183. package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.d.ts.map +1 -1
  184. package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.js +17 -8
  185. package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.js.map +1 -1
  186. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  187. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js +7 -3
  188. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js.map +1 -1
  189. package/packages/pi-coding-agent/dist/resources/extensions/memory/storage.test.js +43 -47
  190. package/packages/pi-coding-agent/dist/resources/extensions/memory/storage.test.js.map +1 -1
  191. package/packages/pi-coding-agent/package.json +1 -1
  192. package/packages/pi-coding-agent/src/core/auth-storage.test.ts +7 -7
  193. package/packages/pi-coding-agent/src/core/auth-storage.ts +15 -1
  194. package/packages/pi-coding-agent/src/core/extensions/runner.test.ts +26 -26
  195. package/packages/pi-coding-agent/src/core/fs-utils.test.ts +31 -43
  196. package/packages/pi-coding-agent/src/core/local-model-check.ts +45 -0
  197. package/packages/pi-coding-agent/src/core/model-registry.ts +21 -1
  198. package/packages/pi-coding-agent/src/core/resolve-config-value.test.ts +40 -45
  199. package/packages/pi-coding-agent/src/core/session-manager.test.ts +33 -33
  200. package/packages/pi-coding-agent/src/core/settings-manager.ts +9 -0
  201. package/packages/pi-coding-agent/src/core/tools/edit-diff.test.ts +17 -17
  202. package/packages/pi-coding-agent/src/main.ts +19 -0
  203. package/packages/pi-coding-agent/src/modes/interactive/components/__tests__/timestamp.test.ts +38 -0
  204. package/packages/pi-coding-agent/src/modes/interactive/components/assistant-message.ts +10 -0
  205. package/packages/pi-coding-agent/src/modes/interactive/components/settings-selector.ts +15 -0
  206. package/packages/pi-coding-agent/src/modes/interactive/components/timestamp.ts +48 -0
  207. package/packages/pi-coding-agent/src/modes/interactive/components/tool-execution.ts +3 -1
  208. package/packages/pi-coding-agent/src/modes/interactive/components/user-message.ts +18 -3
  209. package/packages/pi-coding-agent/src/modes/interactive/controllers/chat-controller.ts +16 -7
  210. package/packages/pi-coding-agent/src/modes/interactive/interactive-mode.ts +8 -1
  211. package/packages/pi-coding-agent/src/resources/extensions/memory/storage.test.ts +74 -74
  212. package/pkg/package.json +1 -1
  213. package/src/resources/extensions/gsd/activity-log.ts +1 -0
  214. package/src/resources/extensions/gsd/auto/infra-errors.ts +3 -0
  215. package/src/resources/extensions/gsd/auto/phases.ts +46 -48
  216. package/src/resources/extensions/gsd/auto-prompts.ts +24 -1
  217. package/src/resources/extensions/gsd/auto-start.ts +39 -2
  218. package/src/resources/extensions/gsd/auto-timers.ts +64 -3
  219. package/src/resources/extensions/gsd/auto-worktree-sync.ts +5 -0
  220. package/src/resources/extensions/gsd/auto-worktree.ts +9 -6
  221. package/src/resources/extensions/gsd/auto.ts +37 -3
  222. package/src/resources/extensions/gsd/bootstrap/db-tools.ts +148 -0
  223. package/src/resources/extensions/gsd/bootstrap/system-context.ts +48 -11
  224. package/src/resources/extensions/gsd/commands/catalog.ts +7 -1
  225. package/src/resources/extensions/gsd/commands/handlers/core.ts +2 -0
  226. package/src/resources/extensions/gsd/commands/handlers/ops.ts +10 -0
  227. package/src/resources/extensions/gsd/commands/handlers/workflow.ts +8 -0
  228. package/src/resources/extensions/gsd/commands-mcp-status.ts +247 -0
  229. package/src/resources/extensions/gsd/db-writer.ts +39 -17
  230. package/src/resources/extensions/gsd/doctor.ts +7 -1
  231. package/src/resources/extensions/gsd/git-service.ts +6 -2
  232. package/src/resources/extensions/gsd/gsd-db.ts +16 -1
  233. package/src/resources/extensions/gsd/markdown-renderer.ts +1 -1
  234. package/src/resources/extensions/gsd/preferences.ts +11 -1
  235. package/src/resources/extensions/gsd/prompts/complete-milestone.md +2 -4
  236. package/src/resources/extensions/gsd/prompts/plan-slice.md +1 -1
  237. package/src/resources/extensions/gsd/prompts/reassess-roadmap.md +6 -6
  238. package/src/resources/extensions/gsd/prompts/replan-slice.md +3 -14
  239. package/src/resources/extensions/gsd/prompts/rethink.md +78 -0
  240. package/src/resources/extensions/gsd/prompts/validate-milestone.md +7 -37
  241. package/src/resources/extensions/gsd/provider-error-pause.ts +9 -0
  242. package/src/resources/extensions/gsd/repo-identity.ts +46 -7
  243. package/src/resources/extensions/gsd/rethink.ts +154 -0
  244. package/src/resources/extensions/gsd/state.ts +41 -1
  245. package/src/resources/extensions/gsd/tests/all-milestones-complete-merge.test.ts +99 -99
  246. package/src/resources/extensions/gsd/tests/auto-lock-creation.test.ts +14 -16
  247. package/src/resources/extensions/gsd/tests/auto-paused-session-validation.test.ts +43 -57
  248. package/src/resources/extensions/gsd/tests/auto-pr-bugs.test.ts +88 -0
  249. package/src/resources/extensions/gsd/tests/auto-preflight.test.ts +11 -13
  250. package/src/resources/extensions/gsd/tests/auto-recovery.test.ts +465 -523
  251. package/src/resources/extensions/gsd/tests/auto-secrets-gate.test.ts +73 -75
  252. package/src/resources/extensions/gsd/tests/auto-start-needs-discussion.test.ts +34 -56
  253. package/src/resources/extensions/gsd/tests/auto-worktree-milestone-merge.test.ts +533 -656
  254. package/src/resources/extensions/gsd/tests/auto-worktree.test.ts +165 -143
  255. package/src/resources/extensions/gsd/tests/cache-staleness-regression.test.ts +29 -52
  256. package/src/resources/extensions/gsd/tests/captures.test.ts +148 -176
  257. package/src/resources/extensions/gsd/tests/claude-import-tui.test.ts +32 -33
  258. package/src/resources/extensions/gsd/tests/collect-from-manifest.test.ts +141 -143
  259. package/src/resources/extensions/gsd/tests/commands-inspect-open-db.test.ts +25 -25
  260. package/src/resources/extensions/gsd/tests/commands-logs.test.ts +81 -81
  261. package/src/resources/extensions/gsd/tests/complete-milestone.test.ts +38 -59
  262. package/src/resources/extensions/gsd/tests/complete-slice.test.ts +228 -263
  263. package/src/resources/extensions/gsd/tests/complete-task.test.ts +250 -302
  264. package/src/resources/extensions/gsd/tests/completed-units-metrics-sync.test.ts +114 -0
  265. package/src/resources/extensions/gsd/tests/context-store.test.ts +354 -367
  266. package/src/resources/extensions/gsd/tests/continue-here.test.ts +68 -72
  267. package/src/resources/extensions/gsd/tests/cost-projection.test.ts +92 -106
  268. package/src/resources/extensions/gsd/tests/crash-recovery.test.ts +27 -35
  269. package/src/resources/extensions/gsd/tests/dashboard-budget.test.ts +220 -237
  270. package/src/resources/extensions/gsd/tests/db-writer.test.ts +465 -416
  271. package/src/resources/extensions/gsd/tests/definition-loader.test.ts +76 -92
  272. package/src/resources/extensions/gsd/tests/derive-state-crossval.test.ts +68 -83
  273. package/src/resources/extensions/gsd/tests/derive-state-db-disk-reconcile.test.ts +121 -0
  274. package/src/resources/extensions/gsd/tests/derive-state-db.test.ts +210 -181
  275. package/src/resources/extensions/gsd/tests/derive-state-deps.test.ts +78 -101
  276. package/src/resources/extensions/gsd/tests/derive-state.test.ts +192 -227
  277. package/src/resources/extensions/gsd/tests/detection.test.ts +232 -278
  278. package/src/resources/extensions/gsd/tests/dev-engine-wrapper.test.ts +30 -34
  279. package/src/resources/extensions/gsd/tests/dispatch-guard.test.ts +164 -180
  280. package/src/resources/extensions/gsd/tests/dispatch-missing-task-plans.test.ts +43 -49
  281. package/src/resources/extensions/gsd/tests/dispatch-uat-last-completed.test.ts +28 -32
  282. package/src/resources/extensions/gsd/tests/doctor-completion-deferral.test.ts +27 -29
  283. package/src/resources/extensions/gsd/tests/doctor-delimiter-fix.test.ts +34 -38
  284. package/src/resources/extensions/gsd/tests/doctor-enhancements.test.ts +54 -75
  285. package/src/resources/extensions/gsd/tests/doctor-environment-worktree.test.ts +21 -32
  286. package/src/resources/extensions/gsd/tests/doctor-environment.test.ts +72 -97
  287. package/src/resources/extensions/gsd/tests/doctor-fixlevel.test.ts +38 -44
  288. package/src/resources/extensions/gsd/tests/doctor-git.test.ts +104 -145
  289. package/src/resources/extensions/gsd/tests/doctor-proactive.test.ts +84 -106
  290. package/src/resources/extensions/gsd/tests/doctor-roadmap-summary-atomicity.test.ts +54 -60
  291. package/src/resources/extensions/gsd/tests/doctor-runtime.test.ts +72 -93
  292. package/src/resources/extensions/gsd/tests/doctor.test.ts +104 -134
  293. package/src/resources/extensions/gsd/tests/ensure-db-open.test.ts +123 -131
  294. package/src/resources/extensions/gsd/tests/est-annotation-timeout.test.ts +120 -0
  295. package/src/resources/extensions/gsd/tests/exit-command.test.ts +20 -24
  296. package/src/resources/extensions/gsd/tests/feature-branch-lifecycle-integration.test.ts +48 -57
  297. package/src/resources/extensions/gsd/tests/files-loadfile-eisdir.test.ts +5 -7
  298. package/src/resources/extensions/gsd/tests/flag-file-db.test.ts +30 -42
  299. package/src/resources/extensions/gsd/tests/freeform-decisions.test.ts +198 -206
  300. package/src/resources/extensions/gsd/tests/git-locale.test.ts +13 -27
  301. package/src/resources/extensions/gsd/tests/git-service.test.ts +285 -388
  302. package/src/resources/extensions/gsd/tests/gitignore-tracked-gsd.test.ts +31 -39
  303. package/src/resources/extensions/gsd/tests/graph-operations.test.ts +63 -69
  304. package/src/resources/extensions/gsd/tests/gsd-db.test.ts +255 -264
  305. package/src/resources/extensions/gsd/tests/gsd-inspect.test.ts +108 -119
  306. package/src/resources/extensions/gsd/tests/gsd-recover.test.ts +81 -103
  307. package/src/resources/extensions/gsd/tests/gsd-tools.test.ts +229 -262
  308. package/src/resources/extensions/gsd/tests/headless-answers.test.ts +13 -13
  309. package/src/resources/extensions/gsd/tests/health-widget.test.ts +29 -37
  310. package/src/resources/extensions/gsd/tests/idle-recovery.test.ts +81 -102
  311. package/src/resources/extensions/gsd/tests/infra-error.test.ts +20 -2
  312. package/src/resources/extensions/gsd/tests/inherited-repo-home-dir.test.ts +121 -0
  313. package/src/resources/extensions/gsd/tests/init-wizard.test.ts +16 -18
  314. package/src/resources/extensions/gsd/tests/integration-edge.test.ts +41 -46
  315. package/src/resources/extensions/gsd/tests/integration-lifecycle.test.ts +42 -53
  316. package/src/resources/extensions/gsd/tests/integration-mixed-milestones.test.ts +75 -91
  317. package/src/resources/extensions/gsd/tests/integration-proof.test.ts +18 -18
  318. package/src/resources/extensions/gsd/tests/knowledge.test.ts +89 -0
  319. package/src/resources/extensions/gsd/tests/markdown-renderer.test.ts +150 -194
  320. package/src/resources/extensions/gsd/tests/mcp-status.test.ts +103 -0
  321. package/src/resources/extensions/gsd/tests/md-importer.test.ts +101 -125
  322. package/src/resources/extensions/gsd/tests/memory-extractor.test.ts +45 -54
  323. package/src/resources/extensions/gsd/tests/memory-store.test.ts +80 -93
  324. package/src/resources/extensions/gsd/tests/merge-conflict-stops-loop.test.ts +66 -0
  325. package/src/resources/extensions/gsd/tests/migrate-command.test.ts +57 -66
  326. package/src/resources/extensions/gsd/tests/migrate-hierarchy.test.ts +83 -93
  327. package/src/resources/extensions/gsd/tests/migrate-parser.test.ts +161 -170
  328. package/src/resources/extensions/gsd/tests/migrate-transformer.test.ts +125 -141
  329. package/src/resources/extensions/gsd/tests/migrate-validator-parsers.test.ts +107 -131
  330. package/src/resources/extensions/gsd/tests/migrate-writer-integration.test.ts +87 -96
  331. package/src/resources/extensions/gsd/tests/migrate-writer.test.ts +125 -164
  332. package/src/resources/extensions/gsd/tests/must-have-parser.test.ts +81 -94
  333. package/src/resources/extensions/gsd/tests/none-mode-gates.test.ts +35 -36
  334. package/src/resources/extensions/gsd/tests/overrides.test.ts +99 -106
  335. package/src/resources/extensions/gsd/tests/parallel-crash-recovery.test.ts +40 -47
  336. package/src/resources/extensions/gsd/tests/parallel-worker-monitoring.test.ts +25 -28
  337. package/src/resources/extensions/gsd/tests/parallel-workers-multi-milestone-e2e.test.ts +66 -83
  338. package/src/resources/extensions/gsd/tests/park-edge-cases.test.ts +54 -77
  339. package/src/resources/extensions/gsd/tests/park-milestone.test.ts +68 -115
  340. package/src/resources/extensions/gsd/tests/parsers.test.ts +546 -611
  341. package/src/resources/extensions/gsd/tests/paths.test.ts +72 -87
  342. package/src/resources/extensions/gsd/tests/post-unit-hooks.test.ts +77 -117
  343. package/src/resources/extensions/gsd/tests/preferences.test.ts +27 -0
  344. package/src/resources/extensions/gsd/tests/prompt-contracts.test.ts +11 -7
  345. package/src/resources/extensions/gsd/tests/prompt-db.test.ts +56 -56
  346. package/src/resources/extensions/gsd/tests/queue-draft-detection.test.ts +93 -119
  347. package/src/resources/extensions/gsd/tests/queue-order.test.ts +70 -82
  348. package/src/resources/extensions/gsd/tests/queue-reorder-e2e.test.ts +42 -55
  349. package/src/resources/extensions/gsd/tests/quick-auto-guard.test.ts +100 -0
  350. package/src/resources/extensions/gsd/tests/quick-branch-lifecycle.test.ts +45 -73
  351. package/src/resources/extensions/gsd/tests/reassess-prompt.test.ts +28 -38
  352. package/src/resources/extensions/gsd/tests/recovery-attempts-reset.test.ts +176 -0
  353. package/src/resources/extensions/gsd/tests/replan-slice.test.ts +73 -80
  354. package/src/resources/extensions/gsd/tests/repo-identity-worktree.test.ts +71 -74
  355. package/src/resources/extensions/gsd/tests/requirements.test.ts +70 -75
  356. package/src/resources/extensions/gsd/tests/retry-state-reset.test.ts +44 -66
  357. package/src/resources/extensions/gsd/tests/roadmap-parse-regression.test.ts +114 -181
  358. package/src/resources/extensions/gsd/tests/rule-registry.test.ts +63 -65
  359. package/src/resources/extensions/gsd/tests/run-uat.test.ts +66 -128
  360. package/src/resources/extensions/gsd/tests/session-lock-multipath.test.ts +18 -25
  361. package/src/resources/extensions/gsd/tests/session-lock-regression.test.ts +37 -44
  362. package/src/resources/extensions/gsd/tests/shared-wal.test.ts +19 -26
  363. package/src/resources/extensions/gsd/tests/sqlite-unavailable-gate.test.ts +63 -0
  364. package/src/resources/extensions/gsd/tests/stalled-tool-recovery.test.ts +6 -8
  365. package/src/resources/extensions/gsd/tests/stop-auto-merge-back.test.ts +67 -0
  366. package/src/resources/extensions/gsd/tests/survivor-branch-complete.test.ts +108 -0
  367. package/src/resources/extensions/gsd/tests/symlink-numbered-variants.test.ts +22 -28
  368. package/src/resources/extensions/gsd/tests/terminated-transient.test.ts +49 -0
  369. package/src/resources/extensions/gsd/tests/token-savings.test.ts +54 -56
  370. package/src/resources/extensions/gsd/tests/tool-call-loop-guard.test.ts +23 -25
  371. package/src/resources/extensions/gsd/tests/tool-naming.test.ts +10 -11
  372. package/src/resources/extensions/gsd/tests/unique-milestone-ids.test.ts +66 -82
  373. package/src/resources/extensions/gsd/tests/unit-runtime.test.ts +46 -47
  374. package/src/resources/extensions/gsd/tests/visualizer-critical-path.test.ts +20 -22
  375. package/src/resources/extensions/gsd/tests/visualizer-data.test.ts +84 -86
  376. package/src/resources/extensions/gsd/tests/visualizer-overlay.test.ts +41 -43
  377. package/src/resources/extensions/gsd/tests/visualizer-views.test.ts +94 -96
  378. package/src/resources/extensions/gsd/tests/windows-path-normalization.test.ts +11 -13
  379. package/src/resources/extensions/gsd/tests/worker-registry.test.ts +27 -29
  380. package/src/resources/extensions/gsd/tests/workflow-templates.test.ts +50 -52
  381. package/src/resources/extensions/gsd/tests/worktree-bugfix.test.ts +10 -13
  382. package/src/resources/extensions/gsd/tests/worktree-db-integration.test.ts +14 -18
  383. package/src/resources/extensions/gsd/tests/worktree-db.test.ts +38 -39
  384. package/src/resources/extensions/gsd/tests/worktree-e2e.test.ts +17 -21
  385. package/src/resources/extensions/gsd/tests/worktree-health.test.ts +25 -30
  386. package/src/resources/extensions/gsd/tests/worktree-integration.test.ts +30 -37
  387. package/src/resources/extensions/gsd/tests/worktree-submodule-safety.test.ts +65 -0
  388. package/src/resources/extensions/gsd/tests/worktree-symlink-removal.test.ts +15 -22
  389. package/src/resources/extensions/gsd/tests/worktree-sync-milestones.test.ts +59 -66
  390. package/src/resources/extensions/gsd/tests/worktree.test.ts +44 -50
  391. package/src/resources/extensions/gsd/tools/plan-slice.ts +2 -0
  392. package/src/resources/extensions/gsd/tools/plan-task.ts +2 -0
  393. package/src/resources/extensions/gsd/tools/replan-slice.ts +3 -0
  394. package/src/resources/extensions/gsd/tools/validate-milestone.ts +127 -0
  395. package/src/resources/extensions/gsd/worktree-manager.ts +43 -2
  396. package/src/resources/extensions/gsd/worktree-resolver.ts +7 -0
  397. package/src/resources/extensions/mcp-client/index.ts +20 -0
  398. package/dist/web/standalone/.next/static/chunks/4024.0de81b543b28b9fe.js +0 -9
  399. package/dist/web/standalone/.next/static/chunks/webpack-9014b5adb127a98a.js +0 -1
  400. package/dist/web/standalone/.next/static/css/8a727f372cf53002.css +0 -1
  401. /package/dist/web/standalone/.next/static/{mgkxN0mGP6gSUmGPEzbk_ → wUzEX1U3CmFcMry2SUDJn}/_buildManifest.js +0 -0
  402. /package/dist/web/standalone/.next/static/{mgkxN0mGP6gSUmGPEzbk_ → wUzEX1U3CmFcMry2SUDJn}/_ssgManifest.js +0 -0
@@ -1,3 +1,5 @@
1
+ import { describe, test } from 'node:test';
2
+ import assert from 'node:assert/strict';
1
3
  // ensureDbOpen — Tests that the lazy DB opener creates + migrates the database
2
4
  // when .gsd/ exists with Markdown content but no gsd.db file.
3
5
  //
@@ -5,14 +7,11 @@
5
7
  // "GSD database is not available" because ensureDbOpen only opened
6
8
  // existing DB files but never created them.
7
9
 
8
- import { createTestContext } from './test-helpers.ts';
9
10
  import * as path from 'node:path';
10
11
  import * as os from 'node:os';
11
12
  import * as fs from 'node:fs';
12
13
  import { closeDatabase, isDbAvailable, getDecisionById } from '../gsd-db.ts';
13
14
 
14
- const { assertEq, assertTrue, report } = createTestContext();
15
-
16
15
  function makeTmpDir(): string {
17
16
  const dir = fs.mkdtempSync(path.join(os.tmpdir(), 'gsd-ensure-db-'));
18
17
  return dir;
@@ -28,141 +27,134 @@ function cleanupDir(dir: string): void {
28
27
  // ensureDbOpen creates DB + migrates when .gsd/ has Markdown
29
28
  // ═══════════════════════════════════════════════════════════════════════════
30
29
 
31
- console.log('\n── ensureDbOpen: creates DB from Markdown ──');
32
-
33
- {
34
- const tmpDir = makeTmpDir();
35
- const gsdDir = path.join(tmpDir, '.gsd');
36
- fs.mkdirSync(gsdDir, { recursive: true });
37
-
38
- // Write a minimal DECISIONS.md so migration has content
39
- const decisionsContent = `# Decisions
40
-
41
- | # | When | Scope | Decision | Choice | Rationale | Revisable |
42
- |---|------|-------|----------|--------|-----------|-----------|
43
- | D001 | M001 | architecture | Use SQLite | SQLite | Sync API | Yes |
44
- `;
45
- fs.writeFileSync(path.join(gsdDir, 'DECISIONS.md'), decisionsContent);
46
-
47
- // Verify no DB file exists yet
48
- const dbPath = path.join(gsdDir, 'gsd.db');
49
- assertTrue(!fs.existsSync(dbPath), 'DB file should not exist before ensureDbOpen');
50
-
51
- // Close any previously open DB
52
- try { closeDatabase(); } catch { /* ok */ }
53
-
54
- // Override process.cwd to point at tmpDir for ensureDbOpen
55
- const origCwd = process.cwd;
56
- process.cwd = () => tmpDir;
57
-
58
- try {
59
- // Dynamic import to get the freshest version
60
- const { ensureDbOpen } = await import('../bootstrap/dynamic-tools.ts');
61
-
62
- const result = await ensureDbOpen();
63
-
64
- assertTrue(result === true, 'ensureDbOpen should return true when .gsd/ has Markdown');
65
- assertTrue(fs.existsSync(dbPath), 'DB file should be created after ensureDbOpen');
66
- assertTrue(isDbAvailable(), 'DB should be available after ensureDbOpen');
67
-
68
- // Verify that Markdown migration actually ran
69
- const decision = getDecisionById('D001');
70
- assertTrue(decision !== null, 'D001 should be migrated from DECISIONS.md');
71
- if (decision) {
72
- assertEq(decision.scope, 'architecture', 'Migrated decision scope should match');
73
- assertEq(decision.choice, 'SQLite', 'Migrated decision choice should match');
30
+ describe('ensure-db-open', () => {
31
+ test('ensureDbOpen: creates DB from Markdown', async () => {
32
+ const tmpDir = makeTmpDir();
33
+ const gsdDir = path.join(tmpDir, '.gsd');
34
+ fs.mkdirSync(gsdDir, { recursive: true });
35
+
36
+ // Write a minimal DECISIONS.md so migration has content
37
+ const decisionsContent = `# Decisions
38
+
39
+ | # | When | Scope | Decision | Choice | Rationale | Revisable |
40
+ |---|------|-------|----------|--------|-----------|-----------|
41
+ | D001 | M001 | architecture | Use SQLite | SQLite | Sync API | Yes |
42
+ `;
43
+ fs.writeFileSync(path.join(gsdDir, 'DECISIONS.md'), decisionsContent);
44
+
45
+ // Verify no DB file exists yet
46
+ const dbPath = path.join(gsdDir, 'gsd.db');
47
+ assert.ok(!fs.existsSync(dbPath), 'DB file should not exist before ensureDbOpen');
48
+
49
+ // Close any previously open DB
50
+ try { closeDatabase(); } catch { /* ok */ }
51
+
52
+ // Override process.cwd to point at tmpDir for ensureDbOpen
53
+ const origCwd = process.cwd;
54
+ process.cwd = () => tmpDir;
55
+
56
+ try {
57
+ // Dynamic import to get the freshest version
58
+ const { ensureDbOpen } = await import('../bootstrap/dynamic-tools.ts');
59
+
60
+ const result = await ensureDbOpen();
61
+
62
+ assert.ok(result === true, 'ensureDbOpen should return true when .gsd/ has Markdown');
63
+ assert.ok(fs.existsSync(dbPath), 'DB file should be created after ensureDbOpen');
64
+ assert.ok(isDbAvailable(), 'DB should be available after ensureDbOpen');
65
+
66
+ // Verify that Markdown migration actually ran
67
+ const decision = getDecisionById('D001');
68
+ assert.ok(decision !== null, 'D001 should be migrated from DECISIONS.md');
69
+ if (decision) {
70
+ assert.deepStrictEqual(decision.scope, 'architecture', 'Migrated decision scope should match');
71
+ assert.deepStrictEqual(decision.choice, 'SQLite', 'Migrated decision choice should match');
72
+ }
73
+ } finally {
74
+ process.cwd = origCwd;
75
+ closeDatabase();
76
+ cleanupDir(tmpDir);
74
77
  }
75
- } finally {
76
- process.cwd = origCwd;
77
- closeDatabase();
78
- cleanupDir(tmpDir);
79
- }
80
- }
81
-
82
- // ═══════════════════════════════════════════════════════════════════════════
83
- // ensureDbOpen returns false when no .gsd/ exists
84
- // ═══════════════════════════════════════════════════════════════════════════
85
-
86
- console.log('\n── ensureDbOpen: no .gsd/ returns false ──');
87
-
88
- {
89
- const tmpDir = makeTmpDir();
90
- // No .gsd/ directory at all
91
-
92
- try { closeDatabase(); } catch { /* ok */ }
93
- const origCwd = process.cwd;
94
- process.cwd = () => tmpDir;
95
-
96
- try {
97
- const { ensureDbOpen } = await import('../bootstrap/dynamic-tools.ts');
98
- const result = await ensureDbOpen();
99
- assertTrue(result === false, 'ensureDbOpen should return false when no .gsd/ exists');
100
- assertTrue(!isDbAvailable(), 'DB should not be available');
101
- } finally {
102
- process.cwd = origCwd;
103
- cleanupDir(tmpDir);
104
- }
105
- }
106
-
107
- // ═══════════════════════════════════════════════════════════════════════════
108
- // ensureDbOpen opens existing DB without re-migration
109
- // ═══════════════════════════════════════════════════════════════════════════
110
-
111
- console.log('\n── ensureDbOpen: opens existing DB ──');
112
-
113
- {
114
- const tmpDir = makeTmpDir();
115
- const gsdDir = path.join(tmpDir, '.gsd');
116
- fs.mkdirSync(gsdDir, { recursive: true });
117
-
118
- // Create a DB file first
119
- const dbPath = path.join(gsdDir, 'gsd.db');
120
- const { openDatabase } = await import('../gsd-db.ts');
121
- openDatabase(dbPath);
122
- closeDatabase();
78
+ });
79
+
80
+ // ═══════════════════════════════════════════════════════════════════════════
81
+ // ensureDbOpen returns false when no .gsd/ exists
82
+ // ═══════════════════════════════════════════════════════════════════════════
83
+
84
+ test('ensureDbOpen: no .gsd/ returns false', async () => {
85
+ const tmpDir = makeTmpDir();
86
+ // No .gsd/ directory at all
87
+
88
+ try { closeDatabase(); } catch { /* ok */ }
89
+ const origCwd = process.cwd;
90
+ process.cwd = () => tmpDir;
91
+
92
+ try {
93
+ const { ensureDbOpen } = await import('../bootstrap/dynamic-tools.ts');
94
+ const result = await ensureDbOpen();
95
+ assert.ok(result === false, 'ensureDbOpen should return false when no .gsd/ exists');
96
+ assert.ok(!isDbAvailable(), 'DB should not be available');
97
+ } finally {
98
+ process.cwd = origCwd;
99
+ cleanupDir(tmpDir);
100
+ }
101
+ });
123
102
 
124
- assertTrue(fs.existsSync(dbPath), 'DB file should exist from manual create');
103
+ // ═══════════════════════════════════════════════════════════════════════════
104
+ // ensureDbOpen opens existing DB without re-migration
105
+ // ═══════════════════════════════════════════════════════════════════════════
125
106
 
126
- const origCwd = process.cwd;
127
- process.cwd = () => tmpDir;
107
+ test('ensureDbOpen: opens existing DB', async () => {
108
+ const tmpDir = makeTmpDir();
109
+ const gsdDir = path.join(tmpDir, '.gsd');
110
+ fs.mkdirSync(gsdDir, { recursive: true });
128
111
 
129
- try {
130
- const { ensureDbOpen } = await import('../bootstrap/dynamic-tools.ts');
131
- const result = await ensureDbOpen();
132
- assertTrue(result === true, 'ensureDbOpen should open existing DB');
133
- assertTrue(isDbAvailable(), 'DB should be available');
134
- } finally {
135
- process.cwd = origCwd;
112
+ // Create a DB file first
113
+ const dbPath = path.join(gsdDir, 'gsd.db');
114
+ const { openDatabase } = await import('../gsd-db.ts');
115
+ openDatabase(dbPath);
136
116
  closeDatabase();
137
- cleanupDir(tmpDir);
138
- }
139
- }
140
-
141
- // ═══════════════════════════════════════════════════════════════════════════
142
- // ensureDbOpen returns false for empty .gsd/ (no Markdown, no DB)
143
- // ═══════════════════════════════════════════════════════════════════════════
144
-
145
- console.log('\n── ensureDbOpen: empty .gsd/ returns false ──');
146
117
 
147
- {
148
- const tmpDir = makeTmpDir();
149
- fs.mkdirSync(path.join(tmpDir, '.gsd'), { recursive: true });
150
- // .gsd/ exists but no DECISIONS.md, REQUIREMENTS.md, or milestones/
118
+ assert.ok(fs.existsSync(dbPath), 'DB file should exist from manual create');
151
119
 
152
- try { closeDatabase(); } catch { /* ok */ }
153
- const origCwd = process.cwd;
154
- process.cwd = () => tmpDir;
120
+ const origCwd = process.cwd;
121
+ process.cwd = () => tmpDir;
155
122
 
156
- try {
157
- const { ensureDbOpen } = await import('../bootstrap/dynamic-tools.ts');
158
- const result = await ensureDbOpen();
159
- assertTrue(result === false, 'ensureDbOpen should return false for empty .gsd/');
160
- } finally {
161
- process.cwd = origCwd;
162
- cleanupDir(tmpDir);
163
- }
164
- }
123
+ try {
124
+ const { ensureDbOpen } = await import('../bootstrap/dynamic-tools.ts');
125
+ const result = await ensureDbOpen();
126
+ assert.ok(result === true, 'ensureDbOpen should open existing DB');
127
+ assert.ok(isDbAvailable(), 'DB should be available');
128
+ } finally {
129
+ process.cwd = origCwd;
130
+ closeDatabase();
131
+ cleanupDir(tmpDir);
132
+ }
133
+ });
134
+
135
+ // ═══════════════════════════════════════════════════════════════════════════
136
+ // ensureDbOpen returns false for empty .gsd/ (no Markdown, no DB)
137
+ // ═══════════════════════════════════════════════════════════════════════════
138
+
139
+ test('ensureDbOpen: empty .gsd/ returns false', async () => {
140
+ const tmpDir = makeTmpDir();
141
+ fs.mkdirSync(path.join(tmpDir, '.gsd'), { recursive: true });
142
+ // .gsd/ exists but no DECISIONS.md, REQUIREMENTS.md, or milestones/
143
+
144
+ try { closeDatabase(); } catch { /* ok */ }
145
+ const origCwd = process.cwd;
146
+ process.cwd = () => tmpDir;
147
+
148
+ try {
149
+ const { ensureDbOpen } = await import('../bootstrap/dynamic-tools.ts');
150
+ const result = await ensureDbOpen();
151
+ assert.ok(result === false, 'ensureDbOpen should return false for empty .gsd/');
152
+ } finally {
153
+ process.cwd = origCwd;
154
+ cleanupDir(tmpDir);
155
+ }
156
+ });
165
157
 
166
- // ═══════════════════════════════════════════════════════════════════════════
158
+ // ═══════════════════════════════════════════════════════════════════════════
167
159
 
168
- report();
160
+ });
@@ -0,0 +1,120 @@
1
+ /**
2
+ * est-annotation-timeout.test.ts — Regression tests for #2243.
3
+ *
4
+ * Tasks with `est: 30m` or `est: 2h` annotations should get extended
5
+ * supervision timeouts. The parseEstimateMinutes helper should parse
6
+ * estimate strings, and startUnitSupervision should use them.
7
+ */
8
+
9
+ import test from "node:test";
10
+ import assert from "node:assert/strict";
11
+ import { readFileSync } from "node:fs";
12
+ import { join } from "node:path";
13
+
14
+ const timersSrcPath = join(import.meta.dirname, "..", "auto-timers.ts");
15
+ const timersSrc = readFileSync(timersSrcPath, "utf-8");
16
+
17
+ // ─── Source analysis: parseEstimateMinutes exists and is exported ────────────
18
+
19
+ test("#2243: auto-timers.ts should export parseEstimateMinutes", () => {
20
+ assert.ok(
21
+ timersSrc.includes("export function parseEstimateMinutes"),
22
+ "parseEstimateMinutes should be exported from auto-timers.ts",
23
+ );
24
+ });
25
+
26
+ // ─── Inline unit test of parseEstimateMinutes logic ─────────────────────────
27
+ // Since importing the module pulls in heavy deps, test the parsing logic inline.
28
+
29
+ function parseEstimateMinutes(estimate: string): number | null {
30
+ if (!estimate || typeof estimate !== "string") return null;
31
+ const trimmed = estimate.trim();
32
+ if (!trimmed) return null;
33
+
34
+ let totalMinutes = 0;
35
+ let matched = false;
36
+
37
+ const hoursMatch = trimmed.match(/(\d+)\s*h/i);
38
+ if (hoursMatch) {
39
+ totalMinutes += Number(hoursMatch[1]) * 60;
40
+ matched = true;
41
+ }
42
+
43
+ const minutesMatch = trimmed.match(/(\d+)\s*m/i);
44
+ if (minutesMatch) {
45
+ totalMinutes += Number(minutesMatch[1]);
46
+ matched = true;
47
+ }
48
+
49
+ return matched ? totalMinutes : null;
50
+ }
51
+
52
+ test("#2243: parseEstimateMinutes parses '30m' correctly", () => {
53
+ assert.equal(parseEstimateMinutes("30m"), 30);
54
+ });
55
+
56
+ test("#2243: parseEstimateMinutes parses '2h' correctly", () => {
57
+ assert.equal(parseEstimateMinutes("2h"), 120);
58
+ });
59
+
60
+ test("#2243: parseEstimateMinutes parses '1h30m' correctly", () => {
61
+ assert.equal(parseEstimateMinutes("1h30m"), 90);
62
+ });
63
+
64
+ test("#2243: parseEstimateMinutes parses '15m' correctly", () => {
65
+ assert.equal(parseEstimateMinutes("15m"), 15);
66
+ });
67
+
68
+ test("#2243: parseEstimateMinutes returns null for empty string", () => {
69
+ assert.equal(parseEstimateMinutes(""), null);
70
+ });
71
+
72
+ test("#2243: parseEstimateMinutes returns null for invalid string", () => {
73
+ assert.equal(parseEstimateMinutes("not a time"), null);
74
+ });
75
+
76
+ // ─── Source analysis: startUnitSupervision uses task estimates ───────────────
77
+
78
+ test("#2243: startUnitSupervision should reference task estimates for timeout scaling", () => {
79
+ const usesEstimate =
80
+ timersSrc.includes("parseEstimateMinutes") &&
81
+ timersSrc.includes("estimateMinutes") &&
82
+ timersSrc.includes("taskEstimate");
83
+
84
+ assert.ok(
85
+ usesEstimate,
86
+ "startUnitSupervision should use task estimate annotations for timeout scaling",
87
+ );
88
+ });
89
+
90
+ test("#2243: SupervisionContext should accept an optional taskEstimate field", () => {
91
+ const ctxIdx = timersSrc.indexOf("SupervisionContext");
92
+ assert.ok(ctxIdx !== -1, "SupervisionContext interface exists");
93
+
94
+ const ctxEnd = timersSrc.indexOf("}", ctxIdx);
95
+ const ctxBlock = timersSrc.slice(ctxIdx, ctxEnd);
96
+
97
+ assert.ok(
98
+ ctxBlock.includes("taskEstimate"),
99
+ "SupervisionContext should include a taskEstimate field",
100
+ );
101
+ });
102
+
103
+ test("#2243: timeouts should be scaled by estimate (timeoutScale in source)", () => {
104
+ assert.ok(
105
+ timersSrc.includes("timeoutScale"),
106
+ "auto-timers.ts should use a timeoutScale factor derived from est: annotations",
107
+ );
108
+ });
109
+
110
+ test("#2243: idle timeout should NOT be scaled (idle is idle regardless of estimate)", () => {
111
+ // Find the idleTimeoutMs line
112
+ const idleIdx = timersSrc.indexOf("const idleTimeoutMs");
113
+ assert.ok(idleIdx !== -1, "idleTimeoutMs variable exists");
114
+
115
+ const idleLine = timersSrc.slice(idleIdx, timersSrc.indexOf("\n", idleIdx));
116
+ assert.ok(
117
+ !idleLine.includes("timeoutScale"),
118
+ "idleTimeoutMs should NOT be scaled — idle is idle",
119
+ );
120
+ });
@@ -3,7 +3,7 @@ import assert from "node:assert/strict";
3
3
 
4
4
  import { registerExitCommand } from "../exit-command.ts";
5
5
 
6
- test("/exit requests graceful shutdown instead of process.exit", async () => {
6
+ test("/exit requests graceful shutdown instead of process.exit", async (t) => {
7
7
  const commands = new Map<
8
8
  string,
9
9
  {
@@ -35,15 +35,13 @@ test("/exit requests graceful shutdown instead of process.exit", async () => {
35
35
  throw new Error(`process.exit should not be called: ${code ?? "undefined"}`);
36
36
  }) as typeof process.exit;
37
37
 
38
- try {
39
- await exit.handler("", {
40
- async shutdown() {
41
- shutdownCalls += 1;
42
- },
43
- });
44
- } finally {
45
- process.exit = originalExit;
46
- }
38
+ t.after(() => { process.exit = originalExit; });
39
+
40
+ await exit.handler("", {
41
+ async shutdown() {
42
+ shutdownCalls += 1;
43
+ },
44
+ });
47
45
 
48
46
  assert.equal(stopAutoCalls, 1, "handler should stop auto-mode exactly once before shutdown");
49
47
  assert.equal(shutdownCalls, 1, "handler should request graceful shutdown exactly once");
@@ -51,7 +49,7 @@ test("/exit requests graceful shutdown instead of process.exit", async () => {
51
49
 
52
50
  // ─── #1839 regression: ESM cache mismatch must not crash exit ────────────────
53
51
 
54
- test("/exit still shuts down gracefully when stopAuto throws (ESM module cache mismatch)", async () => {
52
+ test("/exit still shuts down gracefully when stopAuto throws (ESM module cache mismatch)", async (t) => {
55
53
  const commands = new Map<string, { description?: string; handler: (args: string, ctx: any) => Promise<void> }>();
56
54
 
57
55
  const pi = {
@@ -80,20 +78,18 @@ test("/exit still shuts down gracefully when stopAuto throws (ESM module cache m
80
78
  throw new Error(`process.exit should not be called: ${code ?? "undefined"}`);
81
79
  }) as typeof process.exit;
82
80
 
83
- try {
84
- await exit.handler("", {
85
- async shutdown() {
86
- shutdownCalls += 1;
87
- },
88
- ui: {
89
- notify(msg: string, level: string) {
90
- notifications.push({ msg, level });
91
- },
81
+ t.after(() => { process.exit = originalExit; });
82
+
83
+ await exit.handler("", {
84
+ async shutdown() {
85
+ shutdownCalls += 1;
86
+ },
87
+ ui: {
88
+ notify(msg: string, level: string) {
89
+ notifications.push({ msg, level });
92
90
  },
93
- });
94
- } finally {
95
- process.exit = originalExit;
96
- }
91
+ },
92
+ });
97
93
 
98
94
  assert.equal(shutdownCalls, 1, "shutdown must still be called even when stopAuto throws");
99
95
  assert.equal(notifications.length, 1, "should emit exactly one warning notification");