gsd-pi 2.49.0 → 2.50.0-dev.9476db8

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 (353) 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 +33 -21
  11. package/dist/resources/extensions/gsd/auto-post-unit.js +17 -24
  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 +257 -113
  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/doctor-checks.js +5 -1234
  23. package/dist/resources/extensions/gsd/doctor-engine-checks.js +168 -0
  24. package/dist/resources/extensions/gsd/doctor-environment.js +28 -7
  25. package/dist/resources/extensions/gsd/doctor-git-checks.js +405 -0
  26. package/dist/resources/extensions/gsd/doctor-global-checks.js +74 -0
  27. package/dist/resources/extensions/gsd/doctor-runtime-checks.js +600 -0
  28. package/dist/resources/extensions/gsd/doctor.js +9 -1
  29. package/dist/resources/extensions/gsd/extension-manifest.json +1 -1
  30. package/dist/resources/extensions/gsd/git-service.js +9 -10
  31. package/dist/resources/extensions/gsd/gsd-db.js +124 -1
  32. package/dist/resources/extensions/gsd/guided-flow-queue.js +10 -11
  33. package/dist/resources/extensions/gsd/markdown-renderer.js +33 -5
  34. package/dist/resources/extensions/gsd/preferences-types.js +2 -1
  35. package/dist/resources/extensions/gsd/preferences-validation.js +39 -0
  36. package/dist/resources/extensions/gsd/prompts/complete-milestone.md +27 -8
  37. package/dist/resources/extensions/gsd/prompts/complete-slice.md +9 -8
  38. package/dist/resources/extensions/gsd/prompts/execute-task.md +16 -13
  39. package/dist/resources/extensions/gsd/prompts/forensics.md +12 -5
  40. package/dist/resources/extensions/gsd/prompts/gate-evaluate.md +32 -0
  41. package/dist/resources/extensions/gsd/prompts/guided-complete-slice.md +1 -1
  42. package/dist/resources/extensions/gsd/prompts/guided-execute-task.md +1 -1
  43. package/dist/resources/extensions/gsd/prompts/guided-plan-milestone.md +1 -1
  44. package/dist/resources/extensions/gsd/prompts/guided-plan-slice.md +1 -1
  45. package/dist/resources/extensions/gsd/prompts/plan-milestone.md +1 -1
  46. package/dist/resources/extensions/gsd/prompts/plan-slice.md +8 -3
  47. package/dist/resources/extensions/gsd/prompts/reassess-roadmap.md +3 -0
  48. package/dist/resources/extensions/gsd/prompts/replan-slice.md +1 -1
  49. package/dist/resources/extensions/gsd/repo-identity.js +29 -0
  50. package/dist/resources/extensions/gsd/roadmap-slices.js +2 -2
  51. package/dist/resources/extensions/gsd/session-forensics.js +6 -11
  52. package/dist/resources/extensions/gsd/session-lock.js +67 -56
  53. package/dist/resources/extensions/gsd/state.js +34 -7
  54. package/dist/resources/extensions/gsd/templates/milestone-summary.md +8 -0
  55. package/dist/resources/extensions/gsd/templates/plan.md +16 -0
  56. package/dist/resources/extensions/gsd/templates/roadmap.md +13 -0
  57. package/dist/resources/extensions/gsd/templates/slice-summary.md +9 -0
  58. package/dist/resources/extensions/gsd/templates/task-plan.md +24 -0
  59. package/dist/resources/extensions/gsd/tools/plan-slice.js +14 -1
  60. package/dist/resources/extensions/gsd/tools/validate-milestone.js +3 -3
  61. package/dist/resources/extensions/gsd/verdict-parser.js +84 -0
  62. package/dist/resources/extensions/gsd/worktree-resolver.js +24 -0
  63. package/dist/resources/extensions/gsd/worktree.js +3 -2
  64. package/dist/resources/extensions/remote-questions/config.js +3 -5
  65. package/dist/resources/extensions/search-the-web/native-search.js +8 -3
  66. package/dist/resources/extensions/search-the-web/tool-search.js +19 -2
  67. package/dist/resources/skills/github-workflows/references/gh/SKILL.md +22 -1
  68. package/dist/web/standalone/.next/BUILD_ID +1 -1
  69. package/dist/web/standalone/.next/app-path-routes-manifest.json +13 -13
  70. package/dist/web/standalone/.next/build-manifest.json +4 -4
  71. package/dist/web/standalone/.next/prerender-manifest.json +3 -3
  72. package/dist/web/standalone/.next/react-loadable-manifest.json +1 -1
  73. package/dist/web/standalone/.next/required-server-files.json +4 -4
  74. package/dist/web/standalone/.next/server/app/_global-error/page.js +3 -3
  75. package/dist/web/standalone/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
  76. package/dist/web/standalone/.next/server/app/_global-error.html +2 -2
  77. package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
  78. package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  79. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
  80. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
  81. package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  82. package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  83. package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  84. package/dist/web/standalone/.next/server/app/_not-found/page.js +2 -2
  85. package/dist/web/standalone/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  86. package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
  87. package/dist/web/standalone/.next/server/app/_not-found.rsc +3 -3
  88. package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +3 -3
  89. package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  90. package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +3 -3
  91. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  92. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  93. package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
  94. package/dist/web/standalone/.next/server/app/api/boot/route.js +1 -1
  95. package/dist/web/standalone/.next/server/app/api/boot/route_client-reference-manifest.js +1 -1
  96. package/dist/web/standalone/.next/server/app/api/bridge-terminal/input/route.js +1 -1
  97. package/dist/web/standalone/.next/server/app/api/bridge-terminal/input/route_client-reference-manifest.js +1 -1
  98. package/dist/web/standalone/.next/server/app/api/bridge-terminal/resize/route.js +1 -1
  99. package/dist/web/standalone/.next/server/app/api/bridge-terminal/resize/route_client-reference-manifest.js +1 -1
  100. package/dist/web/standalone/.next/server/app/api/bridge-terminal/stream/route.js +2 -2
  101. package/dist/web/standalone/.next/server/app/api/bridge-terminal/stream/route_client-reference-manifest.js +1 -1
  102. package/dist/web/standalone/.next/server/app/api/browse-directories/route.js +1 -1
  103. package/dist/web/standalone/.next/server/app/api/browse-directories/route_client-reference-manifest.js +1 -1
  104. package/dist/web/standalone/.next/server/app/api/captures/route.js +1 -1
  105. package/dist/web/standalone/.next/server/app/api/captures/route_client-reference-manifest.js +1 -1
  106. package/dist/web/standalone/.next/server/app/api/cleanup/route.js +1 -1
  107. package/dist/web/standalone/.next/server/app/api/cleanup/route_client-reference-manifest.js +1 -1
  108. package/dist/web/standalone/.next/server/app/api/dev-mode/route.js +1 -1
  109. package/dist/web/standalone/.next/server/app/api/dev-mode/route_client-reference-manifest.js +1 -1
  110. package/dist/web/standalone/.next/server/app/api/doctor/route.js +1 -1
  111. package/dist/web/standalone/.next/server/app/api/doctor/route_client-reference-manifest.js +1 -1
  112. package/dist/web/standalone/.next/server/app/api/export-data/route.js +1 -1
  113. package/dist/web/standalone/.next/server/app/api/export-data/route_client-reference-manifest.js +1 -1
  114. package/dist/web/standalone/.next/server/app/api/files/route.js +1 -1
  115. package/dist/web/standalone/.next/server/app/api/files/route_client-reference-manifest.js +1 -1
  116. package/dist/web/standalone/.next/server/app/api/forensics/route.js +1 -1
  117. package/dist/web/standalone/.next/server/app/api/forensics/route_client-reference-manifest.js +1 -1
  118. package/dist/web/standalone/.next/server/app/api/git/route.js +1 -1
  119. package/dist/web/standalone/.next/server/app/api/git/route_client-reference-manifest.js +1 -1
  120. package/dist/web/standalone/.next/server/app/api/history/route.js +1 -1
  121. package/dist/web/standalone/.next/server/app/api/history/route_client-reference-manifest.js +1 -1
  122. package/dist/web/standalone/.next/server/app/api/hooks/route.js +1 -1
  123. package/dist/web/standalone/.next/server/app/api/hooks/route_client-reference-manifest.js +1 -1
  124. package/dist/web/standalone/.next/server/app/api/inspect/route.js +1 -1
  125. package/dist/web/standalone/.next/server/app/api/inspect/route_client-reference-manifest.js +1 -1
  126. package/dist/web/standalone/.next/server/app/api/knowledge/route.js +1 -1
  127. package/dist/web/standalone/.next/server/app/api/knowledge/route_client-reference-manifest.js +1 -1
  128. package/dist/web/standalone/.next/server/app/api/live-state/route.js +1 -1
  129. package/dist/web/standalone/.next/server/app/api/live-state/route_client-reference-manifest.js +1 -1
  130. package/dist/web/standalone/.next/server/app/api/onboarding/route.js +1 -1
  131. package/dist/web/standalone/.next/server/app/api/onboarding/route_client-reference-manifest.js +1 -1
  132. package/dist/web/standalone/.next/server/app/api/preferences/route.js +1 -1
  133. package/dist/web/standalone/.next/server/app/api/preferences/route_client-reference-manifest.js +1 -1
  134. package/dist/web/standalone/.next/server/app/api/projects/route.js +1 -1
  135. package/dist/web/standalone/.next/server/app/api/projects/route_client-reference-manifest.js +1 -1
  136. package/dist/web/standalone/.next/server/app/api/recovery/route.js +1 -1
  137. package/dist/web/standalone/.next/server/app/api/recovery/route_client-reference-manifest.js +1 -1
  138. package/dist/web/standalone/.next/server/app/api/remote-questions/route.js +5 -5
  139. package/dist/web/standalone/.next/server/app/api/remote-questions/route_client-reference-manifest.js +1 -1
  140. package/dist/web/standalone/.next/server/app/api/session/browser/route.js +1 -1
  141. package/dist/web/standalone/.next/server/app/api/session/browser/route_client-reference-manifest.js +1 -1
  142. package/dist/web/standalone/.next/server/app/api/session/command/route.js +1 -1
  143. package/dist/web/standalone/.next/server/app/api/session/command/route_client-reference-manifest.js +1 -1
  144. package/dist/web/standalone/.next/server/app/api/session/events/route.js +2 -2
  145. package/dist/web/standalone/.next/server/app/api/session/events/route_client-reference-manifest.js +1 -1
  146. package/dist/web/standalone/.next/server/app/api/session/manage/route.js +1 -1
  147. package/dist/web/standalone/.next/server/app/api/session/manage/route_client-reference-manifest.js +1 -1
  148. package/dist/web/standalone/.next/server/app/api/settings-data/route.js +1 -1
  149. package/dist/web/standalone/.next/server/app/api/settings-data/route_client-reference-manifest.js +1 -1
  150. package/dist/web/standalone/.next/server/app/api/shutdown/route.js +1 -1
  151. package/dist/web/standalone/.next/server/app/api/shutdown/route_client-reference-manifest.js +1 -1
  152. package/dist/web/standalone/.next/server/app/api/skill-health/route.js +1 -1
  153. package/dist/web/standalone/.next/server/app/api/skill-health/route_client-reference-manifest.js +1 -1
  154. package/dist/web/standalone/.next/server/app/api/steer/route.js +1 -1
  155. package/dist/web/standalone/.next/server/app/api/steer/route_client-reference-manifest.js +1 -1
  156. package/dist/web/standalone/.next/server/app/api/switch-root/route.js +1 -1
  157. package/dist/web/standalone/.next/server/app/api/switch-root/route_client-reference-manifest.js +1 -1
  158. package/dist/web/standalone/.next/server/app/api/terminal/input/route.js +2 -2
  159. package/dist/web/standalone/.next/server/app/api/terminal/input/route_client-reference-manifest.js +1 -1
  160. package/dist/web/standalone/.next/server/app/api/terminal/resize/route.js +2 -2
  161. package/dist/web/standalone/.next/server/app/api/terminal/resize/route_client-reference-manifest.js +1 -1
  162. package/dist/web/standalone/.next/server/app/api/terminal/sessions/route.js +2 -2
  163. package/dist/web/standalone/.next/server/app/api/terminal/sessions/route_client-reference-manifest.js +1 -1
  164. package/dist/web/standalone/.next/server/app/api/terminal/stream/route.js +4 -4
  165. package/dist/web/standalone/.next/server/app/api/terminal/stream/route_client-reference-manifest.js +1 -1
  166. package/dist/web/standalone/.next/server/app/api/terminal/upload/route.js +1 -1
  167. package/dist/web/standalone/.next/server/app/api/terminal/upload/route_client-reference-manifest.js +1 -1
  168. package/dist/web/standalone/.next/server/app/api/undo/route.js +1 -1
  169. package/dist/web/standalone/.next/server/app/api/undo/route_client-reference-manifest.js +1 -1
  170. package/dist/web/standalone/.next/server/app/api/update/route.js +1 -1
  171. package/dist/web/standalone/.next/server/app/api/update/route_client-reference-manifest.js +1 -1
  172. package/dist/web/standalone/.next/server/app/api/visualizer/route.js +1 -1
  173. package/dist/web/standalone/.next/server/app/api/visualizer/route_client-reference-manifest.js +1 -1
  174. package/dist/web/standalone/.next/server/app/index.html +1 -1
  175. package/dist/web/standalone/.next/server/app/index.rsc +4 -4
  176. package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +2 -2
  177. package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +4 -4
  178. package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
  179. package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +3 -3
  180. package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
  181. package/dist/web/standalone/.next/server/app/page.js +2 -2
  182. package/dist/web/standalone/.next/server/app/page_client-reference-manifest.js +1 -1
  183. package/dist/web/standalone/.next/server/app-paths-manifest.json +13 -13
  184. package/dist/web/standalone/.next/server/chunks/229.js +2 -2
  185. package/dist/web/standalone/.next/server/chunks/471.js +3 -3
  186. package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
  187. package/dist/web/standalone/.next/server/middleware-react-loadable-manifest.js +1 -1
  188. package/dist/web/standalone/.next/server/middleware.js +2 -2
  189. package/dist/web/standalone/.next/server/next-font-manifest.js +1 -1
  190. package/dist/web/standalone/.next/server/next-font-manifest.json +1 -1
  191. package/dist/web/standalone/.next/server/pages/404.html +1 -1
  192. package/dist/web/standalone/.next/server/pages/500.html +2 -2
  193. package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
  194. package/dist/web/standalone/.next/static/chunks/4024.7c75ac378de0f2b5.js +9 -0
  195. package/dist/web/standalone/.next/static/chunks/app/_not-found/{page-2f24283c162b6ab3.js → page-f2a7482d42a5614b.js} +1 -1
  196. package/dist/web/standalone/.next/static/chunks/app/{layout-9ecfd95f343793f0.js → layout-a16c7a7ecdf0c2cf.js} +1 -1
  197. package/dist/web/standalone/.next/static/chunks/app/page-6654a8cca61a3d1c.js +1 -0
  198. package/dist/web/standalone/.next/static/chunks/main-app-fdab67f7802d7832.js +1 -0
  199. package/dist/web/standalone/.next/static/chunks/next/dist/client/components/builtin/global-error-459824ffb8c323dd.js +1 -0
  200. package/dist/web/standalone/.next/static/chunks/{webpack-0a4cd455ec4197d2.js → webpack-2473ce2c3879fff4.js} +1 -1
  201. package/dist/web/standalone/node_modules/node-pty/build/Makefile +2 -2
  202. package/dist/web/standalone/node_modules/node-pty/build/Release/pty.node +0 -0
  203. package/dist/web/standalone/node_modules/node-pty/build/pty.target.mk +14 -14
  204. package/dist/web/standalone/node_modules/node-pty/node-addon-api/node_addon_api.target.mk +14 -14
  205. package/dist/web/standalone/node_modules/node-pty/node-addon-api/node_addon_api_except.target.mk +14 -14
  206. package/dist/web/standalone/node_modules/node-pty/node-addon-api/node_addon_api_maybe.target.mk +14 -14
  207. package/dist/web/standalone/server.js +1 -1
  208. package/package.json +1 -1
  209. package/packages/pi-agent-core/dist/agent-loop.d.ts.map +1 -1
  210. package/packages/pi-agent-core/dist/agent-loop.js +4 -1
  211. package/packages/pi-agent-core/dist/agent-loop.js.map +1 -1
  212. package/packages/pi-agent-core/src/agent-loop.ts +4 -1
  213. package/packages/pi-ai/dist/providers/openai-codex-responses.js +39 -10
  214. package/packages/pi-ai/dist/providers/openai-codex-responses.js.map +1 -1
  215. package/packages/pi-ai/src/providers/openai-codex-responses.ts +39 -8
  216. package/packages/pi-coding-agent/dist/core/blob-store.d.ts.map +1 -1
  217. package/packages/pi-coding-agent/dist/core/blob-store.js +8 -3
  218. package/packages/pi-coding-agent/dist/core/blob-store.js.map +1 -1
  219. package/packages/pi-coding-agent/dist/core/discovery-cache.d.ts.map +1 -1
  220. package/packages/pi-coding-agent/dist/core/discovery-cache.js +9 -2
  221. package/packages/pi-coding-agent/dist/core/discovery-cache.js.map +1 -1
  222. package/packages/pi-coding-agent/dist/core/retry-handler.js +1 -1
  223. package/packages/pi-coding-agent/dist/core/retry-handler.js.map +1 -1
  224. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  225. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js +7 -32
  226. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js.map +1 -1
  227. package/packages/pi-coding-agent/dist/modes/rpc/jsonl.d.ts.map +1 -1
  228. package/packages/pi-coding-agent/dist/modes/rpc/jsonl.js +5 -0
  229. package/packages/pi-coding-agent/dist/modes/rpc/jsonl.js.map +1 -1
  230. package/packages/pi-coding-agent/dist/modes/rpc/rpc-client.d.ts.map +1 -1
  231. package/packages/pi-coding-agent/dist/modes/rpc/rpc-client.js +0 -1
  232. package/packages/pi-coding-agent/dist/modes/rpc/rpc-client.js.map +1 -1
  233. package/packages/pi-coding-agent/dist/modes/rpc/rpc-mode.js +1 -1
  234. package/packages/pi-coding-agent/dist/modes/rpc/rpc-mode.js.map +1 -1
  235. package/packages/pi-coding-agent/package.json +1 -1
  236. package/packages/pi-coding-agent/src/core/blob-store.ts +6 -3
  237. package/packages/pi-coding-agent/src/core/discovery-cache.ts +9 -2
  238. package/packages/pi-coding-agent/src/core/retry-handler.ts +1 -1
  239. package/packages/pi-coding-agent/src/modes/interactive/interactive-mode.ts +7 -32
  240. package/packages/pi-coding-agent/src/modes/rpc/jsonl.ts +6 -0
  241. package/packages/pi-coding-agent/src/modes/rpc/rpc-client.ts +0 -2
  242. package/packages/pi-coding-agent/src/modes/rpc/rpc-mode.ts +2 -2
  243. package/pkg/package.json +1 -1
  244. package/src/resources/extensions/gsd/auto/infra-errors.ts +1 -0
  245. package/src/resources/extensions/gsd/auto/phases.ts +10 -11
  246. package/src/resources/extensions/gsd/auto/resolve.ts +3 -3
  247. package/src/resources/extensions/gsd/auto/run-unit.ts +2 -2
  248. package/src/resources/extensions/gsd/auto/session.ts +5 -0
  249. package/src/resources/extensions/gsd/auto/types.ts +13 -0
  250. package/src/resources/extensions/gsd/auto-artifact-paths.ts +19 -21
  251. package/src/resources/extensions/gsd/auto-dashboard.ts +5 -2
  252. package/src/resources/extensions/gsd/auto-dispatch.ts +39 -21
  253. package/src/resources/extensions/gsd/auto-loop.ts +1 -1
  254. package/src/resources/extensions/gsd/auto-post-unit.ts +18 -28
  255. package/src/resources/extensions/gsd/auto-prompts.ts +113 -19
  256. package/src/resources/extensions/gsd/auto-recovery.ts +65 -199
  257. package/src/resources/extensions/gsd/auto-start.ts +7 -27
  258. package/src/resources/extensions/gsd/auto-timers.ts +2 -2
  259. package/src/resources/extensions/gsd/auto-verification.ts +4 -7
  260. package/src/resources/extensions/gsd/auto-worktree.ts +305 -108
  261. package/src/resources/extensions/gsd/auto.ts +11 -10
  262. package/src/resources/extensions/gsd/bootstrap/db-tools.ts +93 -0
  263. package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +8 -0
  264. package/src/resources/extensions/gsd/branch-patterns.ts +16 -0
  265. package/src/resources/extensions/gsd/doctor-checks.ts +5 -1291
  266. package/src/resources/extensions/gsd/doctor-engine-checks.ts +182 -0
  267. package/src/resources/extensions/gsd/doctor-environment.ts +30 -7
  268. package/src/resources/extensions/gsd/doctor-git-checks.ts +415 -0
  269. package/src/resources/extensions/gsd/doctor-global-checks.ts +84 -0
  270. package/src/resources/extensions/gsd/doctor-runtime-checks.ts +626 -0
  271. package/src/resources/extensions/gsd/doctor.ts +9 -1
  272. package/src/resources/extensions/gsd/extension-manifest.json +1 -1
  273. package/src/resources/extensions/gsd/git-service.ts +7 -15
  274. package/src/resources/extensions/gsd/gsd-db.ts +150 -2
  275. package/src/resources/extensions/gsd/guided-flow-queue.ts +11 -12
  276. package/src/resources/extensions/gsd/markdown-renderer.ts +37 -4
  277. package/src/resources/extensions/gsd/preferences-types.ts +5 -1
  278. package/src/resources/extensions/gsd/preferences-validation.ts +37 -0
  279. package/src/resources/extensions/gsd/prompts/complete-milestone.md +27 -8
  280. package/src/resources/extensions/gsd/prompts/complete-slice.md +9 -8
  281. package/src/resources/extensions/gsd/prompts/execute-task.md +16 -13
  282. package/src/resources/extensions/gsd/prompts/forensics.md +12 -5
  283. package/src/resources/extensions/gsd/prompts/gate-evaluate.md +32 -0
  284. package/src/resources/extensions/gsd/prompts/guided-complete-slice.md +1 -1
  285. package/src/resources/extensions/gsd/prompts/guided-execute-task.md +1 -1
  286. package/src/resources/extensions/gsd/prompts/guided-plan-milestone.md +1 -1
  287. package/src/resources/extensions/gsd/prompts/guided-plan-slice.md +1 -1
  288. package/src/resources/extensions/gsd/prompts/plan-milestone.md +1 -1
  289. package/src/resources/extensions/gsd/prompts/plan-slice.md +8 -3
  290. package/src/resources/extensions/gsd/prompts/reassess-roadmap.md +3 -0
  291. package/src/resources/extensions/gsd/prompts/replan-slice.md +1 -1
  292. package/src/resources/extensions/gsd/repo-identity.ts +28 -0
  293. package/src/resources/extensions/gsd/roadmap-slices.ts +2 -2
  294. package/src/resources/extensions/gsd/session-forensics.ts +6 -11
  295. package/src/resources/extensions/gsd/session-lock.ts +92 -64
  296. package/src/resources/extensions/gsd/state.ts +38 -5
  297. package/src/resources/extensions/gsd/templates/milestone-summary.md +8 -0
  298. package/src/resources/extensions/gsd/templates/plan.md +16 -0
  299. package/src/resources/extensions/gsd/templates/roadmap.md +13 -0
  300. package/src/resources/extensions/gsd/templates/slice-summary.md +9 -0
  301. package/src/resources/extensions/gsd/templates/task-plan.md +24 -0
  302. package/src/resources/extensions/gsd/tests/agent-end-retry.test.ts +2 -2
  303. package/src/resources/extensions/gsd/tests/auto-loop.test.ts +35 -0
  304. package/src/resources/extensions/gsd/tests/auto-recovery.test.ts +1 -81
  305. package/src/resources/extensions/gsd/tests/complete-slice.test.ts +2 -2
  306. package/src/resources/extensions/gsd/tests/complete-task.test.ts +2 -2
  307. package/src/resources/extensions/gsd/tests/completed-units-metrics-sync.test.ts +9 -12
  308. package/src/resources/extensions/gsd/tests/doctor-environment.test.ts +115 -1
  309. package/src/resources/extensions/gsd/tests/doctor-fixlevel.test.ts +65 -1
  310. package/src/resources/extensions/gsd/tests/doctor-git.test.ts +50 -0
  311. package/src/resources/extensions/gsd/tests/gate-dispatch.test.ts +189 -0
  312. package/src/resources/extensions/gsd/tests/gate-storage.test.ts +156 -0
  313. package/src/resources/extensions/gsd/tests/git-service.test.ts +49 -0
  314. package/src/resources/extensions/gsd/tests/gsd-db.test.ts +1 -1
  315. package/src/resources/extensions/gsd/tests/infra-error.test.ts +12 -2
  316. package/src/resources/extensions/gsd/tests/journal-integration.test.ts +39 -0
  317. package/src/resources/extensions/gsd/tests/md-importer.test.ts +1 -1
  318. package/src/resources/extensions/gsd/tests/memory-store.test.ts +2 -2
  319. package/src/resources/extensions/gsd/tests/quality-gates.test.ts +347 -0
  320. package/src/resources/extensions/gsd/tests/queue-completed-milestone-perf.test.ts +155 -0
  321. package/src/resources/extensions/gsd/tests/replan-slice.test.ts +2 -1
  322. package/src/resources/extensions/gsd/tests/repo-identity-worktree.test.ts +32 -0
  323. package/src/resources/extensions/gsd/tests/roadmap-slices.test.ts +26 -0
  324. package/src/resources/extensions/gsd/tests/run-uat.test.ts +20 -16
  325. package/src/resources/extensions/gsd/tests/session-lock-transient-read.test.ts +223 -0
  326. package/src/resources/extensions/gsd/tests/skill-activation.test.ts +44 -4
  327. package/src/resources/extensions/gsd/tests/tool-naming.test.ts +1 -1
  328. package/src/resources/extensions/gsd/tests/validate-milestone.test.ts +2 -1
  329. package/src/resources/extensions/gsd/tests/verification-gate.test.ts +0 -16
  330. package/src/resources/extensions/gsd/tests/worktree-resolver.test.ts +67 -0
  331. package/src/resources/extensions/gsd/tests/worktree-sync-milestones.test.ts +1 -1
  332. package/src/resources/extensions/gsd/tests/worktree-sync-overwrite-loop.test.ts +204 -0
  333. package/src/resources/extensions/gsd/tools/plan-slice.ts +16 -0
  334. package/src/resources/extensions/gsd/tools/validate-milestone.ts +3 -3
  335. package/src/resources/extensions/gsd/types.ts +30 -0
  336. package/src/resources/extensions/gsd/verdict-parser.ts +95 -0
  337. package/src/resources/extensions/gsd/verification-gate.ts +0 -2
  338. package/src/resources/extensions/gsd/worktree-resolver.ts +31 -0
  339. package/src/resources/extensions/gsd/worktree.ts +3 -2
  340. package/src/resources/extensions/remote-questions/config.ts +3 -5
  341. package/src/resources/extensions/search-the-web/native-search.ts +8 -3
  342. package/src/resources/extensions/search-the-web/tool-search.ts +22 -2
  343. package/src/resources/skills/github-workflows/references/gh/SKILL.md +22 -1
  344. package/dist/resources/extensions/gsd/auto-worktree-sync.js +0 -191
  345. package/dist/resources/extensions/gsd/resource-version.js +0 -97
  346. package/dist/web/standalone/.next/static/chunks/4024.11ca5c01938e5948.js +0 -9
  347. package/dist/web/standalone/.next/static/chunks/app/page-12dd5ece0df4badc.js +0 -1
  348. package/dist/web/standalone/.next/static/chunks/main-app-d3d4c336195465f9.js +0 -1
  349. package/dist/web/standalone/.next/static/chunks/next/dist/client/components/builtin/global-error-ab5a8926e07ec673.js +0 -1
  350. package/src/resources/extensions/gsd/auto-worktree-sync.ts +0 -234
  351. package/src/resources/extensions/gsd/resource-version.ts +0 -101
  352. /package/dist/web/standalone/.next/static/{gj-y5hikmhS--NT8Web6M → MkE9kzqUGny3-cSE0GNnm}/_buildManifest.js +0 -0
  353. /package/dist/web/standalone/.next/static/{gj-y5hikmhS--NT8Web6M → MkE9kzqUGny3-cSE0GNnm}/_ssgManifest.js +0 -0
