gsd-pi 2.48.0 → 2.49.0-dev.9e177e9

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 (369) hide show
  1. package/dist/headless-ui.js +12 -2
  2. package/dist/headless.js +29 -13
  3. package/dist/resources/extensions/gsd/auto/infra-errors.js +1 -0
  4. package/dist/resources/extensions/gsd/auto/phases.js +11 -11
  5. package/dist/resources/extensions/gsd/auto/resolve.js +2 -2
  6. package/dist/resources/extensions/gsd/auto/run-unit.js +2 -2
  7. package/dist/resources/extensions/gsd/auto/session.js +4 -0
  8. package/dist/resources/extensions/gsd/auto-artifact-paths.js +8 -10
  9. package/dist/resources/extensions/gsd/auto-dashboard.js +6 -3
  10. package/dist/resources/extensions/gsd/auto-dispatch.js +34 -7
  11. package/dist/resources/extensions/gsd/auto-post-unit.js +34 -27
  12. package/dist/resources/extensions/gsd/auto-prompts.js +102 -21
  13. package/dist/resources/extensions/gsd/auto-recovery.js +62 -184
  14. package/dist/resources/extensions/gsd/auto-start.js +4 -31
  15. package/dist/resources/extensions/gsd/auto-timers.js +2 -2
  16. package/dist/resources/extensions/gsd/auto-verification.js +4 -7
  17. package/dist/resources/extensions/gsd/auto-worktree.js +262 -115
  18. package/dist/resources/extensions/gsd/auto.js +7 -5
  19. package/dist/resources/extensions/gsd/bootstrap/db-tools.js +89 -0
  20. package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +8 -1
  21. package/dist/resources/extensions/gsd/branch-patterns.js +13 -0
  22. package/dist/resources/extensions/gsd/commands/handlers/auto.js +43 -3
  23. package/dist/resources/extensions/gsd/doctor-checks.js +5 -1234
  24. package/dist/resources/extensions/gsd/doctor-engine-checks.js +168 -0
  25. package/dist/resources/extensions/gsd/doctor-environment.js +28 -7
  26. package/dist/resources/extensions/gsd/doctor-git-checks.js +405 -0
  27. package/dist/resources/extensions/gsd/doctor-global-checks.js +74 -0
  28. package/dist/resources/extensions/gsd/doctor-runtime-checks.js +600 -0
  29. package/dist/resources/extensions/gsd/doctor.js +9 -1
  30. package/dist/resources/extensions/gsd/extension-manifest.json +1 -1
  31. package/dist/resources/extensions/gsd/git-service.js +20 -20
  32. package/dist/resources/extensions/gsd/gsd-db.js +124 -1
  33. package/dist/resources/extensions/gsd/guided-flow-queue.js +10 -11
  34. package/dist/resources/extensions/gsd/markdown-renderer.js +33 -5
  35. package/dist/resources/extensions/gsd/preferences-types.js +2 -1
  36. package/dist/resources/extensions/gsd/preferences-validation.js +39 -0
  37. package/dist/resources/extensions/gsd/prompts/complete-milestone.md +27 -8
  38. package/dist/resources/extensions/gsd/prompts/complete-slice.md +9 -8
  39. package/dist/resources/extensions/gsd/prompts/discuss-headless.md +223 -56
  40. package/dist/resources/extensions/gsd/prompts/execute-task.md +16 -13
  41. package/dist/resources/extensions/gsd/prompts/forensics.md +12 -5
  42. package/dist/resources/extensions/gsd/prompts/gate-evaluate.md +32 -0
  43. package/dist/resources/extensions/gsd/prompts/guided-complete-slice.md +1 -1
  44. package/dist/resources/extensions/gsd/prompts/guided-execute-task.md +1 -1
  45. package/dist/resources/extensions/gsd/prompts/guided-plan-milestone.md +1 -1
  46. package/dist/resources/extensions/gsd/prompts/guided-plan-slice.md +1 -1
  47. package/dist/resources/extensions/gsd/prompts/plan-milestone.md +1 -1
  48. package/dist/resources/extensions/gsd/prompts/plan-slice.md +8 -3
  49. package/dist/resources/extensions/gsd/prompts/reassess-roadmap.md +3 -0
  50. package/dist/resources/extensions/gsd/prompts/replan-slice.md +1 -1
  51. package/dist/resources/extensions/gsd/prompts/run-uat.md +4 -4
  52. package/dist/resources/extensions/gsd/repo-identity.js +29 -0
  53. package/dist/resources/extensions/gsd/roadmap-slices.js +2 -2
  54. package/dist/resources/extensions/gsd/session-forensics.js +6 -11
  55. package/dist/resources/extensions/gsd/session-lock.js +67 -56
  56. package/dist/resources/extensions/gsd/state.js +34 -7
  57. package/dist/resources/extensions/gsd/templates/milestone-summary.md +8 -0
  58. package/dist/resources/extensions/gsd/templates/plan.md +16 -0
  59. package/dist/resources/extensions/gsd/templates/roadmap.md +13 -0
  60. package/dist/resources/extensions/gsd/templates/slice-summary.md +9 -0
  61. package/dist/resources/extensions/gsd/templates/task-plan.md +24 -0
  62. package/dist/resources/extensions/gsd/tools/plan-slice.js +14 -1
  63. package/dist/resources/extensions/gsd/tools/validate-milestone.js +3 -3
  64. package/dist/resources/extensions/gsd/verdict-parser.js +84 -0
  65. package/dist/resources/extensions/gsd/worktree-command.js +1 -1
  66. package/dist/resources/extensions/gsd/worktree-resolver.js +24 -0
  67. package/dist/resources/extensions/gsd/worktree.js +3 -2
  68. package/dist/resources/extensions/remote-questions/config.js +3 -5
  69. package/dist/resources/extensions/search-the-web/native-search.js +8 -3
  70. package/dist/resources/extensions/search-the-web/tool-search.js +19 -2
  71. package/dist/resources/skills/github-workflows/references/gh/SKILL.md +22 -1
  72. package/dist/web/standalone/.next/BUILD_ID +1 -1
  73. package/dist/web/standalone/.next/app-path-routes-manifest.json +17 -17
  74. package/dist/web/standalone/.next/build-manifest.json +4 -4
  75. package/dist/web/standalone/.next/prerender-manifest.json +3 -3
  76. package/dist/web/standalone/.next/react-loadable-manifest.json +1 -1
  77. package/dist/web/standalone/.next/required-server-files.json +4 -4
  78. package/dist/web/standalone/.next/server/app/_global-error/page.js +3 -3
  79. package/dist/web/standalone/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
  80. package/dist/web/standalone/.next/server/app/_global-error.html +2 -2
  81. package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
  82. package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  83. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
  84. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
  85. package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  86. package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  87. package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  88. package/dist/web/standalone/.next/server/app/_not-found/page.js +2 -2
  89. package/dist/web/standalone/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  90. package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
  91. package/dist/web/standalone/.next/server/app/_not-found.rsc +3 -3
  92. package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +3 -3
  93. package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  94. package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +3 -3
  95. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  96. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  97. package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
  98. package/dist/web/standalone/.next/server/app/api/boot/route.js +1 -1
  99. package/dist/web/standalone/.next/server/app/api/boot/route_client-reference-manifest.js +1 -1
  100. package/dist/web/standalone/.next/server/app/api/bridge-terminal/input/route.js +1 -1
  101. package/dist/web/standalone/.next/server/app/api/bridge-terminal/input/route_client-reference-manifest.js +1 -1
  102. package/dist/web/standalone/.next/server/app/api/bridge-terminal/resize/route.js +1 -1
  103. package/dist/web/standalone/.next/server/app/api/bridge-terminal/resize/route_client-reference-manifest.js +1 -1
  104. package/dist/web/standalone/.next/server/app/api/bridge-terminal/stream/route.js +2 -2
  105. package/dist/web/standalone/.next/server/app/api/bridge-terminal/stream/route_client-reference-manifest.js +1 -1
  106. package/dist/web/standalone/.next/server/app/api/browse-directories/route.js +1 -1
  107. package/dist/web/standalone/.next/server/app/api/browse-directories/route_client-reference-manifest.js +1 -1
  108. package/dist/web/standalone/.next/server/app/api/captures/route.js +1 -1
  109. package/dist/web/standalone/.next/server/app/api/captures/route_client-reference-manifest.js +1 -1
  110. package/dist/web/standalone/.next/server/app/api/cleanup/route.js +1 -1
  111. package/dist/web/standalone/.next/server/app/api/cleanup/route_client-reference-manifest.js +1 -1
  112. package/dist/web/standalone/.next/server/app/api/dev-mode/route.js +1 -1
  113. package/dist/web/standalone/.next/server/app/api/dev-mode/route_client-reference-manifest.js +1 -1
  114. package/dist/web/standalone/.next/server/app/api/doctor/route.js +1 -1
  115. package/dist/web/standalone/.next/server/app/api/doctor/route_client-reference-manifest.js +1 -1
  116. package/dist/web/standalone/.next/server/app/api/export-data/route.js +1 -1
  117. package/dist/web/standalone/.next/server/app/api/export-data/route_client-reference-manifest.js +1 -1
  118. package/dist/web/standalone/.next/server/app/api/files/route.js +1 -1
  119. package/dist/web/standalone/.next/server/app/api/files/route_client-reference-manifest.js +1 -1
  120. package/dist/web/standalone/.next/server/app/api/forensics/route.js +1 -1
  121. package/dist/web/standalone/.next/server/app/api/forensics/route_client-reference-manifest.js +1 -1
  122. package/dist/web/standalone/.next/server/app/api/git/route.js +1 -1
  123. package/dist/web/standalone/.next/server/app/api/git/route_client-reference-manifest.js +1 -1
  124. package/dist/web/standalone/.next/server/app/api/history/route.js +1 -1
  125. package/dist/web/standalone/.next/server/app/api/history/route_client-reference-manifest.js +1 -1
  126. package/dist/web/standalone/.next/server/app/api/hooks/route.js +1 -1
  127. package/dist/web/standalone/.next/server/app/api/hooks/route_client-reference-manifest.js +1 -1
  128. package/dist/web/standalone/.next/server/app/api/inspect/route.js +1 -1
  129. package/dist/web/standalone/.next/server/app/api/inspect/route_client-reference-manifest.js +1 -1
  130. package/dist/web/standalone/.next/server/app/api/knowledge/route.js +1 -1
  131. package/dist/web/standalone/.next/server/app/api/knowledge/route_client-reference-manifest.js +1 -1
  132. package/dist/web/standalone/.next/server/app/api/live-state/route.js +1 -1
  133. package/dist/web/standalone/.next/server/app/api/live-state/route_client-reference-manifest.js +1 -1
  134. package/dist/web/standalone/.next/server/app/api/onboarding/route.js +1 -1
  135. package/dist/web/standalone/.next/server/app/api/onboarding/route_client-reference-manifest.js +1 -1
  136. package/dist/web/standalone/.next/server/app/api/preferences/route.js +1 -1
  137. package/dist/web/standalone/.next/server/app/api/preferences/route_client-reference-manifest.js +1 -1
  138. package/dist/web/standalone/.next/server/app/api/projects/route.js +1 -1
  139. package/dist/web/standalone/.next/server/app/api/projects/route_client-reference-manifest.js +1 -1
  140. package/dist/web/standalone/.next/server/app/api/recovery/route.js +1 -1
  141. package/dist/web/standalone/.next/server/app/api/recovery/route_client-reference-manifest.js +1 -1
  142. package/dist/web/standalone/.next/server/app/api/remote-questions/route.js +5 -5
  143. package/dist/web/standalone/.next/server/app/api/remote-questions/route_client-reference-manifest.js +1 -1
  144. package/dist/web/standalone/.next/server/app/api/session/browser/route.js +1 -1
  145. package/dist/web/standalone/.next/server/app/api/session/browser/route_client-reference-manifest.js +1 -1
  146. package/dist/web/standalone/.next/server/app/api/session/command/route.js +1 -1
  147. package/dist/web/standalone/.next/server/app/api/session/command/route_client-reference-manifest.js +1 -1
  148. package/dist/web/standalone/.next/server/app/api/session/events/route.js +2 -2
  149. package/dist/web/standalone/.next/server/app/api/session/events/route_client-reference-manifest.js +1 -1
  150. package/dist/web/standalone/.next/server/app/api/session/manage/route.js +1 -1
  151. package/dist/web/standalone/.next/server/app/api/session/manage/route_client-reference-manifest.js +1 -1
  152. package/dist/web/standalone/.next/server/app/api/settings-data/route.js +1 -1
  153. package/dist/web/standalone/.next/server/app/api/settings-data/route_client-reference-manifest.js +1 -1
  154. package/dist/web/standalone/.next/server/app/api/shutdown/route.js +1 -1
  155. package/dist/web/standalone/.next/server/app/api/shutdown/route_client-reference-manifest.js +1 -1
  156. package/dist/web/standalone/.next/server/app/api/skill-health/route.js +1 -1
  157. package/dist/web/standalone/.next/server/app/api/skill-health/route_client-reference-manifest.js +1 -1
  158. package/dist/web/standalone/.next/server/app/api/steer/route.js +1 -1
  159. package/dist/web/standalone/.next/server/app/api/steer/route_client-reference-manifest.js +1 -1
  160. package/dist/web/standalone/.next/server/app/api/switch-root/route.js +1 -1
  161. package/dist/web/standalone/.next/server/app/api/switch-root/route_client-reference-manifest.js +1 -1
  162. package/dist/web/standalone/.next/server/app/api/terminal/input/route.js +2 -2
  163. package/dist/web/standalone/.next/server/app/api/terminal/input/route_client-reference-manifest.js +1 -1
  164. package/dist/web/standalone/.next/server/app/api/terminal/resize/route.js +2 -2
  165. package/dist/web/standalone/.next/server/app/api/terminal/resize/route_client-reference-manifest.js +1 -1
  166. package/dist/web/standalone/.next/server/app/api/terminal/sessions/route.js +2 -2
  167. package/dist/web/standalone/.next/server/app/api/terminal/sessions/route_client-reference-manifest.js +1 -1
  168. package/dist/web/standalone/.next/server/app/api/terminal/stream/route.js +4 -4
  169. package/dist/web/standalone/.next/server/app/api/terminal/stream/route_client-reference-manifest.js +1 -1
  170. package/dist/web/standalone/.next/server/app/api/terminal/upload/route.js +1 -1
  171. package/dist/web/standalone/.next/server/app/api/terminal/upload/route_client-reference-manifest.js +1 -1
  172. package/dist/web/standalone/.next/server/app/api/undo/route.js +1 -1
  173. package/dist/web/standalone/.next/server/app/api/undo/route_client-reference-manifest.js +1 -1
  174. package/dist/web/standalone/.next/server/app/api/update/route.js +1 -1
  175. package/dist/web/standalone/.next/server/app/api/update/route_client-reference-manifest.js +1 -1
  176. package/dist/web/standalone/.next/server/app/api/visualizer/route.js +1 -1
  177. package/dist/web/standalone/.next/server/app/api/visualizer/route_client-reference-manifest.js +1 -1
  178. package/dist/web/standalone/.next/server/app/index.html +1 -1
  179. package/dist/web/standalone/.next/server/app/index.rsc +4 -4
  180. package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +2 -2
  181. package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +4 -4
  182. package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
  183. package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +3 -3
  184. package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
  185. package/dist/web/standalone/.next/server/app/page.js +2 -2
  186. package/dist/web/standalone/.next/server/app/page_client-reference-manifest.js +1 -1
  187. package/dist/web/standalone/.next/server/app-paths-manifest.json +17 -17
  188. package/dist/web/standalone/.next/server/chunks/229.js +2 -2
  189. package/dist/web/standalone/.next/server/chunks/471.js +3 -3
  190. package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
  191. package/dist/web/standalone/.next/server/middleware-react-loadable-manifest.js +1 -1
  192. package/dist/web/standalone/.next/server/middleware.js +2 -2
  193. package/dist/web/standalone/.next/server/next-font-manifest.js +1 -1
  194. package/dist/web/standalone/.next/server/next-font-manifest.json +1 -1
  195. package/dist/web/standalone/.next/server/pages/404.html +1 -1
  196. package/dist/web/standalone/.next/server/pages/500.html +2 -2
  197. package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
  198. package/dist/web/standalone/.next/static/chunks/4024.7c75ac378de0f2b5.js +9 -0
  199. package/dist/web/standalone/.next/static/chunks/app/_not-found/{page-2f24283c162b6ab3.js → page-f2a7482d42a5614b.js} +1 -1
  200. package/dist/web/standalone/.next/static/chunks/app/{layout-9ecfd95f343793f0.js → layout-a16c7a7ecdf0c2cf.js} +1 -1
  201. package/dist/web/standalone/.next/static/chunks/app/page-6654a8cca61a3d1c.js +1 -0
  202. package/dist/web/standalone/.next/static/chunks/main-app-fdab67f7802d7832.js +1 -0
  203. package/dist/web/standalone/.next/static/chunks/next/dist/client/components/builtin/global-error-459824ffb8c323dd.js +1 -0
  204. package/dist/web/standalone/.next/static/chunks/{webpack-0a4cd455ec4197d2.js → webpack-2473ce2c3879fff4.js} +1 -1
  205. package/dist/web/standalone/node_modules/node-pty/build/Makefile +2 -2
  206. package/dist/web/standalone/node_modules/node-pty/build/Release/pty.node +0 -0
  207. package/dist/web/standalone/node_modules/node-pty/build/pty.target.mk +14 -14
  208. package/dist/web/standalone/node_modules/node-pty/node-addon-api/node_addon_api.target.mk +14 -14
  209. package/dist/web/standalone/node_modules/node-pty/node-addon-api/node_addon_api_except.target.mk +14 -14
  210. package/dist/web/standalone/node_modules/node-pty/node-addon-api/node_addon_api_maybe.target.mk +14 -14
  211. package/dist/web/standalone/server.js +1 -1
  212. package/dist/worktree-cli.js +1 -1
  213. package/package.json +1 -1
  214. package/packages/pi-agent-core/dist/agent-loop.d.ts.map +1 -1
  215. package/packages/pi-agent-core/dist/agent-loop.js +4 -1
  216. package/packages/pi-agent-core/dist/agent-loop.js.map +1 -1
  217. package/packages/pi-agent-core/src/agent-loop.ts +4 -1
  218. package/packages/pi-ai/dist/providers/openai-codex-responses.js +39 -10
  219. package/packages/pi-ai/dist/providers/openai-codex-responses.js.map +1 -1
  220. package/packages/pi-ai/src/providers/openai-codex-responses.ts +39 -8
  221. package/packages/pi-coding-agent/dist/core/blob-store.d.ts.map +1 -1
  222. package/packages/pi-coding-agent/dist/core/blob-store.js +8 -3
  223. package/packages/pi-coding-agent/dist/core/blob-store.js.map +1 -1
  224. package/packages/pi-coding-agent/dist/core/discovery-cache.d.ts.map +1 -1
  225. package/packages/pi-coding-agent/dist/core/discovery-cache.js +9 -2
  226. package/packages/pi-coding-agent/dist/core/discovery-cache.js.map +1 -1
  227. package/packages/pi-coding-agent/dist/core/retry-handler.js +1 -1
  228. package/packages/pi-coding-agent/dist/core/retry-handler.js.map +1 -1
  229. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  230. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js +7 -32
  231. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js.map +1 -1
  232. package/packages/pi-coding-agent/dist/modes/rpc/jsonl.d.ts.map +1 -1
  233. package/packages/pi-coding-agent/dist/modes/rpc/jsonl.js +5 -0
  234. package/packages/pi-coding-agent/dist/modes/rpc/jsonl.js.map +1 -1
  235. package/packages/pi-coding-agent/dist/modes/rpc/rpc-client.d.ts.map +1 -1
  236. package/packages/pi-coding-agent/dist/modes/rpc/rpc-client.js +0 -1
  237. package/packages/pi-coding-agent/dist/modes/rpc/rpc-client.js.map +1 -1
  238. package/packages/pi-coding-agent/dist/modes/rpc/rpc-mode.js +1 -1
  239. package/packages/pi-coding-agent/dist/modes/rpc/rpc-mode.js.map +1 -1
  240. package/packages/pi-coding-agent/package.json +1 -1
  241. package/packages/pi-coding-agent/src/core/blob-store.ts +6 -3
  242. package/packages/pi-coding-agent/src/core/discovery-cache.ts +9 -2
  243. package/packages/pi-coding-agent/src/core/retry-handler.ts +1 -1
  244. package/packages/pi-coding-agent/src/modes/interactive/interactive-mode.ts +7 -32
  245. package/packages/pi-coding-agent/src/modes/rpc/jsonl.ts +6 -0
  246. package/packages/pi-coding-agent/src/modes/rpc/rpc-client.ts +0 -2
  247. package/packages/pi-coding-agent/src/modes/rpc/rpc-mode.ts +2 -2
  248. package/pkg/package.json +1 -1
  249. package/src/resources/extensions/github-sync/tests/commit-linking.test.ts +8 -4
  250. package/src/resources/extensions/gsd/auto/infra-errors.ts +1 -0
  251. package/src/resources/extensions/gsd/auto/phases.ts +10 -11
  252. package/src/resources/extensions/gsd/auto/resolve.ts +3 -3
  253. package/src/resources/extensions/gsd/auto/run-unit.ts +2 -2
  254. package/src/resources/extensions/gsd/auto/session.ts +5 -0
  255. package/src/resources/extensions/gsd/auto/types.ts +13 -0
  256. package/src/resources/extensions/gsd/auto-artifact-paths.ts +19 -21
  257. package/src/resources/extensions/gsd/auto-dashboard.ts +5 -2
  258. package/src/resources/extensions/gsd/auto-dispatch.ts +40 -5
  259. package/src/resources/extensions/gsd/auto-loop.ts +1 -1
  260. package/src/resources/extensions/gsd/auto-post-unit.ts +36 -31
  261. package/src/resources/extensions/gsd/auto-prompts.ts +113 -19
  262. package/src/resources/extensions/gsd/auto-recovery.ts +65 -199
  263. package/src/resources/extensions/gsd/auto-start.ts +7 -27
  264. package/src/resources/extensions/gsd/auto-timers.ts +2 -2
  265. package/src/resources/extensions/gsd/auto-verification.ts +4 -7
  266. package/src/resources/extensions/gsd/auto-worktree.ts +309 -110
  267. package/src/resources/extensions/gsd/auto.ts +11 -10
  268. package/src/resources/extensions/gsd/bootstrap/db-tools.ts +93 -0
  269. package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +8 -0
  270. package/src/resources/extensions/gsd/branch-patterns.ts +16 -0
  271. package/src/resources/extensions/gsd/commands/handlers/auto.ts +46 -3
  272. package/src/resources/extensions/gsd/doctor-checks.ts +5 -1291
  273. package/src/resources/extensions/gsd/doctor-engine-checks.ts +182 -0
  274. package/src/resources/extensions/gsd/doctor-environment.ts +30 -7
  275. package/src/resources/extensions/gsd/doctor-git-checks.ts +415 -0
  276. package/src/resources/extensions/gsd/doctor-global-checks.ts +84 -0
  277. package/src/resources/extensions/gsd/doctor-runtime-checks.ts +626 -0
  278. package/src/resources/extensions/gsd/doctor.ts +9 -1
  279. package/src/resources/extensions/gsd/extension-manifest.json +1 -1
  280. package/src/resources/extensions/gsd/git-service.ts +19 -26
  281. package/src/resources/extensions/gsd/gsd-db.ts +150 -2
  282. package/src/resources/extensions/gsd/guided-flow-queue.ts +11 -12
  283. package/src/resources/extensions/gsd/markdown-renderer.ts +37 -4
  284. package/src/resources/extensions/gsd/preferences-types.ts +5 -1
  285. package/src/resources/extensions/gsd/preferences-validation.ts +37 -0
  286. package/src/resources/extensions/gsd/prompts/complete-milestone.md +27 -8
  287. package/src/resources/extensions/gsd/prompts/complete-slice.md +9 -8
  288. package/src/resources/extensions/gsd/prompts/discuss-headless.md +223 -56
  289. package/src/resources/extensions/gsd/prompts/execute-task.md +16 -13
  290. package/src/resources/extensions/gsd/prompts/forensics.md +12 -5
  291. package/src/resources/extensions/gsd/prompts/gate-evaluate.md +32 -0
  292. package/src/resources/extensions/gsd/prompts/guided-complete-slice.md +1 -1
  293. package/src/resources/extensions/gsd/prompts/guided-execute-task.md +1 -1
  294. package/src/resources/extensions/gsd/prompts/guided-plan-milestone.md +1 -1
  295. package/src/resources/extensions/gsd/prompts/guided-plan-slice.md +1 -1
  296. package/src/resources/extensions/gsd/prompts/plan-milestone.md +1 -1
  297. package/src/resources/extensions/gsd/prompts/plan-slice.md +8 -3
  298. package/src/resources/extensions/gsd/prompts/reassess-roadmap.md +3 -0
  299. package/src/resources/extensions/gsd/prompts/replan-slice.md +1 -1
  300. package/src/resources/extensions/gsd/prompts/run-uat.md +4 -4
  301. package/src/resources/extensions/gsd/repo-identity.ts +28 -0
  302. package/src/resources/extensions/gsd/roadmap-slices.ts +2 -2
  303. package/src/resources/extensions/gsd/session-forensics.ts +6 -11
  304. package/src/resources/extensions/gsd/session-lock.ts +92 -64
  305. package/src/resources/extensions/gsd/state.ts +38 -5
  306. package/src/resources/extensions/gsd/templates/milestone-summary.md +8 -0
  307. package/src/resources/extensions/gsd/templates/plan.md +16 -0
  308. package/src/resources/extensions/gsd/templates/roadmap.md +13 -0
  309. package/src/resources/extensions/gsd/templates/slice-summary.md +9 -0
  310. package/src/resources/extensions/gsd/templates/task-plan.md +24 -0
  311. package/src/resources/extensions/gsd/tests/agent-end-retry.test.ts +2 -2
  312. package/src/resources/extensions/gsd/tests/all-milestones-complete-merge.test.ts +2 -2
  313. package/src/resources/extensions/gsd/tests/auto-loop.test.ts +35 -0
  314. package/src/resources/extensions/gsd/tests/auto-recovery.test.ts +1 -81
  315. package/src/resources/extensions/gsd/tests/auto-stash-merge.test.ts +1 -1
  316. package/src/resources/extensions/gsd/tests/auto-worktree-milestone-merge.test.ts +14 -12
  317. package/src/resources/extensions/gsd/tests/complete-slice.test.ts +2 -2
  318. package/src/resources/extensions/gsd/tests/complete-task.test.ts +2 -2
  319. package/src/resources/extensions/gsd/tests/completed-units-metrics-sync.test.ts +9 -12
  320. package/src/resources/extensions/gsd/tests/doctor-environment.test.ts +115 -1
  321. package/src/resources/extensions/gsd/tests/doctor-fixlevel.test.ts +65 -1
  322. package/src/resources/extensions/gsd/tests/doctor-git.test.ts +50 -0
  323. package/src/resources/extensions/gsd/tests/feature-branch-lifecycle-integration.test.ts +1 -1
  324. package/src/resources/extensions/gsd/tests/gate-dispatch.test.ts +189 -0
  325. package/src/resources/extensions/gsd/tests/gate-storage.test.ts +156 -0
  326. package/src/resources/extensions/gsd/tests/git-service.test.ts +68 -9
  327. package/src/resources/extensions/gsd/tests/gsd-db.test.ts +1 -1
  328. package/src/resources/extensions/gsd/tests/infra-error.test.ts +12 -2
  329. package/src/resources/extensions/gsd/tests/journal-integration.test.ts +39 -0
  330. package/src/resources/extensions/gsd/tests/md-importer.test.ts +1 -1
  331. package/src/resources/extensions/gsd/tests/memory-store.test.ts +2 -2
  332. package/src/resources/extensions/gsd/tests/milestone-transition-worktree.test.ts +2 -2
  333. package/src/resources/extensions/gsd/tests/parallel-merge.test.ts +6 -6
  334. package/src/resources/extensions/gsd/tests/quality-gates.test.ts +347 -0
  335. package/src/resources/extensions/gsd/tests/queue-completed-milestone-perf.test.ts +155 -0
  336. package/src/resources/extensions/gsd/tests/replan-slice.test.ts +2 -1
  337. package/src/resources/extensions/gsd/tests/repo-identity-worktree.test.ts +32 -0
  338. package/src/resources/extensions/gsd/tests/roadmap-slices.test.ts +26 -0
  339. package/src/resources/extensions/gsd/tests/run-uat.test.ts +87 -15
  340. package/src/resources/extensions/gsd/tests/session-lock-transient-read.test.ts +223 -0
  341. package/src/resources/extensions/gsd/tests/skill-activation.test.ts +44 -4
  342. package/src/resources/extensions/gsd/tests/tool-naming.test.ts +1 -1
  343. package/src/resources/extensions/gsd/tests/validate-milestone.test.ts +2 -1
  344. package/src/resources/extensions/gsd/tests/verification-gate.test.ts +0 -16
  345. package/src/resources/extensions/gsd/tests/worktree-resolver.test.ts +67 -0
  346. package/src/resources/extensions/gsd/tests/worktree-sync-milestones.test.ts +1 -1
  347. package/src/resources/extensions/gsd/tests/worktree-sync-overwrite-loop.test.ts +204 -0
  348. package/src/resources/extensions/gsd/tools/plan-slice.ts +16 -0
  349. package/src/resources/extensions/gsd/tools/validate-milestone.ts +3 -3
  350. package/src/resources/extensions/gsd/types.ts +30 -0
  351. package/src/resources/extensions/gsd/verdict-parser.ts +95 -0
  352. package/src/resources/extensions/gsd/verification-gate.ts +0 -2
  353. package/src/resources/extensions/gsd/worktree-command.ts +1 -1
  354. package/src/resources/extensions/gsd/worktree-resolver.ts +31 -0
  355. package/src/resources/extensions/gsd/worktree.ts +3 -2
  356. package/src/resources/extensions/remote-questions/config.ts +3 -5
  357. package/src/resources/extensions/search-the-web/native-search.ts +8 -3
  358. package/src/resources/extensions/search-the-web/tool-search.ts +22 -2
  359. package/src/resources/skills/github-workflows/references/gh/SKILL.md +22 -1
  360. package/dist/resources/extensions/gsd/auto-worktree-sync.js +0 -191
  361. package/dist/resources/extensions/gsd/resource-version.js +0 -97
  362. package/dist/web/standalone/.next/static/chunks/4024.11ca5c01938e5948.js +0 -9
  363. package/dist/web/standalone/.next/static/chunks/app/page-12dd5ece0df4badc.js +0 -1
  364. package/dist/web/standalone/.next/static/chunks/main-app-d3d4c336195465f9.js +0 -1
  365. package/dist/web/standalone/.next/static/chunks/next/dist/client/components/builtin/global-error-ab5a8926e07ec673.js +0 -1
  366. package/src/resources/extensions/gsd/auto-worktree-sync.ts +0 -234
  367. package/src/resources/extensions/gsd/resource-version.ts +0 -101
  368. /package/dist/web/standalone/.next/static/{zGWUKFTfjCQerNgsPpAbF → vNN0h0emdEi8l_npi8poE}/_buildManifest.js +0 -0
  369. /package/dist/web/standalone/.next/static/{zGWUKFTfjCQerNgsPpAbF → vNN0h0emdEi8l_npi8poE}/_ssgManifest.js +0 -0
