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
@@ -48,11 +48,17 @@ export function attachJsonlLineReader(stream: Readable, onLine: (line: string) =
48
48
  }
49
49
  };
50
50
 
51
+ const onError = (_err: Error) => {
52
+ // Stream errors are non-fatal for JSONL reading
53
+ };
54
+
51
55
  stream.on("data", onData);
52
56
  stream.on("end", onEnd);
57
+ stream.on("error", onError);
53
58
 
54
59
  return () => {
55
60
  stream.off("data", onData);
56
61
  stream.off("end", onEnd);
62
+ stream.off("error", onError);
57
63
  };
58
64
  }
@@ -488,8 +488,6 @@ export class RpcClient {
488
488
  const fullCommand = { ...command, id } as RpcCommand;
489
489
 
490
490
  return new Promise((resolve, reject) => {
491
- this.pendingRequests.set(id, { resolve, reject });
492
-
493
491
  const timeout = setTimeout(() => {
494
492
  this.pendingRequests.delete(id);
495
493
  reject(new Error(`Timeout waiting for response to ${command.type}. Stderr: ${this.stderr}`));
@@ -710,8 +710,8 @@ export async function runRpcMode(session: AgentSession): Promise<never> {
710
710
  }
711
711
 
712
712
  default: {
713
- const unknownCommand = command as { type: string };
714
- return error(undefined, unknownCommand.type, `Unknown command: ${unknownCommand.type}`);
713
+ const unknownCommand = command as { type: string; id?: string };
714
+ return error(unknownCommand.id, unknownCommand.type, `Unknown command: ${unknownCommand.type}`);
715
715
  }
716
716
  }
717
717
  };
package/pkg/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@glittercowboy/gsd",
3
- "version": "2.48.0",
3
+ "version": "2.49.0",
4
4
  "piConfig": {
5
5
  "name": "gsd",
6
6
  "configDir": ".gsd"
@@ -10,7 +10,8 @@ describe("commit linking", () => {
10
10
  issueNumber: 43,
11
11
  });
12
12
  assert.ok(msg.includes("Resolves #43"), "should include Resolves trailer");
13
- assert.ok(msg.startsWith("feat(S01/T02):"), "subject line unchanged");
13
+ assert.ok(msg.startsWith("feat:"), "subject line has no scope");
14
+ assert.ok(msg.includes("GSD-Task: S01/T02"), "GSD-Task trailer present");
14
15
  });
15
16
 
16
17
  it("includes both key files and Resolves #N", () => {
@@ -22,10 +23,13 @@ describe("commit linking", () => {
22
23
  });
23
24
  assert.ok(msg.includes("- src/auth.ts"), "key files present");
24
25
  assert.ok(msg.includes("Resolves #43"), "Resolves trailer present");
25
- // Resolves should come after key files
26
+ assert.ok(msg.includes("GSD-Task: S01/T02"), "GSD-Task trailer present");
27
+ // GSD-Task should come after key files but before Resolves
26
28
  const keyFilesIdx = msg.indexOf("- src/auth.ts");
29
+ const taskIdx = msg.indexOf("GSD-Task: S01/T02");
27
30
  const resolvesIdx = msg.indexOf("Resolves #43");
28
- assert.ok(resolvesIdx > keyFilesIdx, "Resolves after key files");
31
+ assert.ok(taskIdx > keyFilesIdx, "GSD-Task after key files");
32
+ assert.ok(resolvesIdx > taskIdx, "Resolves after GSD-Task");
29
33
  });
30
34
 
31
35
  it("no Resolves trailer when issueNumber is not set", () => {
@@ -34,6 +38,6 @@ describe("commit linking", () => {
34
38
  taskTitle: "implement auth",
35
39
  });
36
40
  assert.ok(!msg.includes("Resolves"), "no Resolves when no issueNumber");
37
- assert.ok(!msg.includes("\n"), "no body when no issueNumber or keyFiles");
41
+ assert.ok(msg.includes("GSD-Task: S01/T02"), "GSD-Task trailer still present");
38
42
  });
39
43
  });