@@ -13,9 +13,19 @@ export function handleExtensionUIRequest(event, writeToStdin) {
13
13
  const { id, method } = event;
14
14
  let response;
15
15
  switch (method) {
16
- case 'select':
17
- response = { type: 'extension_ui_response', id, value: event.options?.[0] ?? '' };
16
+ case 'select': {
17
+ // Lock-guard prompts list "View status" first, but headless needs "Force start"
18
+ // to proceed. Detect by title and pick the force option.
19
+ const title = String(event.title ?? '');
20
+ let selected = event.options?.[0] ?? '';
21
+ if (title.includes('Auto-mode is running') && event.options) {
22
+ const forceOption = event.options.find(o => o.toLowerCase().includes('force start'));
23
+ if (forceOption)
24
+ selected = forceOption;
25
+ }
26
+ response = { type: 'extension_ui_response', id, value: selected };
18
27
  break;
28
+ }
19
29
  case 'confirm':
20
30
  response = { type: 'extension_ui_response', id, confirmed: true };
21
31
  break;
package/dist/headless.js CHANGED
@@ -37,8 +37,8 @@ export function parseHeadlessArgs(argv) {
37
37
  if (!positionalStarted && arg.startsWith('--')) {
38
38
  if (arg === '--timeout' && i + 1 < args.length) {
39
39
  options.timeout = parseInt(args[++i], 10);
40
- if (Number.isNaN(options.timeout) || options.timeout <= 0) {
41
- process.stderr.write('[headless] Error: --timeout must be a positive integer (milliseconds)\n');
40
+ if (Number.isNaN(options.timeout) || options.timeout < 0) {
41
+ process.stderr.write('[headless] Error: --timeout must be a non-negative integer (milliseconds, 0 to disable)\n');
42
42
  process.exit(1);
43
43
  }
44
44
  }
@@ -132,6 +132,13 @@ async function runHeadlessOnce(options, restartCount) {
132
132
  if (isNewMilestone && options.timeout === 300_000) {
133
133
  options.timeout = 600_000; // 10 minutes
134
134
  }
135
+ // auto-mode sessions are long-running (minutes to hours) with their own internal
136
+ // per-unit timeout via auto-supervisor. Disable the overall timeout unless the
137
+ // user explicitly set --timeout.
138
+ const isAutoMode = options.command === 'auto';
139
+ if (isAutoMode && options.timeout === 300_000) {
140
+ options.timeout = 0;
141
+ }
135
142
  // Supervised mode cannot share stdin with --context -
136
143
  if (options.supervised && options.context === '-') {
137
144
  process.stderr.write('[headless] Error: --supervised cannot be used with --context - (both require stdin)\n');
@@ -267,12 +274,14 @@ async function runHeadlessOnce(options, restartCount) {
267
274
  }
268
275
  // Precompute supervised response timeout
269
276
  const responseTimeout = options.responseTimeout ?? 30_000;
270
- // Overall timeout
271
- const timeoutTimer = setTimeout(() => {
272
- process.stderr.write(`[headless] Timeout after ${options.timeout / 1000}s\n`);
273
- exitCode = 1;
274
- resolveCompletion();
275
- }, options.timeout);
277
+ // Overall timeout (disabled when options.timeout === 0, e.g. auto-mode)
278
+ const timeoutTimer = options.timeout > 0
279
+ ? setTimeout(() => {
280
+ process.stderr.write(`[headless] Timeout after ${options.timeout / 1000}s\n`);
281
+ exitCode = 1;
282
+ resolveCompletion();
283
+ }, options.timeout)
284
+ : null;
276
285
  // Event handler
277
286
  client.onEvent((event) => {
278
287
  const eventObj = event;
@@ -354,7 +363,8 @@ async function runHeadlessOnce(options, restartCount) {
354
363
  interrupted = true;
355
364
  exitCode = 1;
356
365
  client.stop().finally(() => {
357
- clearTimeout(timeoutTimer);
366
+ if (timeoutTimer)
367
+ clearTimeout(timeoutTimer);
358
368
  if (idleTimer)
359
369
  clearTimeout(idleTimer);
360
370
  process.exit(exitCode);
@@ -368,7 +378,8 @@ async function runHeadlessOnce(options, restartCount) {
368
378
  }
369
379
  catch (err) {
370
380
  process.stderr.write(`[headless] Error: Failed to start RPC session: ${err instanceof Error ? err.message : String(err)}\n`);
371
- clearTimeout(timeoutTimer);
381
+ if (timeoutTimer)
382
+ clearTimeout(timeoutTimer);
372
383
  process.exit(1);
373
384
  }
374
385
  // Access stdin writer from the internal process
@@ -376,7 +387,8 @@ async function runHeadlessOnce(options, restartCount) {
376
387
  if (!internalProcess?.stdin) {
377
388
  process.stderr.write('[headless] Error: Cannot access child process stdin\n');
378
389
  await client.stop();
379
- clearTimeout(timeoutTimer);
390
+ if (timeoutTimer)
391
+ clearTimeout(timeoutTimer);
380
392
  process.exit(1);
381
393
  }
382
394
  stdinWriter = (data) => {
@@ -424,7 +436,10 @@ async function runHeadlessOnce(options, restartCount) {
424
436
  if (!options.json) {
425
437
  process.stderr.write('[headless] Milestone ready — chaining into auto-mode...\n');
426
438
  }
427
- // Reset completion state for the auto-mode phase
439
+ // Reset completion state for the auto-mode phase.
440
+ // Disable the overall timeout — auto-mode has its own internal supervisor.
441
+ if (timeoutTimer)
442
+ clearTimeout(timeoutTimer);
428
443
  completed = false;
429
444
  milestoneReady = false;
430
445
  blocked = false;
@@ -443,7 +458,8 @@ async function runHeadlessOnce(options, restartCount) {
443
458
  }
444
459
  }
445
460
  // Cleanup
446
- clearTimeout(timeoutTimer);
461
+ if (timeoutTimer)
462
+ clearTimeout(timeoutTimer);
447
463
  if (idleTimer)
448
464
  clearTimeout(idleTimer);
449
465
  pendingResponseTimers.forEach((timer) => clearTimeout(timer));
@@ -17,6 +17,7 @@ export const INFRA_ERROR_CODES = new Set([
17
17
  "EDQUOT", // disk quota exceeded
18
18
  "EMFILE", // too many open files (process)
19
19
  "ENFILE", // too many open files (system)
20
+ "EAGAIN", // resource temporarily unavailable (resource exhaustion)
20
21
  "ECONNREFUSED", // connection refused (offline / local server down)
21
22
  "ENOTFOUND", // DNS lookup failed (offline / no network)
22
23
  "ENETUNREACH", // network unreachable (offline / no route)
@@ -721,18 +721,18 @@ export async function runUnitPhase(ic, iterData, loopState, sidecarItem) {
721
721
  deps.updateSessionLock(deps.lockBase(), unitType, unitId, sessionFile);
722
722
  deps.writeLock(deps.lockBase(), unitType, unitId, sessionFile);
723
723
  // Tag the most recent window entry with error info for stuck detection
724
- if (unitResult.status === "error" || unitResult.status === "cancelled") {
725
- const lastEntry = loopState.recentUnits[loopState.recentUnits.length - 1];
726
- if (lastEntry) {
724
+ const lastEntry = loopState.recentUnits[loopState.recentUnits.length - 1];
725
+ if (lastEntry) {
726
+ if (unitResult.errorContext) {
727
+ lastEntry.error = `${unitResult.errorContext.category}:${unitResult.errorContext.message}`.slice(0, 200);
728
+ }
729
+ else if (unitResult.status === "error" || unitResult.status === "cancelled") {
727
730
  lastEntry.error = `${unitResult.status}:${unitType}/${unitId}`;
728
731
  }
729
- }
730
- else if (unitResult.event?.messages?.length) {
731
- const lastMsg = unitResult.event.messages[unitResult.event.messages.length - 1];
732
- const msgStr = typeof lastMsg === "string" ? lastMsg : JSON.stringify(lastMsg);
733
- if (/error|fail|exception/i.test(msgStr)) {
734
- const lastEntry = loopState.recentUnits[loopState.recentUnits.length - 1];
735
- if (lastEntry) {
732
+ else if (unitResult.event?.messages?.length) {
733
+ const lastMsg = unitResult.event.messages[unitResult.event.messages.length - 1];
734
+ const msgStr = typeof lastMsg === "string" ? lastMsg : JSON.stringify(lastMsg);
735
+ if (/error|fail|exception/i.test(msgStr)) {
736
736
  lastEntry.error = msgStr.slice(0, 200);
737
737
  }
738
738
  }
@@ -779,7 +779,7 @@ export async function runUnitPhase(ic, iterData, loopState, sidecarItem) {
779
779
  s.unitDispatchCount.delete(`${unitType}/${unitId}`);
780
780
  s.unitRecoveryCount.delete(`${unitType}/${unitId}`);
781
781
  }
782
- deps.emitJournalEvent({ ts: new Date().toISOString(), flowId: ic.flowId, seq: ic.nextSeq(), eventType: "unit-end", data: { unitType, unitId, status: unitResult.status, artifactVerified }, causedBy: { flowId: ic.flowId, seq: unitStartSeq } });
782
+ deps.emitJournalEvent({ ts: new Date().toISOString(), flowId: ic.flowId, seq: ic.nextSeq(), eventType: "unit-end", data: { unitType, unitId, status: unitResult.status, artifactVerified, ...(unitResult.errorContext ? { errorContext: unitResult.errorContext } : {}) }, causedBy: { flowId: ic.flowId, seq: unitStartSeq } });
783
783
  return { action: "next", data: { unitStartedAt: s.currentUnit.startedAt } };
784
784
  }
785
785
  // ─── runFinalize ──────────────────────────────────────────────────────────────
@@ -64,12 +64,12 @@ export function isSessionSwitchInFlight() {
64
64
  * blocks to ensure the autoLoop is never stuck awaiting a promise that
65
65
  * will never resolve. Safe to call when no resolver is pending (no-op).
66
66
  */
67
- export function resolveAgentEndCancelled() {
67
+ export function resolveAgentEndCancelled(errorContext) {
68
68
  if (_currentResolve) {
69
69
  debugLog("resolveAgentEndCancelled", { status: "resolving-cancelled" });
70
70
  const r = _currentResolve;
71
71
  _currentResolve = null;
72
- r({ status: "cancelled" });
72
+ r({ status: "cancelled", ...(errorContext ? { errorContext } : {}) });
73
73
  }
74
74
  }
75
75
  // ─── resetPendingResolve (test helper) ───────────────────────────────────────
@@ -41,13 +41,13 @@ export async function runUnit(ctx, pi, s, unitType, unitId, prompt) {
41
41
  unitId,
42
42
  error: msg,
43
43
  });
44
- return { status: "cancelled" };
44
+ return { status: "cancelled", errorContext: { message: `Session creation failed: ${msg}`, category: "session-failed", isTransient: true } };
45
45
  }
46
46
  if (sessionTimeoutHandle)
47
47
  clearTimeout(sessionTimeoutHandle);
48
48
  if (sessionResult.cancelled) {
49
49
  debugLog("runUnit-session-timeout", { unitType, unitId });
50
- return { status: "cancelled" };
50
+ return { status: "cancelled", errorContext: { message: "Session creation timed out", category: "timeout", isTransient: true } };
51
51
  }
52
52
  if (!s.active) {
53
53
  return { status: "cancelled" };
@@ -61,6 +61,9 @@ export class AutoSession {
61
61
  lastStateRebuildAt = 0;
62
62
  // ── Sidecar queue ─────────────────────────────────────────────────────
63
63
  sidecarQueue = [];
64
+ // ── Isolation degradation ────────────────────────────────────────────
65
+ /** Set to true when worktree creation fails; prevents merge of nonexistent branch. */
66
+ isolationDegraded = false;
64
67
  // ── Dispatch circuit breakers ──────────────────────────────────────
65
68
  rewriteAttemptCount = 0;
66
69
  // ── Metrics ──────────────────────────────────────────────────────────────
@@ -140,6 +143,7 @@ export class AutoSession {
140
143
  this.pendingQuickTasks = [];
141
144
  this.sidecarQueue = [];
142
145
  this.rewriteAttemptCount = 0;
146
+ this.isolationDegraded = false;
143
147
  // Signal handler
144
148
  this.sigtermHandler = null;
145
149
  // Loop promise state lives in auto-loop.ts module scope
@@ -4,14 +4,13 @@
4
4
  // auto-recovery.ts (Phase 5 dead-code cleanup). The artifact verification
5
5
  // function was removed entirely — callers now query WorkflowEngine directly.
6
6
  import { resolveMilestonePath, resolveSlicePath, relMilestoneFile, relSliceFile, buildMilestoneFileName, buildSliceFileName, buildTaskFileName, } from "./paths.js";
7
+ import { parseUnitId } from "./unit-id.js";
7
8
  import { join } from "node:path";
8
9
  /**
9
10
  * Resolve the expected artifact for a unit to an absolute path.
10
11
  */
11
12
  export function resolveExpectedArtifactPath(unitType, unitId, base) {
12
- const parts = unitId.split("/");
13
- const mid = parts[0];
14
- const sid = parts[1];
13
+ const { milestone: mid, slice: sid, task: tid } = parseUnitId(unitId);
15
14
  switch (unitType) {
16
15
  case "discuss-milestone": {
17
16
  const dir = resolveMilestonePath(base, mid);
@@ -39,10 +38,9 @@ export function resolveExpectedArtifactPath(unitType, unitId, base) {
39
38
  }
40
39
  case "run-uat": {
41
40
  const dir = resolveSlicePath(base, mid, sid);
42
- return dir ? join(dir, buildSliceFileName(sid, "UAT-RESULT")) : null;
41
+ return dir ? join(dir, buildSliceFileName(sid, "UAT")) : null;
43
42
  }
44
43
  case "execute-task": {
45
- const tid = parts[2];
46
44
  const dir = resolveSlicePath(base, mid, sid);
47
45
  return dir && tid
48
46
  ? join(dir, "tasks", buildTaskFileName(tid, "SUMMARY"))
@@ -66,6 +64,9 @@ export function resolveExpectedArtifactPath(unitType, unitId, base) {
66
64
  }
67
65
  case "rewrite-docs":
68
66
  return null;
67
+ case "gate-evaluate":
68
+ // Gate evaluate writes to DB quality_gates table — verified via state derivation
69
+ return null;
69
70
  case "reactive-execute":
70
71
  // Reactive execute produces multiple task summaries — verified separately
71
72
  return null;
@@ -74,9 +75,7 @@ export function resolveExpectedArtifactPath(unitType, unitId, base) {
74
75
  }
75
76
  }
76
77
  export function diagnoseExpectedArtifact(unitType, unitId, base) {
77
- const parts = unitId.split("/");
78
- const mid = parts[0];
79
- const sid = parts[1];
78
+ const { milestone: mid, slice: sid, task: tid } = parseUnitId(unitId);
80
79
  switch (unitType) {
81
80
  case "discuss-milestone":
82
81
  return `${relMilestoneFile(base, mid, "CONTEXT")} (milestone context from discussion)`;
@@ -89,7 +88,6 @@ export function diagnoseExpectedArtifact(unitType, unitId, base) {
89
88
  case "plan-slice":
90
89
  return `${relSliceFile(base, mid, sid, "PLAN")} (slice plan)`;
91
90
  case "execute-task": {
92
- const tid = parts[2];
93
91
  return `Task ${tid} marked [x] in ${relSliceFile(base, mid, sid, "PLAN")} + summary written`;
94
92
  }
95
93
  case "complete-slice":
@@ -101,7 +99,7 @@ export function diagnoseExpectedArtifact(unitType, unitId, base) {
101
99
  case "reassess-roadmap":
102
100
  return `${relSliceFile(base, mid, sid, "ASSESSMENT")} (roadmap reassessment)`;
103
101
  case "run-uat":
104
- return `${relSliceFile(base, mid, sid, "UAT-RESULT")} (UAT result)`;
102
+ return `${relSliceFile(base, mid, sid, "UAT")} (UAT result)`;
105
103
  case "validate-milestone":
106
104
  return `${relMilestoneFile(base, mid, "VALIDATION")} (milestone validation report)`;
107
105
  case "complete-milestone":
@@ -18,15 +18,16 @@ import { computeProgressScore } from "./progress-score.js";
18
18
  import { getActiveWorktreeName } from "./worktree-command.js";
19
19
  import { loadEffectiveGSDPreferences, getGlobalGSDPreferencesPath } from "./preferences.js";
20
20
  import { resolveServiceTierIcon, getEffectiveServiceTier } from "./service-tier.js";
21
+ import { parseUnitId } from "./unit-id.js";
21
22
  // ─── UAT Slice Extraction ─────────────────────────────────────────────────────
22
23
  /**
23
24
  * Extract the target slice ID from a run-uat unit ID (e.g. "M001/S01" → "S01").
24
25
  * Returns null if the format doesn't match.
25
26
  */
26
27
  export function extractUatSliceId(unitId) {
27
- const parts = unitId.split("/");
28
- if (parts.length >= 2 && parts[1].startsWith("S"))
29
- return parts[1];
28
+ const { slice } = parseUnitId(unitId);
29
+ if (slice?.startsWith("S"))
30
+ return slice;
30
31
  return null;
31
32
  }
32
33
  // ─── Unit Description Helpers ─────────────────────────────────────────────────
@@ -115,6 +116,8 @@ export function describeNextUnit(state) {
115
116
  return { label: `Replan ${sid}: ${sTitle}`, description: "Blocker found — replan the slice." };
116
117
  case "completing-milestone":
117
118
  return { label: "Complete milestone", description: "Write milestone summary." };
119
+ case "evaluating-gates":
120
+ return { label: `Evaluate gates for ${sid}: ${sTitle}`, description: "Parallel quality gate assessment before execution." };
118
121
  default:
119
122
  return { label: "Continue", description: "Execute the next step." };
120
123
  }
@@ -9,12 +9,13 @@
9
9
  * without modifying orchestration code.
10
10
  */
11
11
  import { loadFile, extractUatType, loadActiveOverrides } from "./files.js";
12
- import { isDbAvailable, getMilestoneSlices } from "./gsd-db.js";
12
+ import { isDbAvailable, getMilestoneSlices, getPendingGates, markAllGatesOmitted } from "./gsd-db.js";
13
+ import { extractVerdict, isAcceptableUatVerdict } from "./verdict-parser.js";
13
14
  import { resolveMilestoneFile, resolveMilestonePath, resolveSliceFile, resolveTaskFile, relSliceFile, buildMilestoneFileName, } from "./paths.js";
14
15
  import { existsSync, mkdirSync, writeFileSync } from "node:fs";
15
16
  import { join } from "node:path";
16
17
  import { hasImplementationArtifacts } from "./auto-recovery.js";
17
- import { buildDiscussMilestonePrompt, buildResearchMilestonePrompt, buildPlanMilestonePrompt, buildResearchSlicePrompt, buildPlanSlicePrompt, buildExecuteTaskPrompt, buildCompleteSlicePrompt, buildCompleteMilestonePrompt, buildValidateMilestonePrompt, buildReplanSlicePrompt, buildRunUatPrompt, buildReassessRoadmapPrompt, buildRewriteDocsPrompt, buildReactiveExecutePrompt, checkNeedsReassessment, checkNeedsRunUat, } from "./auto-prompts.js";
18
+ import { buildDiscussMilestonePrompt, buildResearchMilestonePrompt, buildPlanMilestonePrompt, buildResearchSlicePrompt, buildPlanSlicePrompt, buildExecuteTaskPrompt, buildCompleteSlicePrompt, buildCompleteMilestonePrompt, buildValidateMilestonePrompt, buildReplanSlicePrompt, buildRunUatPrompt, buildReassessRoadmapPrompt, buildRewriteDocsPrompt, buildReactiveExecutePrompt, buildGateEvaluatePrompt, checkNeedsReassessment, checkNeedsRunUat, } from "./auto-prompts.js";
18
19
  function missingSliceStop(mid, phase) {
19
20
  return {
20
21
  action: "stop",
@@ -104,30 +105,15 @@ export const DISPATCH_RULES = [
104
105
  return null;
105
106
  }
106
107
  for (const sliceId of completedSliceIds) {
107
- const resultFile = resolveSliceFile(basePath, mid, sliceId, "UAT-RESULT");
108
+ const resultFile = resolveSliceFile(basePath, mid, sliceId, "UAT");
108
109
  if (!resultFile)
109
110
  continue;
110
111
  const content = await loadFile(resultFile);
111
112
  if (!content)
112
113
  continue;
113
- const verdictMatch = content.match(/verdict:\s*([\w-]+)/i);
114
- const verdict = verdictMatch?.[1]?.toLowerCase();
115
- // Determine acceptable verdicts based on UAT type.
116
- // mixed / human-experience / live-runtime modes may legitimately
117
- // produce PARTIAL when all automatable checks pass but human-only
118
- // checks remain — this should not block progression.
119
- const acceptableVerdicts = ["pass", "passed"];
120
- const uatFile = resolveSliceFile(basePath, mid, sliceId, "UAT");
121
- if (uatFile) {
122
- const uatContent = await loadFile(uatFile);
123
- if (uatContent) {
124
- const uatType = extractUatType(uatContent);
125
- if (uatType === "mixed" || uatType === "human-experience" || uatType === "live-runtime") {
126
- acceptableVerdicts.push("partial");
127
- }
128
- }
129
- }
130
- if (verdict && !acceptableVerdicts.includes(verdict)) {
114
+ const verdict = extractVerdict(content);
115
+ const uatType = extractUatType(content);
116
+ if (verdict && !isAcceptableUatVerdict(verdict, uatType)) {
131
117
  return {
132
118
  action: "stop",
133
119
  reason: `UAT verdict for ${sliceId} is "${verdict}" — blocking progression until resolved.\nReview the UAT result and update the verdict to PASS, or re-run /gsd auto after fixing.`,
@@ -261,6 +247,32 @@ export const DISPATCH_RULES = [
261
247
  };
262
248
  },
263
249
  },
250
+ {
251
+ name: "evaluating-gates → gate-evaluate",
252
+ match: async ({ state, mid, midTitle, basePath, prefs }) => {
253
+ if (state.phase !== "evaluating-gates")
254
+ return null;
255
+ if (!state.activeSlice)
256
+ return missingSliceStop(mid, state.phase);
257
+ const sid = state.activeSlice.id;
258
+ const sTitle = state.activeSlice.title;
259
+ // Gate evaluation is opt-in via preferences
260
+ const gateConfig = prefs?.gate_evaluation;
261
+ if (!gateConfig?.enabled) {
262
+ markAllGatesOmitted(mid, sid);
263
+ return { action: "skip" };
264
+ }
265
+ const pending = getPendingGates(mid, sid, "slice");
266
+ if (pending.length === 0)
267
+ return { action: "skip" };
268
+ return {
269
+ action: "dispatch",
270
+ unitType: "gate-evaluate",
271
+ unitId: `${mid}/${sid}/gates+${pending.map(g => g.gate_id).join(",")}`,
272
+ prompt: await buildGateEvaluatePrompt(mid, midTitle, sid, sTitle, basePath),
273
+ };
274
+ },
275
+ },
264
276
  {
265
277
  name: "replanning-slice → replan-slice",
266
278
  match: async ({ state, mid, midTitle, basePath }) => {
@@ -15,11 +15,12 @@ import { loadFile, parseSummary, resolveAllOverrides } from "./files.js";
15
15
  import { loadPrompt } from "./prompt-loader.js";
16
16
  import { resolveSliceFile, resolveTaskFile, resolveMilestoneFile, resolveTasksDir, buildTaskFileName, } from "./paths.js";
17
17
  import { invalidateAllCaches } from "./cache.js";
18
+ import { parseUnitId } from "./unit-id.js";
18
19
  import { closeoutUnit } from "./auto-unit-closeout.js";
19
20
  import { autoCommitCurrentBranch, } from "./worktree.js";
20
21
  import { verifyExpectedArtifact, resolveExpectedArtifactPath, } from "./auto-recovery.js";
21
22
  import { regenerateIfMissing } from "./workflow-projections.js";
22
- import { syncStateToProjectRoot } from "./auto-worktree-sync.js";
23
+ import { syncStateToProjectRoot } from "./auto-worktree.js";
23
24
  import { isDbAvailable, getTask, getSlice, getMilestone, updateTaskStatus, _getAdapter } from "./gsd-db.js";
24
25
  import { renderPlanCheckboxes } from "./markdown-renderer.js";
25
26
  import { consumeSignal } from "./session-status-io.js";
@@ -47,13 +48,20 @@ import { _resetHasChangesCache } from "./native-git-bridge.js";
47
48
  * in postUnitPostVerification() eventually ingests rogue files, but explicit
48
49
  * detection provides immediate diagnostics so operators know the prompt failed.
49
50
  */
51
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
52
+ function hasNonEmptyFields(row, fields) {
53
+ if (!row)
54
+ return false;
55
+ return fields.some(f => String(row[f] || "").trim().length > 0);
56
+ }
57
+ const MILESTONE_PLANNING_FIELDS = ["title", "vision", "requirement_coverage", "boundary_map_markdown"];
58
+ const SLICE_PLANNING_FIELDS = ["title", "demo", "risk", "depends"];
50
59
  export function detectRogueFileWrites(unitType, unitId, basePath) {
51
60
  if (!isDbAvailable())
52
61
  return [];
53
- const parts = unitId.split("/");
62
+ const { milestone: mid, slice: sid, task: tid } = parseUnitId(unitId);
54
63
  const rogues = [];
55
64
  if (unitType === "execute-task") {
56
- const [mid, sid, tid] = parts;
57
65
  if (!mid || !sid || !tid)
58
66
  return [];
59
67
  const summaryPath = resolveTaskFile(basePath, mid, sid, tid, "SUMMARY");
@@ -65,7 +73,6 @@ export function detectRogueFileWrites(unitType, unitId, basePath) {
65
73
  }
66
74
  }
67
75
  else if (unitType === "complete-slice") {
68
- const [mid, sid] = parts;
69
76
  if (!mid || !sid)
70
77
  return [];
71
78
  const summaryPath = resolveSliceFile(basePath, mid, sid, "SUMMARY");
@@ -77,33 +84,25 @@ export function detectRogueFileWrites(unitType, unitId, basePath) {
77
84
  }
78
85
  }
79
86
  else if (unitType === "plan-milestone") {
80
- const [mid] = parts;
81
87
  if (!mid)
82
88
  return [];
83
89
  const roadmapPath = resolveMilestoneFile(basePath, mid, "ROADMAP");
84
90
  if (!roadmapPath || !existsSync(roadmapPath))
85
91
  return [];
86
92
  const dbRow = getMilestone(mid);
87
- const hasPlanningState = !!dbRow && (String(dbRow.title || "").trim().length > 0 ||
88
- String(dbRow.vision || "").trim().length > 0 ||
89
- String(dbRow.requirement_coverage || "").trim().length > 0 ||
90
- String(dbRow.boundary_map_markdown || "").trim().length > 0);
93
+ const hasPlanningState = hasNonEmptyFields(dbRow, MILESTONE_PLANNING_FIELDS);
91
94
  if (!hasPlanningState) {
92
95
  rogues.push({ path: roadmapPath, unitType, unitId });
93
96
  }
94
97
  }
95
98
  else if (unitType === "plan-slice" || unitType === "replan-slice") {
96
- const [mid, sid] = parts;
97
99
  if (!mid || !sid)
98
100
  return [];
99
101
  const planPath = resolveSliceFile(basePath, mid, sid, "PLAN");
100
102
  if (!planPath || !existsSync(planPath))
101
103
  return [];
102
104
  const dbRow = getSlice(mid, sid);
103
- const hasPlanningState = !!dbRow && (String(dbRow.title || "").trim().length > 0 ||
104
- String(dbRow.demo || "").trim().length > 0 ||
105
- String(dbRow.risk || "").trim().length > 0 ||
106
- String(dbRow.depends || "").trim().length > 0);
105
+ const hasPlanningState = hasNonEmptyFields(dbRow, SLICE_PLANNING_FIELDS);
107
106
  if (!hasPlanningState) {
108
107
  rogues.push({ path: planPath, unitType, unitId });
109
108
  }
@@ -114,7 +113,6 @@ export function detectRogueFileWrites(unitType, unitId, basePath) {
114
113
  }
115
114
  }
116
115
  else if (unitType === "reassess-roadmap") {
117
- const [mid, sid] = parts;
118
116
  if (!mid || !sid)
119
117
  return [];
120
118
  const assessPath = resolveSliceFile(basePath, mid, sid, "ASSESSMENT");
@@ -130,7 +128,6 @@ export function detectRogueFileWrites(unitType, unitId, basePath) {
130
128
  }
131
129
  }
132
130
  else if (unitType === "plan-task") {
133
- const [mid, sid, tid] = parts;
134
131
  if (!mid || !sid || !tid)
135
132
  return [];
136
133
  const taskPlanPath = resolveTaskFile(basePath, mid, sid, tid, "PLAN");
@@ -180,8 +177,7 @@ export async function postUnitPreVerification(pctx, opts) {
180
177
  try {
181
178
  let taskContext;
182
179
  if (s.currentUnit.type === "execute-task") {
183
- const parts = s.currentUnit.id.split("/");
184
- const [mid, sid, tid] = parts;
180
+ const { milestone: mid, slice: sid, task: tid } = parseUnitId(s.currentUnit.id);
185
181
  if (mid && sid && tid) {
186
182
  const summaryPath = resolveTaskFile(s.basePath, mid, sid, tid, "SUMMARY");
187
183
  if (summaryPath) {
@@ -284,8 +280,7 @@ export async function postUnitPreVerification(pctx, opts) {
284
280
  // Reactive state cleanup on slice completion
285
281
  if (s.currentUnit.type === "complete-slice") {
286
282
  try {
287
- const parts = s.currentUnit.id.split("/");
288
- const [mid, sid] = parts;
283
+ const { milestone: mid, slice: sid } = parseUnitId(s.currentUnit.id);
289
284
  if (mid && sid) {
290
285
  const { clearReactiveState } = await import("./reactive-graph.js");
291
286
  clearReactiveState(s.basePath, mid, sid);
@@ -356,8 +351,7 @@ export async function postUnitPreVerification(pctx, opts) {
356
351
  // from DB data before giving up (e.g. research-slice produces PLAN from engine).
357
352
  if (!triggerArtifactVerified) {
358
353
  try {
359
- const parts = s.currentUnit.id.split("/");
360
- const [mid, sid] = parts;
354
+ const { milestone: mid, slice: sid } = parseUnitId(s.currentUnit.id);
361
355
  if (mid && sid) {
362
356
  const regenerated = regenerateIfMissing(s.basePath, mid, sid, "PLAN");
363
357
  if (regenerated) {
@@ -444,8 +438,7 @@ export async function postUnitPostVerification(pctx) {
444
438
  ctx.ui.notify(`Hook requested retry of ${trigger.unitType} ${trigger.unitId} — resetting task state.`, "info");
445
439
  // ── State reset: undo the completion so deriveState re-derives the unit ──
446
440
  try {
447
- const parts = trigger.unitId.split("/");
448
- const [mid, sid, tid] = parts;
441
+ const { milestone: mid, slice: sid, task: tid } = parseUnitId(trigger.unitId);
449
442
  // 1. Reset task status in DB and re-render plan checkboxes
450
443
  if (mid && sid && tid) {
451
444
  try {