@@ -160,15 +160,17 @@ describe("auto-worktree-milestone-merge", () => {
160
160
 
161
161
  const result = mergeMilestoneToMain(repo, "M020", roadmap);
162
162
 
163
- assert.match(result.commitMessage, /^feat\(M020\):/, "subject has conventional commit prefix");
163
+ assert.match(result.commitMessage, /^feat:/, "subject has conventional commit prefix without milestone ID");
164
164
  assert.ok(result.commitMessage.includes("Backend foundation"), "subject includes milestone title");
165
165
  assert.ok(result.commitMessage.includes("- S01: Core API"), "body lists S01");
166
166
  assert.ok(result.commitMessage.includes("- S02: Error handling"), "body lists S02");
167
167
  assert.ok(result.commitMessage.includes("- S03: Logging infra"), "body lists S03");
168
+ assert.ok(result.commitMessage.includes("GSD-Milestone: M020"), "body has GSD-Milestone trailer");
168
169
  assert.ok(result.commitMessage.includes("Branch: milestone/M020"), "body has branch metadata");
169
170
 
170
171
  const gitMsg = run("git log -1 --format=%B main", repo).trim();
171
- assert.match(gitMsg, /^feat\(M020\):/, "git commit message starts with feat(M020):");
172
+ assert.match(gitMsg, /^feat:/, "git commit message starts with feat:");
173
+ assert.ok(gitMsg.includes("GSD-Milestone: M020"), "git commit has GSD-Milestone trailer");
172
174
  assert.ok(gitMsg.includes("- S01: Core API"), "git commit body has S01");
173
175
  });