@@ -18,6 +18,7 @@ export const INFRA_ERROR_CODES: ReadonlySet<string> = new Set([
18
18
  "EDQUOT", // disk quota exceeded
19
19
  "EMFILE", // too many open files (process)
20
20
  "ENFILE", // too many open files (system)
21
+ "EAGAIN", // resource temporarily unavailable (resource exhaustion)
21
22
  "ECONNREFUSED", // connection refused (offline / local server down)
22
23
  "ENOTFOUND", // DNS lookup failed (offline / no network)
23
24
  "ENETUNREACH", // network unreachable (offline / no route)
@@ -1039,17 +1039,16 @@ export async function runUnitPhase(
1039
1039
  );
1040
1040
 
1041
1041
  // Tag the most recent window entry with error info for stuck detection
1042
- if (unitResult.status === "error" || unitResult.status === "cancelled") {
1043
- const lastEntry = loopState.recentUnits[loopState.recentUnits.length - 1];
1044
- if (lastEntry) {
1042
+ const lastEntry = loopState.recentUnits[loopState.recentUnits.length - 1];
1043
+ if (lastEntry) {
1044
+ if (unitResult.errorContext) {
1045
+ lastEntry.error = `${unitResult.errorContext.category}:${unitResult.errorContext.message}`.slice(0, 200);
1046
+ } else if (unitResult.status === "error" || unitResult.status === "cancelled") {
1045
1047
  lastEntry.error = `${unitResult.status}:${unitType}/${unitId}`;
1046
- }
1047
- } else if (unitResult.event?.messages?.length) {
1048
- const lastMsg = unitResult.event.messages[unitResult.event.messages.length - 1];
1049
- const msgStr = typeof lastMsg === "string" ? lastMsg : JSON.stringify(lastMsg);
1050
- if (/error|fail|exception/i.test(msgStr)) {
1051
- const lastEntry = loopState.recentUnits[loopState.recentUnits.length - 1];
1052
- if (lastEntry) {
1048
+ } else if (unitResult.event?.messages?.length) {
1049
+ const lastMsg = unitResult.event.messages[unitResult.event.messages.length - 1];
1050
+ const msgStr = typeof lastMsg === "string" ? lastMsg : JSON.stringify(lastMsg);
1051
+ if (/error|fail|exception/i.test(msgStr)) {
1053
1052
  lastEntry.error = msgStr.slice(0, 200);
1054
1053
  }
1055
1054
  }
@@ -1122,7 +1121,7 @@ export async function runUnitPhase(
1122
1121
  s.unitRecoveryCount.delete(`${unitType}/${unitId}`);
1123
1122
  }
1124
1123
 
1125
- 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 } });
1124
+ 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 } });
1126
1125
 
1127
1126
  return { action: "next", data: { unitStartedAt: s.currentUnit.startedAt } };
1128
1127
  }
@@ -8,7 +8,7 @@
8
8
  * Imports from: auto/types
9
9
  */
10
10
 
11
- import type { UnitResult, AgentEndEvent } from "./types.js";
11
+ import type { UnitResult, AgentEndEvent, ErrorContext } from "./types.js";
12
12
  import type { AutoSession } from "./session.js";
13
13
  import { debugLog } from "../debug-logger.js";
14
14
 
@@ -77,12 +77,12 @@ export function isSessionSwitchInFlight(): boolean {
77
77
  * blocks to ensure the autoLoop is never stuck awaiting a promise that
78
78
  * will never resolve. Safe to call when no resolver is pending (no-op).
79
79
  */
80
- export function resolveAgentEndCancelled(): void {
80
+ export function resolveAgentEndCancelled(errorContext?: ErrorContext): void {
81
81
  if (_currentResolve) {
82
82
  debugLog("resolveAgentEndCancelled", { status: "resolving-cancelled" });
83
83
  const r = _currentResolve;
84
84
  _currentResolve = null;
85
- r({ status: "cancelled" });
85
+ r({ status: "cancelled", ...(errorContext ? { errorContext } : {}) });
86
86
  }
87
87
  }
88
88
 
@@ -58,13 +58,13 @@ export async function runUnit(
58
58
  unitId,
59
59
  error: msg,
60
60
  });
61
- return { status: "cancelled" };
61
+ return { status: "cancelled", errorContext: { message: `Session creation failed: ${msg}`, category: "session-failed", isTransient: true } };
62
62
  }