174
176
 
@@ -213,11 +215,11 @@ describe("auto-worktree-milestone-merge", () => {
213
215
  const result = mergeMilestoneToMain(repo, "M040", roadmap);
214
216
 
215
217
  const mainLog = run("git log --oneline main", repo);
216
- assert.ok(mainLog.includes("feat(M040)"), "milestone commit on main");
218
+ assert.ok(mainLog.includes("feat:"), "milestone commit on main");
217
219
 
218
220
  run("git push origin main", repo);
219
221
  const remoteLog = run("git log --oneline main", bareDir);
220
- assert.ok(remoteLog.includes("feat(M040)"), "milestone commit reachable on remote after manual push");
222
+ assert.ok(remoteLog.includes("feat:"), "milestone commit reachable on remote after manual push");
221
223
 
222
224
  assert.strictEqual(typeof result.pushed, "boolean", "pushed flag remains boolean");
223
225
  });
@@ -248,7 +250,7 @@ describe("auto-worktree-milestone-merge", () => {
248
250
  let threw = false;
249
251
  try {
250
252
  const result = mergeMilestoneToMain(repo, "M050", roadmap);
251
- assert.ok(result.commitMessage.includes("feat(M050)"), "merge commit created despite .gsd conflict");
253
+ assert.ok(result.commitMessage.includes("feat:") && result.commitMessage.includes("GSD-Milestone: M050"), "merge commit created despite .gsd conflict");
252
254
  } catch (err) {
253
255
  threw = true;
254
256
  }
@@ -274,7 +276,7 @@ describe("auto-worktree-milestone-merge", () => {
274
276
  let threw = false;
275
277
  try {
276
278
  const result = mergeMilestoneToMain(repo, "M060", roadmap);
277
- assert.ok(result.commitMessage.includes("feat(M060)"), "merge commit created");
279
+ assert.ok(result.commitMessage.includes("feat:") && result.commitMessage.includes("GSD-Milestone: M060"), "merge commit created");
278
280
  } catch (err) {
279
281
  threw = true;
280
282
  }
@@ -312,7 +314,7 @@ describe("auto-worktree-milestone-merge", () => {
312
314
  let errMsg = "";
313
315
  try {
314
316
  const result = mergeMilestoneToMain(dir, "M070", roadmap);
315
- assert.ok(result.commitMessage.includes("feat(M070)"), "merge commit created on master");
317
+ assert.ok(result.commitMessage.includes("feat:") && result.commitMessage.includes("GSD-Milestone: M070"), "merge commit created on master");
316
318
  } catch (err) {
317
319
  threw = true;
318
320
  errMsg = err instanceof Error ? err.message : String(err);
@@ -392,7 +394,7 @@ describe("auto-worktree-milestone-merge", () => {
392
394
  let threw = false;
393
395
  try {
394
396
  const result = mergeMilestoneToMain(repo, "M090", roadmap);
395
- assert.ok(result.commitMessage.includes("feat(M090)"), "#1738 merge succeeds after cleaning synced dirs");
397
+ assert.ok(result.commitMessage.includes("feat:") && result.commitMessage.includes("GSD-Milestone: M090"), "#1738 merge succeeds after cleaning synced dirs");
396
398
  } catch (err: unknown) {
397
399
  threw = true;
398
400
  }
@@ -419,7 +421,7 @@ describe("auto-worktree-milestone-merge", () => {
419
421
  let threw = false;
420
422
  try {
421
423
  const result = mergeMilestoneToMain(repo, "M100", roadmap);
422
- assert.ok(result.commitMessage.includes("feat(M100)"), "#2151: merge succeeds after stashing dirty files");
424
+ assert.ok(result.commitMessage.includes("feat:") && result.commitMessage.includes("GSD-Milestone: M100"), "#2151: merge succeeds after stashing dirty files");
423
425
  } catch {
424
426
  threw = true;
425
427
  }
@@ -519,7 +521,7 @@ describe("auto-worktree-milestone-merge", () => {
519
521
  let errMsg = "";
520
522
  try {
521
523
  const result = mergeMilestoneToMain(repo, "M140", roadmap);
522
- assert.ok(result.commitMessage.includes("feat(M140)"), "merge commit created");
524
+ assert.ok(result.commitMessage.includes("feat:") && result.commitMessage.includes("GSD-Milestone: M140"), "merge commit created");
523
525
  } catch (err) {
524
526
  threw = true;
525
527
  errMsg = err instanceof Error ? err.message : String(err);
@@ -589,7 +591,7 @@ describe("auto-worktree-milestone-merge", () => {
589
591
  assert.ok(existsSync(squashMsgPath), "SQUASH_MSG planted before merge");
590
592
 
591
593
  const result = mergeMilestoneToMain(repo, "M160", roadmap);
592
- assert.ok(result.commitMessage.includes("feat(M160)"), "merge commit created");
594
+ assert.ok(result.commitMessage.includes("feat:") && result.commitMessage.includes("GSD-Milestone: M160"), "merge commit created");
593
595
 
594
596
  assert.ok(!existsSync(squashMsgPath), "#1853: SQUASH_MSG must not persist after successful squash-merge");
595
597
  });
@@ -609,7 +611,7 @@ describe("auto-worktree-milestone-merge", () => {
609
611
  ]);
610
612
 
611
613
  const result = mergeMilestoneToMain(repo, "M170", roadmap);
612
- assert.ok(result.commitMessage.includes("feat(M170)"), "merge commit created");
614
+ assert.ok(result.commitMessage.includes("feat:") && result.commitMessage.includes("GSD-Milestone: M170"), "merge commit created");
613
615
 
614
616
  assert.ok(
615
617
  existsSync(join(repo, "uncommitted-agent-code.ts")),
@@ -125,9 +125,9 @@ console.log('\n=== complete-slice: schema v6 migration ===');
125
125
 
126
126
  const adapter = _getAdapter()!;
127
127
 
128
- // Verify schema version is current (v10 after M001 planning migrations)
128
+ // Verify schema version is current (v12 after quality gates table)
129
129
  const versionRow = adapter.prepare('SELECT MAX(version) as v FROM schema_version').get();
130
- assertEq(versionRow?.['v'], 11, 'schema version should be 11');
130
+ assertEq(versionRow?.['v'], 12, 'schema version should be 12');
131
131
 
132
132
  // Verify slices table has full_summary_md and full_uat_md columns
133
133
  const cols = adapter.prepare("PRAGMA table_info(slices)").all();
@@ -109,9 +109,9 @@ console.log('\n=== complete-task: schema v5 migration ===');
109
109
 
110
110
  const adapter = _getAdapter()!;
111
111
 
112
- // Verify schema version is current (v11 after state machine migration)
112
+ // Verify schema version is current (v12 after quality gates table)
113
113
  const versionRow = adapter.prepare('SELECT MAX(version) as v FROM schema_version').get();
114
- assertEq(versionRow?.['v'], 11, 'schema version should be 11');
114
+ assertEq(versionRow?.['v'], 12, 'schema version should be 12');
115
115
 
116
116
  // Verify all 4 new tables exist
117
117
  const tables = adapter.prepare(
@@ -48,35 +48,32 @@ test("#2313: completed-units.json should not be blindly wiped to [] on milestone
48
48
  // ─── Bug 2: metrics.json should be in the sync file lists ──────────────────
49
49
 
50
50
  test("#2313: syncStateToProjectRoot should sync metrics.json", () => {
51
- const syncSrcPath = join(import.meta.dirname, "..", "auto-worktree-sync.ts");
51
+ const syncSrcPath = join(import.meta.dirname, "..", "auto-worktree.ts");
52
52
  const syncSrc = readFileSync(syncSrcPath, "utf-8");
53
53
 
54
54
  // syncStateToProjectRoot should copy metrics.json from worktree to project root
55
55
  assert.ok(
56
56
  syncSrc.includes("metrics.json"),
57
- "auto-worktree-sync.ts should reference metrics.json for sync",
57
+ "auto-worktree.ts should reference metrics.json for sync",
58
58
  );
59
59
  });
60
60
 
61
- test("#2313: syncWorktreeStateBack should include metrics.json in root files list", () => {
61
+ test("#2313: syncWorktreeStateBack should include metrics.json in ROOT_STATE_FILES", () => {
62
62
  const autoWorktreeSrcPath = join(import.meta.dirname, "..", "auto-worktree.ts");
63
63
  const autoWorktreeSrc = readFileSync(autoWorktreeSrcPath, "utf-8");
64
64
 
65
- // Find the rootFiles array in syncWorktreeStateBack
66
- const syncBackIdx = autoWorktreeSrc.indexOf("syncWorktreeStateBack");
67
- assert.ok(syncBackIdx !== -1, "syncWorktreeStateBack exists");
65
+ // Find the ROOT_STATE_FILES constant (single source of truth for both sync directions)
66
+ const constIdx = autoWorktreeSrc.indexOf("ROOT_STATE_FILES");
67
+ assert.ok(constIdx !== -1, "ROOT_STATE_FILES constant exists");
68
68
 
69
- const rootFilesIdx = autoWorktreeSrc.indexOf("rootFiles", syncBackIdx);
70
- assert.ok(rootFilesIdx !== -1, "rootFiles list exists in syncWorktreeStateBack");
71
-
72
- // Get the rootFiles array content
73
- const arrayStart = autoWorktreeSrc.indexOf("[", rootFilesIdx);
69
+ // Get the array content
70
+ const arrayStart = autoWorktreeSrc.indexOf("[", constIdx);
74
71
  const arrayEnd = autoWorktreeSrc.indexOf("]", arrayStart);
75
72
  const rootFilesBlock = autoWorktreeSrc.slice(arrayStart, arrayEnd);
76
73
 
77
74
  assert.ok(
78
75
  rootFilesBlock.includes("metrics.json"),
79
- "metrics.json should be in syncWorktreeStateBack rootFiles list",
76
+ "metrics.json should be in ROOT_STATE_FILES list",
80
77
  );
81
78
  });
82
79
 
@@ -15,7 +15,7 @@ import assert from 'node:assert/strict';
15
15
  * - Report formatting
16
16
  */
17
17
 
18
- import { mkdtempSync, mkdirSync, writeFileSync, rmSync } from "node:fs";
18
+ import { mkdtempSync, mkdirSync, writeFileSync, rmSync, utimesSync } from "node:fs";
19
19
  import { join, dirname } from "node:path";
20
20
  import { tmpdir } from "node:os";
21
21
 
@@ -102,6 +102,120 @@ describe('doctor-environment', async () => {
102
102
  assert.deepStrictEqual(depsCheck!.status, "ok", "existing node_modules is ok");
103
103
  });
104
104
 
105
+ // ── Stale Dependencies: marker file check (#1974) ──────────────────
106
+ console.log("\n=== env: npm marker file newer than lockfile → ok (#1974) ===");
107
+ {
108
+ // Simulate the exact bug scenario:
109
+ // 1. node_modules dir mtime is old (no entries added/removed recently)
110
+ // 2. package-lock.json mtime is recent (npm rewrote it)
111
+ // 3. node_modules/.package-lock.json mtime is between dir and lockfile
112
+ // (npm wrote it during the same install that rewrote the lockfile)
113
+ //
114
+ // The bug: code compares lockfile mtime vs dir mtime → false positive warning
115
+ // The fix: compare lockfile mtime vs marker file mtime → correctly ok
116
+ const dir = createProjectDir({
117
+ "package.json": JSON.stringify({ name: "test" }),
118
+ });
119
+ mkdirSync(join(dir, "node_modules"), { recursive: true });
120
+
121
+ // Simulate the exact bug: npm install with "up to date" rewrites the
122
+ // lockfile and the marker, but no packages are added/removed so the
123
+ // directory mtime should be old. We write the marker first (which
124
+ // bumps dir mtime), then force the dir mtime back to the past.
125
+ //
126
+ // Timeline: dir(T-120s) < lockfile(T-5s) ≈ marker(T-5s)
127
+ // Bug: code compares lockfile vs dir → false positive stale warning
128
+ // Fix: code compares lockfile vs marker → correctly reports ok
129
+ const dirTime = new Date(Date.now() - 120_000);
130
+ const installTime = new Date(Date.now() - 5_000);
131
+
132
+ // Write marker file (this bumps dir mtime as a side effect)
133
+ writeFileSync(join(dir, "node_modules", ".package-lock.json"), "{}");
134
+ utimesSync(join(dir, "node_modules", ".package-lock.json"), installTime, installTime);
135
+
136
+ // Force dir mtime back to the past — simulates no top-level entries changed
137
+ utimesSync(join(dir, "node_modules"), dirTime, dirTime);
138
+
139
+ // Lockfile written at install time (same as marker, or slightly after)
140
+ writeFileSync(join(dir, "package-lock.json"), "{}");
141
+ utimesSync(join(dir, "package-lock.json"), installTime, installTime);
142
+
143
+ cleanups.push(dir);
144
+ const results = runEnvironmentChecks(dir);
145
+ const depsCheck = results.find(r => r.name === "dependencies");
146
+ assert.ok(depsCheck !== undefined, "dependencies check runs");
147
+ assert.equal(depsCheck!.status, "ok", "npm marker newer than lockfile → not stale");
148
+ }
149
+
150
+ console.log("\n=== env: yarn marker file newer than lockfile → ok (#1974) ===");
151
+ {
152
+ const dir = createProjectDir({
153
+ "package.json": JSON.stringify({ name: "test" }),
154
+ });
155
+ mkdirSync(join(dir, "node_modules"), { recursive: true });
156
+
157
+ const dirTime = new Date(Date.now() - 120_000);
158
+ const installTime = new Date(Date.now() - 5_000);
159
+
160
+ writeFileSync(join(dir, "node_modules", ".yarn-integrity"), "{}");
161
+ utimesSync(join(dir, "node_modules", ".yarn-integrity"), installTime, installTime);
162
+ utimesSync(join(dir, "node_modules"), dirTime, dirTime);
163
+
164
+ writeFileSync(join(dir, "yarn.lock"), "");
165
+ utimesSync(join(dir, "yarn.lock"), installTime, installTime);
166
+
167
+ cleanups.push(dir);
168
+ const results = runEnvironmentChecks(dir);
169
+ const depsCheck = results.find(r => r.name === "dependencies");
170
+ assert.ok(depsCheck !== undefined, "dependencies check runs");
171
+ assert.equal(depsCheck!.status, "ok", "yarn marker newer than lockfile → not stale");
172
+ }
173
+
174
+ console.log("\n=== env: pnpm marker file newer than lockfile → ok (#1974) ===");
175
+ {
176
+ const dir = createProjectDir({
177
+ "package.json": JSON.stringify({ name: "test" }),
178
+ });
179
+ mkdirSync(join(dir, "node_modules"), { recursive: true });
180
+
181
+ const dirTime = new Date(Date.now() - 120_000);
182
+ const installTime = new Date(Date.now() - 5_000);
183
+
184
+ writeFileSync(join(dir, "node_modules", ".modules.yaml"), "{}");
185
+ utimesSync(join(dir, "node_modules", ".modules.yaml"), installTime, installTime);
186
+ utimesSync(join(dir, "node_modules"), dirTime, dirTime);
187
+
188
+ writeFileSync(join(dir, "pnpm-lock.yaml"), "");
189
+ utimesSync(join(dir, "pnpm-lock.yaml"), installTime, installTime);
190
+
191
+ cleanups.push(dir);
192
+ const results = runEnvironmentChecks(dir);
193
+ const depsCheck = results.find(r => r.name === "dependencies");
194
+ assert.ok(depsCheck !== undefined, "dependencies check runs");
195
+ assert.equal(depsCheck!.status, "ok", "pnpm marker newer than lockfile → not stale");
196
+ }
197
+
198
+ console.log("\n=== env: no marker file falls back to dir mtime → stale warning (#1974) ===");
199
+ {
200
+ // No marker file exists, lockfile newer than dir → should still warn
201
+ const dir = createProjectDir({
202
+ "package.json": JSON.stringify({ name: "test" }),
203
+ });
204
+ mkdirSync(join(dir, "node_modules"), { recursive: true });
205
+
206
+ const past = new Date(Date.now() - 60_000);
207
+ utimesSync(join(dir, "node_modules"), past, past);
208
+
209
+ writeFileSync(join(dir, "package-lock.json"), "{}");
210
+ // No marker file written — fallback to dir mtime comparison
211
+
212
+ cleanups.push(dir);
213
+ const results = runEnvironmentChecks(dir);
214
+ const depsCheck = results.find(r => r.name === "dependencies");
215
+ assert.ok(depsCheck !== undefined, "dependencies check runs");
216
+ assert.equal(depsCheck!.status, "warning", "no marker + lockfile newer → stale warning");
217
+ }
218
+
105
219
  // ── Env File Check ─────────────────────────────────────────────────
106
220
  test('env: .env.example without .env detected', () => {
107
221
  const dir = createProjectDir({
@@ -15,6 +15,7 @@ import { tmpdir } from "node:os";
15
15
  import test from "node:test";
16
16
  import assert from "node:assert/strict";
17
17
  import { runGSDDoctor } from "../doctor.ts";
18
+ import { closeDatabase } from "../gsd-db.ts";
18
19
 
19
20
  function makeTmp(name: string): string {
20
21
  const dir = join(tmpdir(), `doctor-fixlevel-${name}-${Date.now()}-${Math.random().toString(36).slice(2)}`);
@@ -112,6 +113,70 @@ test("fixLevel:all — no reconciliation issue codes are reported", async (t) =>
112
113
  assert.ok(roadmapContent.includes("- [ ] **S01"), "roadmap should remain unchecked");
113
114
  });
114
115
 
116
+ test("legacy roadmap fallback: future slices are treated as pending, active slice is not", async (t) => {
117
+ const tmp = makeTmp("legacy-pending-fallback");
118
+ t.after(() => {
119
+ try { closeDatabase(); } catch { /* noop */ }
120
+ rmSync(tmp, { recursive: true, force: true });
121
+ });
122
+
123
+ // Force the legacy parser branch.
124
+ try { closeDatabase(); } catch { /* noop */ }
125
+
126
+ const gsd = join(tmp, ".gsd");
127
+ const m = join(gsd, "milestones", "M001");
128
+ const s01 = join(m, "slices", "S01", "tasks");
129
+ mkdirSync(s01, { recursive: true });
130
+
131
+ writeFileSync(join(m, "M001-ROADMAP.md"), `# M001: Test
132
+
133
+ ## Slices
134
+
135
+ - [x] **S01: Done Slice** \`risk:low\` \`depends:[]\`
136
+ > Done
137
+ - [ ] **S02: Active Slice** \`risk:medium\` \`depends:[S01]\`
138
+ > In progress
139
+ - [ ] **S03: Future Slice** \`risk:low\` \`depends:[S02]\`
140
+ > Later
141
+ - [ ] **S04: Future Slice Two** \`risk:low\` \`depends:[S03]\`
142
+ > Later
143
+ `);
144
+
145
+ writeFileSync(join(m, "slices", "S01", "S01-PLAN.md"), `# S01: Done Slice
146
+
147
+ **Goal:** done
148
+
149
+ ## Tasks
150
+
151
+ - [x] **T01: Done task** \`est:5m\`
152
+ `);
153
+
154
+ // Active slice exists in state/registry but has no directory yet — this should
155
+ // still be reported as a real error, while future untouched slices should be skipped.
156
+ const report = await runGSDDoctor(tmp, { scope: "M001" });
157
+ const missingSliceDirUnits = report.issues
158
+ .filter(i => i.code === "missing_slice_dir")
159
+ .map(i => i.unitId)
160
+ .sort();
161
+
162
+ assert.deepStrictEqual(
163
+ missingSliceDirUnits,
164
+ ["M001/S02"],
165
+ "legacy fallback should only report the active slice, not future unstarted slices",
166
+ );
167
+
168
+ const missingTasksDirUnits = report.issues
169
+ .filter(i => i.code === "missing_tasks_dir")
170
+ .map(i => i.unitId)
171
+ .sort();
172
+
173
+ assert.deepStrictEqual(
174
+ missingTasksDirUnits,
175
+ [],
176
+ "future slices without directories should be skipped before missing_tasks_dir checks",
177
+ );
178
+ });
179
+
115
180
  test("fixLevel:all — delimiter_in_title still fixable", async (t) => {
116
181
  const tmp = makeTmp("delimiter-fix");
117
182
  t.after(() => rmSync(tmp, { recursive: true, force: true }));
@@ -141,7 +206,6 @@ test("fixLevel:all — delimiter_in_title still fixable", async (t) => {
141
206
 
142
207
  const report = await runGSDDoctor(tmp, { fix: true });
143
208
 
144
- const delimiterIssues = report.issues.filter(i => i.code === "delimiter_in_title");
145
209
  // The milestone-level delimiter is auto-fixed, but the report may or may not include it
146
210
  // depending on whether it was fixed successfully. Just verify it ran without crashing.
147
211
  assert.ok(report.issues !== undefined, "doctor produces a report");
@@ -145,6 +145,56 @@ describe('doctor-git', async () => {
145
145
  } else {
146
146
  }
147
147
 
148
+ // ─── Test 1b: Orphaned worktree fix when cwd is inside worktree (#1946) ──
149
+ // Reproduces the deadlock: if process.cwd() is inside the orphaned worktree,
150
+ // the doctor must chdir out before removing it — not skip the removal.
151
+ if (process.platform !== "win32") {
152
+ console.log("\n=== orphaned_auto_worktree (cwd inside worktree) ===");
153
+ {
154
+ const dir = createRepoWithCompletedMilestone();
155
+ cleanups.push(dir);
156
+
157
+ // Create worktree with milestone/M001 branch under .gsd/worktrees/
158
+ mkdirSync(join(dir, ".gsd", "worktrees"), { recursive: true });
159
+ run("git worktree add -b milestone/M001 .gsd/worktrees/M001", dir);
160
+
161
+ const wtPath = realpathSync(join(dir, ".gsd", "worktrees", "M001"));
162
+
163
+ // Simulate the deadlock: set cwd inside the orphaned worktree
164
+ const previousCwd = process.cwd();
165
+ process.chdir(wtPath);
166
+ try {
167
+ const fixed = await runGSDDoctor(dir, { fix: true, isolationMode: "worktree" });
168
+
169
+ // The fix must NOT skip removal — it should chdir out and remove
170
+ assert.ok(
171
+ !fixed.fixesApplied.some(f => f.includes("skipped removing worktree")),
172
+ "does NOT skip removal when cwd is inside worktree",
173
+ );
174
+ assert.ok(
175
+ fixed.fixesApplied.some(f => f.includes("removed orphaned worktree")),
176
+ "removes orphaned worktree even when cwd was inside it",
177
+ );
178
+
179
+ // Verify worktree is gone
180
+ const wtList = run("git worktree list", dir);
181
+ assert.ok(!wtList.includes("milestone/M001"), "worktree removed after fix with cwd inside");
182
+
183
+ // Verify cwd was moved out (should be basePath, not still inside worktree)
184
+ const newCwd = process.cwd();
185
+ assert.ok(
186
+ !newCwd.startsWith(wtPath),
187
+ "cwd moved out of worktree after fix",
188
+ );
189
+ } finally {
190
+ // Restore cwd — the worktree dir may be gone, so chdir to previousCwd
191
+ try { process.chdir(previousCwd); } catch { process.chdir(dir); }
192
+ }
193
+ }
194
+ } else {
195
+ console.log("\n=== orphaned_auto_worktree (cwd inside worktree — skipped on Windows) ===");
196
+ }
197
+
148
198
  // ─── Test 2: Stale milestone branch detection & fix ────────────────
149
199
  // Skip on Windows: git branch glob matching and path resolution
150
200
  // behave differently in Windows temp dirs.
@@ -252,7 +252,7 @@ describe('feature-branch-lifecycle-integration', async () => {
252
252
  // Exactly one new commit on feature branch (the squash merge)
253
253
  const featureLog = run(`git log --oneline ${featureBranch}`, repo);
254
254
  assert.ok(
255
- featureLog.includes(`feat(${milestoneId})`),
255
+ featureLog.includes("feat:"),
256
256
  "feature branch has milestone merge commit",
257
257
  );
258
258
 
@@ -0,0 +1,189 @@
1
+ // Quality gate dispatch + state derivation tests
2
+ // Verifies the evaluating-gates phase and dispatch rule behavior.
3
+
4
+ import { describe, test, beforeEach, afterEach } from "node:test";
5
+ import assert from "node:assert/strict";
6
+ import { mkdtempSync, mkdirSync, writeFileSync, rmSync } from "node:fs";
7
+ import { join } from "node:path";
8
+ import { tmpdir } from "node:os";
9
+
10
+ import {
11
+ openDatabase,
12
+ closeDatabase,
13
+ insertMilestone,
14
+ insertSlice,
15
+ insertTask,
16
+ upsertSlicePlanning,
17
+ upsertTaskPlanning,
18
+ insertGateRow,
19
+ saveGateResult,
20
+ markAllGatesOmitted,
21
+ getPendingSliceGateCount,
22
+ } from "../gsd-db.ts";
23
+ import { deriveState, invalidateStateCache } from "../state.ts";
24
+ import { renderPlanFromDb } from "../markdown-renderer.ts";
25
+ import { invalidateAllCaches } from "../cache.ts";
26
+
27
+ function setupTestProject(): { tmpDir: string; dbPath: string } {
28
+ const tmpDir = mkdtempSync(join(tmpdir(), "gate-dispatch-"));
29
+ const dbPath = join(tmpDir, ".gsd", "gsd.db");
30
+ mkdirSync(join(tmpDir, ".gsd"), { recursive: true });
31
+ openDatabase(dbPath);
32
+
33
+ // Create milestone
34
+ insertMilestone({
35
+ id: "M001",
36
+ title: "Test Milestone",
37
+ status: "active",
38
+ });
39
+
40
+ // Create slice
41
+ insertSlice({
42
+ milestoneId: "M001",
43
+ id: "S01",
44
+ title: "Test Slice",
45
+ status: "pending",
46
+ risk: "medium",
47
+ depends: [],
48
+ });
49
+
50
+ // Write roadmap file (required for deriveState)
51
+ const milestoneDir = join(tmpDir, ".gsd", "milestones", "M001");
52
+ mkdirSync(milestoneDir, { recursive: true });
53
+ writeFileSync(
54
+ join(milestoneDir, "M001-ROADMAP.md"),
55
+ [
56
+ "# M001: Test Milestone",
57
+ "",
58
+ "## Vision",
59
+ "Test milestone vision.",
60
+ "",
61
+ "## Success Criteria",
62
+ "- Test criteria",
63
+ "",
64
+ "## Delivery Sequence",
65
+ "- [ ] **S01: Test Slice** `risk:medium`",
66
+ " After this: test demo",
67
+ "",
68
+ ].join("\n"),
69
+ );
70
+
71
+ return { tmpDir, dbPath };
72
+ }
73
+
74
+ function planSlice(tmpDir: string) {
75
+ upsertSlicePlanning("M001", "S01", {
76
+ goal: "Test goal",
77
+ successCriteria: "Test criteria",
78
+ proofLevel: "contract",
79
+ integrationClosure: "",
80
+ observabilityImpact: "Run tests",
81
+ });
82
+ insertTask({
83
+ id: "T01",
84
+ sliceId: "S01",
85
+ milestoneId: "M001",
86
+ title: "Test Task",
87
+ status: "pending",
88
+ });
89
+ upsertTaskPlanning("M001", "S01", "T01", {
90
+ title: "Test Task",
91
+ description: "Implement test",
92
+ estimate: "1h",
93
+ files: ["src/test.ts"],
94
+ verify: "npm test",
95
+ inputs: [],
96
+ expectedOutput: ["src/test.ts"],
97
+ observabilityImpact: "",
98
+ fullPlanMd: "",
99
+ });
100
+ }
101
+
102
+ describe("evaluating-gates phase", () => {
103
+ let tmpDir: string;
104
+
105
+ beforeEach(() => {
106
+ const setup = setupTestProject();
107
+ tmpDir = setup.tmpDir;
108
+ });
109
+
110
+ afterEach(() => {
111
+ invalidateAllCaches();
112
+ invalidateStateCache();
113
+ closeDatabase();
114
+ rmSync(tmpDir, { recursive: true, force: true });
115
+ });
116
+
117
+ test("state returns evaluating-gates when slice gates are pending", async () => {
118
+ planSlice(tmpDir);
119
+ await renderPlanFromDb(tmpDir, "M001", "S01");
120
+
121
+ // Seed gates as pending
122
+ insertGateRow({ milestoneId: "M001", sliceId: "S01", gateId: "Q3", scope: "slice" });
123
+ insertGateRow({ milestoneId: "M001", sliceId: "S01", gateId: "Q4", scope: "slice" });
124
+
125
+ invalidateStateCache();
126
+ const state = await deriveState(tmpDir);
127
+ assert.equal(state.phase, "evaluating-gates");
128
+ assert.ok(state.nextAction.includes("quality gate"));
129
+ });
130
+
131
+ test("state returns executing when all gates are resolved", async () => {
132
+ planSlice(tmpDir);
133
+ await renderPlanFromDb(tmpDir, "M001", "S01");
134
+
135
+ insertGateRow({ milestoneId: "M001", sliceId: "S01", gateId: "Q3", scope: "slice" });
136
+ insertGateRow({ milestoneId: "M001", sliceId: "S01", gateId: "Q4", scope: "slice" });
137
+
138
+ saveGateResult({ milestoneId: "M001", sliceId: "S01", gateId: "Q3", verdict: "pass", rationale: "OK", findings: "" });
139
+ saveGateResult({ milestoneId: "M001", sliceId: "S01", gateId: "Q4", verdict: "omitted", rationale: "N/A", findings: "" });
140
+
141
+ invalidateStateCache();
142
+ const state = await deriveState(tmpDir);
143
+ assert.equal(state.phase, "executing");
144
+ });
145
+
146
+ test("state returns executing when no gates exist (backward compat)", async () => {
147
+ planSlice(tmpDir);
148
+ await renderPlanFromDb(tmpDir, "M001", "S01");
149
+
150
+ // No gates seeded at all
151
+ invalidateStateCache();
152
+ const state = await deriveState(tmpDir);
153
+ assert.equal(state.phase, "executing");
154
+ });
155
+
156
+ test("markAllGatesOmitted clears evaluating-gates phase", async () => {
157
+ planSlice(tmpDir);
158
+ await renderPlanFromDb(tmpDir, "M001", "S01");
159
+
160
+ insertGateRow({ milestoneId: "M001", sliceId: "S01", gateId: "Q3", scope: "slice" });
161
+ insertGateRow({ milestoneId: "M001", sliceId: "S01", gateId: "Q4", scope: "slice" });
162
+
163
+ invalidateStateCache();
164
+ assert.equal((await deriveState(tmpDir)).phase, "evaluating-gates");
165
+
166
+ markAllGatesOmitted("M001", "S01");
167
+ invalidateStateCache();
168
+ assert.equal((await deriveState(tmpDir)).phase, "executing");
169
+ });
170
+
171
+ test("task-scoped gates do not block evaluating-gates phase", async () => {
172
+ planSlice(tmpDir);
173
+ await renderPlanFromDb(tmpDir, "M001", "S01");
174
+
175
+ // Only task-scoped gates — no slice-scoped gates
176
+ insertGateRow({ milestoneId: "M001", sliceId: "S01", gateId: "Q5", scope: "task", taskId: "T01" });
177
+
178
+ invalidateStateCache();
179
+ const state = await deriveState(tmpDir);
180
+ // Should be executing, not evaluating-gates, because Q5 is task-scoped
181
+ assert.equal(state.phase, "executing");
182
+ });
183
+
184
+ test("getPendingSliceGateCount ignores task-scoped gates", () => {
185
+ insertGateRow({ milestoneId: "M001", sliceId: "S01", gateId: "Q3", scope: "slice" });
186
+ insertGateRow({ milestoneId: "M001", sliceId: "S01", gateId: "Q5", scope: "task", taskId: "T01" });
187
+ assert.equal(getPendingSliceGateCount("M001", "S01"), 1);
188
+ });
189
+ });