63
63
  if (sessionTimeoutHandle) clearTimeout(sessionTimeoutHandle);
64
64
 
65
65
  if (sessionResult.cancelled) {
66
66
  debugLog("runUnit-session-timeout", { unitType, unitId });
67
- return { status: "cancelled" };
67
+ return { status: "cancelled", errorContext: { message: "Session creation timed out", category: "timeout", isTransient: true } };
68
68
  }
69
69
 
70
70
  if (!s.active) {
@@ -118,6 +118,10 @@ export class AutoSession {
118
118
  // ── Sidecar queue ─────────────────────────────────────────────────────
119
119
  sidecarQueue: SidecarItem[] = [];
120
120
 
121
+ // ── Isolation degradation ────────────────────────────────────────────
122
+ /** Set to true when worktree creation fails; prevents merge of nonexistent branch. */
123
+ isolationDegraded = false;
124
+
121
125
  // ── Dispatch circuit breakers ──────────────────────────────────────
122
126
  rewriteAttemptCount = 0;
123
127
 
@@ -200,6 +204,7 @@ export class AutoSession {
200
204
  this.pendingQuickTasks = [];
201
205
  this.sidecarQueue = [];
202
206
  this.rewriteAttemptCount = 0;
207
+ this.isolationDegraded = false;
203
208
 
204
209
  // Signal handler
205
210
  this.sigtermHandler = null;
@@ -47,12 +47,25 @@ export interface AgentEndEvent {
47
47
  messages: unknown[];
48
48
  }
49
49
 
50
+ /**
51
+ * Structured error context attached to a UnitResult when the unit ends
52
+ * due to an infrastructure or timeout error (not user-driven cancellation).
53
+ */
54
+ export interface ErrorContext {
55
+ message: string;
56
+ category: "provider" | "timeout" | "idle" | "network" | "aborted" | "session-failed" | "unknown";
57
+ stopReason?: string;
58
+ isTransient?: boolean;
59
+ retryAfterMs?: number;
60
+ }
61
+
50
62
  /**
51
63
  * Result of a single unit execution (one iteration of the loop).
52
64
  */
53
65
  export interface UnitResult {
54
66
  status: "completed" | "cancelled" | "error";
55
67
  event?: AgentEndEvent;
68
+ errorContext?: ErrorContext;
56
69
  }
57
70
 
58
71
  // ─── Phase pipeline types ────────────────────────────────────────────────────
@@ -13,6 +13,7 @@ import {
13
13
  buildSliceFileName,
14
14
  buildTaskFileName,
15
15
  } from "./paths.js";
16
+ import { parseUnitId } from "./unit-id.js";
16
17
  import { join } from "node:path";
17
18
 
18
19
  /**
@@ -23,9 +24,7 @@ export function resolveExpectedArtifactPath(
23
24
  unitId: string,
24
25
  base: string,
25
26
  ): string | null {
26
- const parts = unitId.split("/");
27
- const mid = parts[0]!;
28
- const sid = parts[1];
27
+ const { milestone: mid, slice: sid, task: tid } = parseUnitId(unitId);
29
28
  switch (unitType) {
30
29
  case "discuss-milestone": {
31
30
  const dir = resolveMilestonePath(base, mid);
@@ -53,10 +52,9 @@ export function resolveExpectedArtifactPath(
53
52
  }
54
53
  case "run-uat": {
55
54
  const dir = resolveSlicePath(base, mid, sid!);
56
- return dir ? join(dir, buildSliceFileName(sid!, "UAT-RESULT")) : null;
55
+ return dir ? join(dir, buildSliceFileName(sid!, "UAT")) : null;
57
56
  }
58
57
  case "execute-task": {
59
- const tid = parts[2];
60
58
  const dir = resolveSlicePath(base, mid, sid!);
61
59
  return dir && tid
62
60
  ? join(dir, "tasks", buildTaskFileName(tid, "SUMMARY"))
@@ -80,6 +78,9 @@ export function resolveExpectedArtifactPath(
80
78
  }
81
79
  case "rewrite-docs":
82
80
  return null;
81
+ case "gate-evaluate":
82
+ // Gate evaluate writes to DB quality_gates table — verified via state derivation
83
+ return null;
83
84
  case "reactive-execute":
84
85
  // Reactive execute produces multiple task summaries — verified separately
85
86
  return null;
@@ -93,38 +94,35 @@ export function diagnoseExpectedArtifact(
93
94
  unitId: string,
94
95
  base: string,
95
96
  ): string | null {
96
- const parts = unitId.split("/");
97
- const mid = parts[0];
98
- const sid = parts[1];
97
+ const { milestone: mid, slice: sid, task: tid } = parseUnitId(unitId);
99
98
  switch (unitType) {
100
99
  case "discuss-milestone":
101
- return `${relMilestoneFile(base, mid!, "CONTEXT")} (milestone context from discussion)`;
100
+ return `${relMilestoneFile(base, mid, "CONTEXT")} (milestone context from discussion)`;
102
101
  case "research-milestone":
103
- return `${relMilestoneFile(base, mid!, "RESEARCH")} (milestone research)`;
102
+ return `${relMilestoneFile(base, mid, "RESEARCH")} (milestone research)`;
104
103
  case "plan-milestone":
105
- return `${relMilestoneFile(base, mid!, "ROADMAP")} (milestone roadmap)`;
104
+ return `${relMilestoneFile(base, mid, "ROADMAP")} (milestone roadmap)`;
106
105
  case "research-slice":
107
- return `${relSliceFile(base, mid!, sid!, "RESEARCH")} (slice research)`;
106
+ return `${relSliceFile(base, mid, sid!, "RESEARCH")} (slice research)`;
108
107
  case "plan-slice":
109
- return `${relSliceFile(base, mid!, sid!, "PLAN")} (slice plan)`;
108
+ return `${relSliceFile(base, mid, sid!, "PLAN")} (slice plan)`;
110
109
  case "execute-task": {
111
- const tid = parts[2];
112
- return `Task ${tid} marked [x] in ${relSliceFile(base, mid!, sid!, "PLAN")} + summary written`;
110
+ return `Task ${tid} marked [x] in ${relSliceFile(base, mid, sid!, "PLAN")} + summary written`;
113
111
  }
114
112
  case "complete-slice":
115
- return `Slice ${sid} marked [x] in ${relMilestoneFile(base, mid!, "ROADMAP")} + summary + UAT written`;
113
+ return `Slice ${sid} marked [x] in ${relMilestoneFile(base, mid, "ROADMAP")} + summary + UAT written`;
116
114
  case "replan-slice":
117
- return `${relSliceFile(base, mid!, sid!, "REPLAN")} + updated ${relSliceFile(base, mid!, sid!, "PLAN")}`;
115
+ return `${relSliceFile(base, mid, sid!, "REPLAN")} + updated ${relSliceFile(base, mid, sid!, "PLAN")}`;
118
116
  case "rewrite-docs":
119
117
  return "Active overrides resolved in .gsd/OVERRIDES.md + plan documents updated";
120
118
  case "reassess-roadmap":
121
- return `${relSliceFile(base, mid!, sid!, "ASSESSMENT")} (roadmap reassessment)`;
119
+ return `${relSliceFile(base, mid, sid!, "ASSESSMENT")} (roadmap reassessment)`;
122
120
  case "run-uat":
123
- return `${relSliceFile(base, mid!, sid!, "UAT-RESULT")} (UAT result)`;
121
+ return `${relSliceFile(base, mid, sid!, "UAT")} (UAT result)`;
124
122
  case "validate-milestone":
125
- return `${relMilestoneFile(base, mid!, "VALIDATION")} (milestone validation report)`;
123
+ return `${relMilestoneFile(base, mid, "VALIDATION")} (milestone validation report)`;
126
124
  case "complete-milestone":
127
- return `${relMilestoneFile(base, mid!, "SUMMARY")} (milestone summary)`;
125
+ return `${relMilestoneFile(base, mid, "SUMMARY")} (milestone summary)`;
128
126
  default:
129
127
  return null;
130
128
  }
@@ -25,6 +25,7 @@ import { computeProgressScore } from "./progress-score.js";
25
25
  import { getActiveWorktreeName } from "./worktree-command.js";
26
26
  import { loadEffectiveGSDPreferences, getGlobalGSDPreferencesPath } from "./preferences.js";
27
27
  import { resolveServiceTierIcon, getEffectiveServiceTier } from "./service-tier.js";
28
+ import { parseUnitId } from "./unit-id.js";
28
29
 
29
30
  // ─── UAT Slice Extraction ─────────────────────────────────────────────────────
30
31
 
@@ -33,8 +34,8 @@ import { resolveServiceTierIcon, getEffectiveServiceTier } from "./service-tier.
33
34
  * Returns null if the format doesn't match.
34
35
  */
35
36
  export function extractUatSliceId(unitId: string): string | null {
36
- const parts = unitId.split("/");
37
- if (parts.length >= 2 && parts[1]!.startsWith("S")) return parts[1]!;
37
+ const { slice } = parseUnitId(unitId);
38
+ if (slice?.startsWith("S")) return slice;
38
39
  return null;
39
40
  }
40
41
 
@@ -151,6 +152,8 @@ export function describeNextUnit(state: GSDState): { label: string; description:
151
152
  return { label: `Replan ${sid}: ${sTitle}`, description: "Blocker found — replan the slice." };
152
153
  case "completing-milestone":
153
154
  return { label: "Complete milestone", description: "Write milestone summary." };
155
+ case "evaluating-gates":
156
+ return { label: `Evaluate gates for ${sid}: ${sTitle}`, description: "Parallel quality gate assessment before execution." };
154
157
  default:
155
158
  return { label: "Continue", description: "Execute the next step." };
156
159
  }
@@ -13,7 +13,8 @@ import type { GSDState } from "./types.js";
13
13
  import type { GSDPreferences } from "./preferences.js";
14
14
  import type { UatType } from "./files.js";
15
15
  import { loadFile, extractUatType, loadActiveOverrides } from "./files.js";
16
- import { isDbAvailable, getMilestoneSlices } from "./gsd-db.js";
16
+ import { isDbAvailable, getMilestoneSlices, getPendingGates, markAllGatesOmitted } from "./gsd-db.js";
17
+ import { extractVerdict, isAcceptableUatVerdict } from "./verdict-parser.js";
17
18
 
18
19
  import {
19
20
  resolveMilestoneFile,
@@ -43,6 +44,7 @@ import {
43
44
  buildReassessRoadmapPrompt,
44
45
  buildRewriteDocsPrompt,
45
46
  buildReactiveExecutePrompt,
47
+ buildGateEvaluatePrompt,
46
48
  checkNeedsReassessment,
47
49
  checkNeedsRunUat,
48
50
  } from "./auto-prompts.js";
@@ -184,13 +186,14 @@ export const DISPATCH_RULES: DispatchRule[] = [
184
186
  }
185
187
 
186
188
  for (const sliceId of completedSliceIds) {
187
- const resultFile = resolveSliceFile(basePath, mid, sliceId, "UAT-RESULT");
189
+ const resultFile = resolveSliceFile(basePath, mid, sliceId, "UAT");
188
190
  if (!resultFile) continue;
189
191
  const content = await loadFile(resultFile);
190
192
  if (!content) continue;
191
- const verdictMatch = content.match(/verdict:\s*([\w-]+)/i);
192
- const verdict = verdictMatch?.[1]?.toLowerCase();
193
- if (verdict && verdict !== "pass" && verdict !== "passed") {
193
+ const verdict = extractVerdict(content);
194
+ const uatType = extractUatType(content);
195
+
196
+ if (verdict && !isAcceptableUatVerdict(verdict, uatType)) {
194
197
  return {
195
198
  action: "stop" as const,
196
199
  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.`,
@@ -331,6 +334,38 @@ export const DISPATCH_RULES: DispatchRule[] = [
331
334
  };
332
335
  },
333
336
  },
337
+ {
338
+ name: "evaluating-gates → gate-evaluate",
339
+ match: async ({ state, mid, midTitle, basePath, prefs }) => {
340
+ if (state.phase !== "evaluating-gates") return null;
341
+ if (!state.activeSlice) return missingSliceStop(mid, state.phase);
342
+ const sid = state.activeSlice.id;
343
+ const sTitle = state.activeSlice.title;
344
+
345
+ // Gate evaluation is opt-in via preferences
346
+ const gateConfig = prefs?.gate_evaluation;
347
+ if (!gateConfig?.enabled) {
348
+ markAllGatesOmitted(mid, sid);
349
+ return { action: "skip" };
350
+ }
351
+
352
+ const pending = getPendingGates(mid, sid, "slice");
353
+ if (pending.length === 0) return { action: "skip" };
354
+
355
+ return {
356
+ action: "dispatch",
357
+ unitType: "gate-evaluate",
358
+ unitId: `${mid}/${sid}/gates+${pending.map(g => g.gate_id).join(",")}`,
359
+ prompt: await buildGateEvaluatePrompt(
360
+ mid,
361
+ midTitle,
362
+ sid,
363
+ sTitle,
364
+ basePath,
365
+ ),
366
+ };
367
+ },
368
+ },
334
369
  {
335
370
  name: "replanning-slice → replan-slice",
336
371
  match: async ({ state, mid, midTitle, basePath }) => {
@@ -13,4 +13,4 @@ export { resolveAgentEnd, resolveAgentEndCancelled, isSessionSwitchInFlight, _re
13
13
  export { detectStuck } from "./auto/detect-stuck.js";
14
14
  export { runUnit } from "./auto/run-unit.js";
15
15
  export type { LoopDeps } from "./auto/loop-deps.js";
16
- export type { AgentEndEvent, UnitResult } from "./auto/types.js";
16
+ export type { AgentEndEvent, ErrorContext, UnitResult } from "./auto/types.js";
@@ -23,6 +23,7 @@ import {
23
23
  buildTaskFileName,
24
24
  } from "./paths.js";
25
25
  import { invalidateAllCaches } from "./cache.js";
26
+ import { parseUnitId } from "./unit-id.js";
26
27
  import { closeoutUnit, type CloseoutOptions } from "./auto-unit-closeout.js";
27
28
  import {
28
29
  autoCommitCurrentBranch,
@@ -33,7 +34,7 @@ import {
33
34
  resolveExpectedArtifactPath,
34
35
  } from "./auto-recovery.js";
35
36
  import { regenerateIfMissing } from "./workflow-projections.js";
36
- import { syncStateToProjectRoot } from "./auto-worktree-sync.js";
37
+ import { syncStateToProjectRoot } from "./auto-worktree.js";
37
38
  import { isDbAvailable, getTask, getSlice, getMilestone, updateTaskStatus, _getAdapter } from "./gsd-db.js";
38
39
  import { renderPlanCheckboxes } from "./markdown-renderer.js";
39
40
  import { consumeSignal } from "./session-status-io.js";
@@ -47,6 +48,16 @@ import {
47
48
  import { hasPendingCaptures, loadPendingCaptures } from "./captures.js";
48
49
  import { debugLog } from "./debug-logger.js";
49
50
  import type { AutoSession } from "./auto/session.js";
51
+
52
+ /** Unit types that only touch `.gsd/` internal state files (no code changes).
53
+ * Auto-commit is skipped for these — their state files are picked up by the
54
+ * next actual task commit via `smartStage()`. */
55
+ const LIFECYCLE_ONLY_UNITS = new Set([
56
+ "research-milestone", "discuss-milestone", "plan-milestone",
57
+ "validate-milestone", "research-slice", "plan-slice",
58
+ "replan-slice", "complete-slice", "run-uat",
59
+ "reassess-roadmap", "rewrite-docs",
60
+ ]);
50
61
  import {
51
62
  updateProgressWidget as _updateProgressWidget,
52
63
  updateSliceProgressCache,
@@ -74,6 +85,15 @@ export interface RogueFileWrite {
74
85
  * in postUnitPostVerification() eventually ingests rogue files, but explicit
75
86
  * detection provides immediate diagnostics so operators know the prompt failed.
76
87
  */
88
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
89
+ function hasNonEmptyFields(row: Record<string, any> | null, fields: string[]): boolean {
90
+ if (!row) return false;
91
+ return fields.some(f => String(row[f] || "").trim().length > 0);
92
+ }
93
+
94
+ const MILESTONE_PLANNING_FIELDS = ["title", "vision", "requirement_coverage", "boundary_map_markdown"];
95
+ const SLICE_PLANNING_FIELDS = ["title", "demo", "risk", "depends"];
96
+
77
97
  export function detectRogueFileWrites(
78
98
  unitType: string,
79
99
  unitId: string,
@@ -81,11 +101,10 @@ export function detectRogueFileWrites(
81
101
  ): RogueFileWrite[] {
82
102
  if (!isDbAvailable()) return [];
83
103
 
84
- const parts = unitId.split("/");
104
+ const { milestone: mid, slice: sid, task: tid } = parseUnitId(unitId);
85
105
  const rogues: RogueFileWrite[] = [];
86
106
 
87
107
  if (unitType === "execute-task") {
88
- const [mid, sid, tid] = parts;
89
108
  if (!mid || !sid || !tid) return [];
90
109
 
91
110
  const summaryPath = resolveTaskFile(basePath, mid, sid, tid, "SUMMARY");
@@ -96,7 +115,6 @@ export function detectRogueFileWrites(
96
115
  rogues.push({ path: summaryPath, unitType, unitId });
97
116
  }
98
117
  } else if (unitType === "complete-slice") {
99
- const [mid, sid] = parts;
100
118
  if (!mid || !sid) return [];
101
119
 
102
120
  const summaryPath = resolveSliceFile(basePath, mid, sid, "SUMMARY");
@@ -107,37 +125,25 @@ export function detectRogueFileWrites(
107
125
  rogues.push({ path: summaryPath, unitType, unitId });
108
126
  }
109
127
  } else if (unitType === "plan-milestone") {
110
- const [mid] = parts;
111
128
  if (!mid) return [];
112
129
 
113
130
  const roadmapPath = resolveMilestoneFile(basePath, mid, "ROADMAP");
114
131
  if (!roadmapPath || !existsSync(roadmapPath)) return [];
115
132
 
116
133
  const dbRow = getMilestone(mid);
117
- const hasPlanningState = !!dbRow && (
118
- String(dbRow.title || "").trim().length > 0 ||
119
- String(dbRow.vision || "").trim().length > 0 ||
120
- String(dbRow.requirement_coverage || "").trim().length > 0 ||
121
- String(dbRow.boundary_map_markdown || "").trim().length > 0
122
- );
134
+ const hasPlanningState = hasNonEmptyFields(dbRow, MILESTONE_PLANNING_FIELDS);
123
135
 
124
136
  if (!hasPlanningState) {
125
137
  rogues.push({ path: roadmapPath, unitType, unitId });
126
138
  }
127
139
  } else if (unitType === "plan-slice" || unitType === "replan-slice") {
128
- const [mid, sid] = parts;
129
140
  if (!mid || !sid) return [];
130
141
 
131
142
  const planPath = resolveSliceFile(basePath, mid, sid, "PLAN");
132
143
  if (!planPath || !existsSync(planPath)) return [];
133
144
 
134
145
  const dbRow = getSlice(mid, sid);
135
- const hasPlanningState = !!dbRow && (
136
- String(dbRow.title || "").trim().length > 0 ||
137
- String(dbRow.demo || "").trim().length > 0 ||
138
- String(dbRow.risk || "").trim().length > 0 ||
139
- String(dbRow.depends || "").trim().length > 0
140
- );
146
+ const hasPlanningState = hasNonEmptyFields(dbRow, SLICE_PLANNING_FIELDS);
141
147
 
142
148
  if (!hasPlanningState) {
143
149
  rogues.push({ path: planPath, unitType, unitId });
@@ -149,7 +155,6 @@ export function detectRogueFileWrites(
149
155
  rogues.push({ path: replanPath, unitType, unitId });
150
156
  }
151
157
  } else if (unitType === "reassess-roadmap") {
152
- const [mid, sid] = parts;
153
158
  if (!mid || !sid) return [];
154
159
 
155
160
  const assessPath = resolveSliceFile(basePath, mid, sid, "ASSESSMENT");
@@ -166,7 +171,6 @@ export function detectRogueFileWrites(
166
171
  }
167
172
  }
168
173
  } else if (unitType === "plan-task") {
169
- const [mid, sid, tid] = parts;
170
174
  if (!mid || !sid || !tid) return [];
171
175
 
172
176
  const taskPlanPath = resolveTaskFile(basePath, mid, sid, tid, "PLAN");
@@ -239,8 +243,7 @@ export async function postUnitPreVerification(pctx: PostUnitContext, opts?: PreV
239
243
  let taskContext: TaskCommitContext | undefined;
240
244
 
241
245
  if (s.currentUnit.type === "execute-task") {
242
- const parts = s.currentUnit.id.split("/");
243
- const [mid, sid, tid] = parts;
246
+ const { milestone: mid, slice: sid, task: tid } = parseUnitId(s.currentUnit.id);
244
247
  if (mid && sid && tid) {
245
248
  const summaryPath = resolveTaskFile(s.basePath, mid, sid, tid, "SUMMARY");
246
249
  if (summaryPath) {
@@ -279,9 +282,14 @@ export async function postUnitPreVerification(pctx: PostUnitContext, opts?: PreV
279
282
  // `git worktree remove --force` during teardown.
280
283
  _resetHasChangesCache();
281
284
 
282
- const commitMsg = autoCommitCurrentBranch(s.basePath, s.currentUnit.type, s.currentUnit.id, taskContext);
283
- if (commitMsg) {
284
- ctx.ui.notify(`Committed: ${commitMsg.split("\n")[0]}`, "info");
285
+ // Skip auto-commit for lifecycle-only units (#2553) they only touch
286
+ // `.gsd/` internal state files. Those files are picked up by the next
287
+ // actual task commit via smartStage().
288
+ if (!LIFECYCLE_ONLY_UNITS.has(s.currentUnit.type)) {
289
+ const commitMsg = autoCommitCurrentBranch(s.basePath, s.currentUnit.type, s.currentUnit.id, taskContext);
290
+ if (commitMsg) {
291
+ ctx.ui.notify(`Committed: ${commitMsg.split("\n")[0]}`, "info");
292
+ }
285
293
  }
286
294
  } catch (e) {
287
295
  debugLog("postUnit", { phase: "auto-commit", error: String(e) });
@@ -339,8 +347,7 @@ export async function postUnitPreVerification(pctx: PostUnitContext, opts?: PreV
339
347
  // Reactive state cleanup on slice completion
340
348
  if (s.currentUnit.type === "complete-slice") {
341
349
  try {
342
- const parts = s.currentUnit.id.split("/");
343
- const [mid, sid] = parts;
350
+ const { milestone: mid, slice: sid } = parseUnitId(s.currentUnit.id);
344
351
  if (mid && sid) {
345
352
  const { clearReactiveState } = await import("./reactive-graph.js");
346
353
  clearReactiveState(s.basePath, mid, sid);
@@ -425,8 +432,7 @@ export async function postUnitPreVerification(pctx: PostUnitContext, opts?: PreV
425
432
  // from DB data before giving up (e.g. research-slice produces PLAN from engine).
426
433
  if (!triggerArtifactVerified) {
427
434
  try {
428
- const parts = s.currentUnit.id.split("/");
429
- const [mid, sid] = parts;
435
+ const { milestone: mid, slice: sid } = parseUnitId(s.currentUnit.id);
430
436
  if (mid && sid) {
431
437
  const regenerated = regenerateIfMissing(s.basePath, mid, sid, "PLAN");
432
438
  if (regenerated) {
@@ -526,8 +532,7 @@ export async function postUnitPostVerification(pctx: PostUnitContext): Promise<"
526
532
 
527
533
  // ── State reset: undo the completion so deriveState re-derives the unit ──
528
534
  try {
529
- const parts = trigger.unitId.split("/");
530
- const [mid, sid, tid] = parts;
535
+ const { milestone: mid, slice: sid, task: tid } = parseUnitId(trigger.unitId);
531
536
 
532
537
  // 1. Reset task status in DB and re-render plan checkboxes
533
538
  if (mid && sid && tid) {