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
@@ -5,7 +5,8 @@
5
5
  * state, no globals — every dependency is passed as a parameter or imported as a
6
6
  * utility.
7
7
  */
8
- import { loadFile, parseContinue, parseSummary, extractUatType, loadActiveOverrides, formatOverridesSection, parseTaskPlanFile } from "./files.js";
8
+ import { loadFile, parseContinue, parseSummary, loadActiveOverrides, formatOverridesSection, parseTaskPlanFile } from "./files.js";
9
+ import { hasVerdict, getUatType } from "./verdict-parser.js";
9
10
  import { loadPrompt, inlineTemplate } from "./prompt-loader.js";
10
11
  import { resolveMilestoneFile, resolveSliceFile, resolveSlicePath, resolveTasksDir, resolveTaskFiles, resolveTaskFile, relMilestoneFile, relSliceFile, relSlicePath, relMilestonePath, resolveGsdRootFile, relGsdRootFile, resolveRuntimeFile, } from "./paths.js";
11
12
  import { resolveSkillDiscoveryMode, resolveInlineLevel, loadEffectiveGSDPreferences, resolveAllSkillReferences } from "./preferences.js";
@@ -14,6 +15,7 @@ import { getLoadedSkills } from "@gsd/pi-coding-agent";
14
15
  import { join, basename } from "node:path";
15
16
  import { existsSync } from "node:fs";
16
17
  import { computeBudgets, resolveExecutorContextWindow, truncateAtSectionBoundary } from "./context-budget.js";
18
+ import { getPendingGates } from "./gsd-db.js";
17
19
  import { formatDecisionsCompact, formatRequirementsCompact } from "./structured-data-formatter.js";
18
20
  // ─── Preamble Cap ─────────────────────────────────────────────────────────────
19
21
  const MAX_PREAMBLE_CHARS = 30_000;
@@ -354,10 +356,17 @@ function resolvePreferredSkillNames(prefs, visibleSkills, contextTokens, base) {
354
356
  .filter(skill => preferred.has(normalizeSkillReference(skill.name)) && skillMatchesContext(skill, contextTokens))
355
357
  .map(skill => normalizeSkillReference(skill.name));
356
358
  }
359
+ /** Skill names must be lowercase alphanumeric with hyphens — reject anything else
360
+ * to prevent prompt injection via crafted directory names. */
361
+ const SAFE_SKILL_NAME = /^[a-z0-9][a-z0-9-]*$/;
357
362
  function formatSkillActivationBlock(skillNames) {
358
- if (skillNames.length === 0)
363
+ const safe = skillNames.filter(name => SAFE_SKILL_NAME.test(name));
364
+ if (safe.length === 0)
359
365
  return "";
360
- const calls = skillNames.map(name => `Call Skill('${name}')`).join('. ');
366
+ // Use explicit parameter syntax so LLMs pass { skill: "..." } instead of { name: "..." }.
367
+ // The function-call-like syntax `Skill('name')` led LLMs to infer a positional
368
+ // parameter name, causing tool validation failures — see #2224.
369
+ const calls = safe.map(name => `Call Skill({ skill: '${name}' })`).join('. ');
361
370
  return `<skill_activation>${calls}.</skill_activation>`;
362
371
  }
363
372
  export function buildSkillActivationBlock(params) {
@@ -663,13 +672,10 @@ export async function checkNeedsRunUat(base, mid, state, prefs) {
663
672
  const uatContent = await loadFile(uatFile);
664
673
  if (!uatContent)
665
674
  return null;
666
- const uatResultFile = resolveSliceFile(base, mid, sid, "UAT-RESULT");
667
- if (uatResultFile) {
668
- const hasResult = !!(await loadFile(uatResultFile));
669
- if (hasResult)
670
- return null;
671
- }
672
- const uatType = extractUatType(uatContent) ?? "artifact-driven";
675
+ // If the UAT file already contains a verdict, UAT has been run — skip
676
+ if (hasVerdict(uatContent))
677
+ return null;
678
+ const uatType = getUatType(uatContent);
673
679
  return { sliceId: sid, uatType };
674
680
  }
675
681
  }
@@ -697,13 +703,10 @@ export async function checkNeedsRunUat(base, mid, state, prefs) {
697
703
  const uatContentFb = await loadFile(uatFileFb);
698
704
  if (!uatContentFb)
699
705
  return null;
700
- const uatResultFb = resolveSliceFile(base, mid, uatSid, "UAT-RESULT");
701
- if (uatResultFb) {
702
- const hasResultFb = !!(await loadFile(uatResultFb));
703
- if (hasResultFb)
704
- return null;
705
- }
706
- const uatTypeFb = extractUatType(uatContentFb) ?? "artifact-driven";
706
+ // If the UAT file already contains a verdict, UAT has been run — skip
707
+ if (hasVerdict(uatContentFb))
708
+ return null;
709
+ const uatTypeFb = getUatType(uatContentFb);
707
710
  return { sliceId: uatSid, uatType: uatTypeFb };
708
711
  }
709
712
  // ─── Prompt Builders ──────────────────────────────────────────────────────
@@ -1194,8 +1197,8 @@ export async function buildValidateMilestonePrompt(mid, midTitle, base, level) {
1194
1197
  const summaryPath = resolveSliceFile(base, mid, sid, "SUMMARY");
1195
1198
  const summaryRel = relSliceFile(base, mid, sid, "SUMMARY");
1196
1199
  inlined.push(await inlineFile(summaryPath, summaryRel, `${sid} Summary`));
1197
- const uatPath = resolveSliceFile(base, mid, sid, "UAT-RESULT");
1198
- const uatRel = relSliceFile(base, mid, sid, "UAT-RESULT");
1200
+ const uatPath = resolveSliceFile(base, mid, sid, "UAT");
1201
+ const uatRel = relSliceFile(base, mid, sid, "UAT");
1199
1202
  const uatInline = await inlineFileOptional(uatPath, uatRel, `${sid} UAT Result`);
1200
1203
  if (uatInline)
1201
1204
  inlined.push(uatInline);
@@ -1334,8 +1337,8 @@ export async function buildRunUatPrompt(mid, sliceId, uatPath, uatContent, base)
1334
1337
  if (projectInline)
1335
1338
  inlined.push(projectInline);
1336
1339
  const inlinedContext = capPreamble(`## Inlined Context (preloaded — do not re-read these files)\n\n${inlined.join("\n\n---\n\n")}`);
1337
- const uatResultPath = join(base, relSliceFile(base, mid, sliceId, "UAT-RESULT"));
1338
- const uatType = extractUatType(uatContent) ?? "artifact-driven";
1340
+ const uatResultPath = join(base, relSliceFile(base, mid, sliceId, "UAT"));
1341
+ const uatType = getUatType(uatContent);
1339
1342
  return loadPrompt("run-uat", {
1340
1343
  workingDirectory: base,
1341
1344
  milestoneId: mid,
@@ -1465,6 +1468,84 @@ export async function buildReactiveExecutePrompt(mid, midTitle, sid, sTitle, rea
1465
1468
  inlinedTemplates,
1466
1469
  });
1467
1470
  }
1471
+ // ─── Gate Evaluation ──────────────────────────────────────────────────────
1472
+ const GATE_QUESTIONS = {
1473
+ Q3: {
1474
+ question: "How can this be exploited?",
1475
+ guidance: [
1476
+ "Identify abuse scenarios: parameter tampering, replay attacks, privilege escalation.",
1477
+ "Map data exposure risks: PII, tokens, secrets accessible through this slice.",
1478
+ "Define input trust boundaries: untrusted user input reaching DB, API, or filesystem.",
1479
+ "If none apply, return verdict 'omitted' with rationale explaining why.",
1480
+ ].join("\n"),
1481
+ },
1482
+ Q4: {
1483
+ question: "What existing promises does this break?",
1484
+ guidance: [
1485
+ "List which existing requirements (R001, R003, etc.) are touched by this slice.",
1486
+ "Identify what must be re-tested after shipping.",
1487
+ "Flag decisions that should be revisited given the new scope.",
1488
+ "If no existing requirements are affected, return verdict 'omitted'.",
1489
+ ].join("\n"),
1490
+ },
1491
+ };
1492
+ export async function buildGateEvaluatePrompt(mid, midTitle, sid, sTitle, base) {
1493
+ const pending = getPendingGates(mid, sid, "slice");
1494
+ // Load the slice plan for context
1495
+ const planFile = resolveSliceFile(base, mid, sid, "PLAN");
1496
+ const planContent = planFile ? (await loadFile(planFile)) ?? "(plan file empty)" : "(plan file not found)";
1497
+ // Build per-gate subagent prompts
1498
+ const subagentSections = [];
1499
+ const gateListLines = [];
1500
+ for (const gate of pending) {
1501
+ const meta = GATE_QUESTIONS[gate.gate_id];
1502
+ if (!meta)
1503
+ continue;
1504
+ gateListLines.push(`- **${gate.gate_id}**: ${meta.question}`);
1505
+ const subPrompt = [
1506
+ `You are evaluating quality gate **${gate.gate_id}** for slice ${sid} (${sTitle}).`,
1507
+ "",
1508
+ `## Question: ${meta.question}`,
1509
+ "",
1510
+ meta.guidance,
1511
+ "",
1512
+ "## Slice Plan",
1513
+ "",
1514
+ planContent,
1515
+ "",
1516
+ "## Instructions",
1517
+ "",
1518
+ "Analyze the slice plan above and answer the gate question.",
1519
+ `Call the \`gsd_save_gate_result\` tool with:`,
1520
+ `- \`milestoneId\`: "${mid}"`,
1521
+ `- \`sliceId\`: "${sid}"`,
1522
+ `- \`gateId\`: "${gate.gate_id}"`,
1523
+ "- `verdict`: \"pass\" (no concerns), \"flag\" (concerns found), or \"omitted\" (not applicable)",
1524
+ "- `rationale`: one-sentence justification",
1525
+ "- `findings`: detailed markdown findings (or empty if omitted)",
1526
+ ].join("\n");
1527
+ subagentSections.push([
1528
+ `### ${gate.gate_id}: ${meta.question}`,
1529
+ "",
1530
+ "Use this as the prompt for a `subagent` call:",
1531
+ "",
1532
+ "```",
1533
+ subPrompt,
1534
+ "```",
1535
+ ].join("\n"));
1536
+ }
1537
+ return loadPrompt("gate-evaluate", {
1538
+ workingDirectory: base,
1539
+ milestoneId: mid,
1540
+ milestoneTitle: midTitle,
1541
+ sliceId: sid,
1542
+ sliceTitle: sTitle,
1543
+ slicePlanContent: planContent,
1544
+ gateCount: String(pending.length),
1545
+ gateList: gateListLines.join("\n"),
1546
+ subagentPrompts: subagentSections.join("\n\n---\n\n"),
1547
+ });
1548
+ }
1468
1549
  export async function buildRewriteDocsPrompt(mid, midTitle, activeSlice, base, overrides) {
1469
1550
  const sid = activeSlice?.id;
1470
1551
  const sTitle = activeSlice?.title ?? "";
@@ -6,85 +6,19 @@
6
6
  * Pure functions that receive all needed state as parameters — no module-level
7
7
  * globals or AutoContext dependency.
8
8
  */
9
- import { clearUnitRuntimeRecord } from "./unit-runtime.js";
10
9
  import { clearParseCache } from "./files.js";
11
10
  import { parseRoadmap as parseLegacyRoadmap, parsePlan as parseLegacyPlan } from "./parsers-legacy.js";
12
11
  import { isDbAvailable, getTask, getSlice, getSliceTasks } from "./gsd-db.js";
13
12
  import { isValidationTerminal } from "./state.js";
14
13
  import { nativeConflictFiles, nativeCommit, nativeCheckoutTheirs, nativeAddPaths, nativeMergeAbort, nativeResetHard, } from "./native-git-bridge.js";
15
- import { resolveMilestonePath, resolveSlicePath, resolveSliceFile, resolveTasksDir, resolveTaskFiles, relMilestoneFile, relSliceFile, buildMilestoneFileName, buildSliceFileName, buildTaskFileName, resolveMilestoneFile, clearPathCache, resolveGsdRootFile, } from "./paths.js";
14
+ import { resolveSlicePath, resolveSliceFile, resolveTasksDir, resolveTaskFiles, relMilestoneFile, relSliceFile, buildSliceFileName, resolveMilestoneFile, clearPathCache, resolveGsdRootFile, } from "./paths.js";
16
15
  import { existsSync, mkdirSync, readFileSync, writeFileSync, unlinkSync, } from "node:fs";
17
16
  import { execFileSync } from "node:child_process";
18
17
  import { dirname, join } from "node:path";
18
+ import { resolveExpectedArtifactPath, diagnoseExpectedArtifact, } from "./auto-artifact-paths.js";
19
+ // Re-export so existing consumers of auto-recovery.ts keep working.
20
+ export { resolveExpectedArtifactPath, diagnoseExpectedArtifact };
19
21
  // ─── Artifact Resolution & Verification ───────────────────────────────────────
20
- /**
21
- * Resolve the expected artifact for a unit to an absolute path.
22
- */
23
- export function resolveExpectedArtifactPath(unitType, unitId, base) {
24
- const parts = unitId.split("/");
25
- const mid = parts[0];
26
- const sid = parts[1];
27
- switch (unitType) {
28
- case "discuss-milestone": {
29
- const dir = resolveMilestonePath(base, mid);
30
- return dir ? join(dir, buildMilestoneFileName(mid, "CONTEXT")) : null;
31
- }
32
- case "research-milestone": {
33
- const dir = resolveMilestonePath(base, mid);
34
- return dir ? join(dir, buildMilestoneFileName(mid, "RESEARCH")) : null;
35
- }
36
- case "plan-milestone": {
37
- const dir = resolveMilestonePath(base, mid);
38
- return dir ? join(dir, buildMilestoneFileName(mid, "ROADMAP")) : null;
39
- }
40
- case "research-slice": {
41
- const dir = resolveSlicePath(base, mid, sid);
42
- return dir ? join(dir, buildSliceFileName(sid, "RESEARCH")) : null;
43
- }
44
- case "plan-slice": {
45
- const dir = resolveSlicePath(base, mid, sid);
46
- return dir ? join(dir, buildSliceFileName(sid, "PLAN")) : null;
47
- }
48
- case "reassess-roadmap": {
49
- const dir = resolveSlicePath(base, mid, sid);
50
- return dir ? join(dir, buildSliceFileName(sid, "ASSESSMENT")) : null;
51
- }
52
- case "run-uat": {
53
- const dir = resolveSlicePath(base, mid, sid);
54
- return dir ? join(dir, buildSliceFileName(sid, "UAT-RESULT")) : null;
55
- }
56
- case "execute-task": {
57
- const tid = parts[2];
58
- const dir = resolveSlicePath(base, mid, sid);
59
- return dir && tid
60
- ? join(dir, "tasks", buildTaskFileName(tid, "SUMMARY"))
61
- : null;
62
- }
63
- case "complete-slice": {
64
- const dir = resolveSlicePath(base, mid, sid);
65
- return dir ? join(dir, buildSliceFileName(sid, "SUMMARY")) : null;
66
- }
67
- case "validate-milestone": {
68
- const dir = resolveMilestonePath(base, mid);
69
- return dir ? join(dir, buildMilestoneFileName(mid, "VALIDATION")) : null;
70
- }
71
- case "complete-milestone": {
72
- const dir = resolveMilestonePath(base, mid);
73
- return dir ? join(dir, buildMilestoneFileName(mid, "SUMMARY")) : null;
74
- }
75
- case "replan-slice": {
76
- const dir = resolveSlicePath(base, mid, sid);
77
- return dir ? join(dir, buildSliceFileName(sid, "REPLAN")) : null;
78
- }
79
- case "rewrite-docs":
80
- return null;
81
- case "reactive-execute":
82
- // Reactive execute produces multiple task summaries — verified separately
83
- return null;
84
- default:
85
- return null;
86
- }
87
- }
88
22
  /**
89
23
  * Check whether a milestone produced implementation artifacts (non-`.gsd/` files)
90
24
  * in the git history. Uses `git log --name-only` to inspect all commits on the
@@ -244,6 +178,36 @@ export function verifyExpectedArtifact(unitType, unitId, base) {
244
178
  }
245
179
  return true;
246
180
  }
181
+ // Gate-evaluate: verify that each dispatched gate has been resolved in the DB.
182
+ // The unitId encodes the batch: "{mid}/{sid}/gates+Q3,Q4"
183
+ if (unitType === "gate-evaluate") {
184
+ const parts = unitId.split("/");
185
+ const mid = parts[0];
186
+ const sid = parts[1];
187
+ const batchPart = parts[2]; // "gates+Q3,Q4"
188
+ if (!mid || !sid || !batchPart)
189
+ return false;
190
+ const plusIdx = batchPart.indexOf("+");
191
+ if (plusIdx === -1)
192
+ return true; // no specific gates encoded — pass
193
+ const gateIds = batchPart.slice(plusIdx + 1).split(",").filter(Boolean);
194
+ if (gateIds.length === 0)
195
+ return true;
196
+ try {
197
+ const { getPendingGates: getPending } = require("./gsd-db.js");
198
+ const pending = getPending(mid, sid, "slice");
199
+ const pendingIds = new Set(pending.map((g) => g.gate_id));
200
+ // All dispatched gates must no longer be pending
201
+ for (const gid of gateIds) {
202
+ if (pendingIds.has(gid))
203
+ return false;
204
+ }
205
+ }
206
+ catch {
207
+ // DB unavailable — treat as verified to avoid blocking
208
+ }
209
+ return true;
210
+ }
247
211
  const absPath = resolveExpectedArtifactPath(unitType, unitId, base);
248
212
  // For unit types with no verifiable artifact (null path), the parent directory
249
213
  // is missing on disk — treat as stale completion state so the key gets evicted (#313).
@@ -415,44 +379,35 @@ export function writeBlockerPlaceholder(unitType, unitId, base, reason) {
415
379
  writeFileSync(absPath, content, "utf-8");
416
380
  return diagnoseExpectedArtifact(unitType, unitId, base);
417
381
  }
418
- export function diagnoseExpectedArtifact(unitType, unitId, base) {
419
- const parts = unitId.split("/");
420
- const mid = parts[0];
421
- const sid = parts[1];
422
- switch (unitType) {
423
- case "discuss-milestone":
424
- return `${relMilestoneFile(base, mid, "CONTEXT")} (milestone context from discussion)`;
425
- case "research-milestone":
426
- return `${relMilestoneFile(base, mid, "RESEARCH")} (milestone research)`;
427
- case "plan-milestone":
428
- return `${relMilestoneFile(base, mid, "ROADMAP")} (milestone roadmap)`;
429
- case "research-slice":
430
- return `${relSliceFile(base, mid, sid, "RESEARCH")} (slice research)`;
431
- case "plan-slice":
432
- return `${relSliceFile(base, mid, sid, "PLAN")} (slice plan)`;
433
- case "execute-task": {
434
- const tid = parts[2];
435
- return `Task ${tid} marked [x] in ${relSliceFile(base, mid, sid, "PLAN")} + summary written`;
382
+ // ─── Merge State Reconciliation ───────────────────────────────────────────────
383
+ /**
384
+ * Best-effort abort of a pending merge/squash and hard-reset to HEAD.
385
+ * Handles both real merges (MERGE_HEAD) and squash merges (SQUASH_MSG).
386
+ */
387
+ function abortAndResetMerge(basePath, hasMergeHead, squashMsgPath) {
388
+ if (hasMergeHead) {
389
+ try {
390
+ nativeMergeAbort(basePath);
391
+ }
392
+ catch {
393
+ /* best-effort */
394
+ }
395
+ }
396
+ else if (squashMsgPath) {
397
+ try {
398
+ unlinkSync(squashMsgPath);
399
+ }
400
+ catch {
401
+ /* best-effort */
436
402
  }
437
- case "complete-slice":
438
- return `Slice ${sid} marked [x] in ${relMilestoneFile(base, mid, "ROADMAP")} + summary + UAT written`;
439
- case "replan-slice":
440
- return `${relSliceFile(base, mid, sid, "REPLAN")} + updated ${relSliceFile(base, mid, sid, "PLAN")}`;
441
- case "rewrite-docs":
442
- return "Active overrides resolved in .gsd/OVERRIDES.md + plan documents updated";
443
- case "reassess-roadmap":
444
- return `${relSliceFile(base, mid, sid, "ASSESSMENT")} (roadmap reassessment)`;
445
- case "run-uat":
446
- return `${relSliceFile(base, mid, sid, "UAT-RESULT")} (UAT result)`;
447
- case "validate-milestone":
448
- return `${relMilestoneFile(base, mid, "VALIDATION")} (milestone validation report)`;
449
- case "complete-milestone":
450
- return `${relMilestoneFile(base, mid, "SUMMARY")} (milestone summary)`;
451
- default:
452
- return null;
403
+ }
404
+ try {
405
+ nativeResetHard(basePath);
406
+ }
407
+ catch {
408
+ /* best-effort */
453
409
  }
454
410
  }
455
- // ─── Merge State Reconciliation ───────────────────────────────────────────────
456
411
  /**
457
412
  * Detect leftover merge state from a prior session and reconcile it.
458
413
  * If MERGE_HEAD or SQUASH_MSG exists, check whether conflicts are resolved.
@@ -503,95 +458,18 @@ export function reconcileMergeState(basePath, ctx) {
503
458
  }
504
459
  }
505
460
  if (!resolved) {
506
- if (hasMergeHead) {
507
- try {
508
- nativeMergeAbort(basePath);
509
- }
510
- catch {
511
- /* best-effort */
512
- }
513
- }
514
- else if (hasSquashMsg) {
515
- try {
516
- unlinkSync(squashMsgPath);
517
- }
518
- catch {
519
- /* best-effort */
520
- }
521
- }
522
- try {
523
- nativeResetHard(basePath);
524
- }
525
- catch {
526
- /* best-effort */
527
- }
461
+ abortAndResetMerge(basePath, hasMergeHead, squashMsgPath);
528
462
  ctx.ui.notify("Detected leftover merge state — auto-resolve failed, cleaned up. Re-deriving state.", "warning");
529
463
  }
530
464
  }
531
465
  else {
532
466
  // Code conflicts present — abort and reset
533
- if (hasMergeHead) {
534
- try {
535
- nativeMergeAbort(basePath);
536
- }
537
- catch {
538
- /* best-effort */
539
- }
540
- }
541
- else if (hasSquashMsg) {
542
- try {
543
- unlinkSync(squashMsgPath);
544
- }
545
- catch {
546
- /* best-effort */
547
- }
548
- }
549
- try {
550
- nativeResetHard(basePath);
551
- }
552
- catch {
553
- /* best-effort */
554
- }
467
+ abortAndResetMerge(basePath, hasMergeHead, squashMsgPath);
555
468
  ctx.ui.notify("Detected leftover merge state with unresolved conflicts — cleaned up. Re-deriving state.", "warning");
556
469
  }
557
470
  }
558
471
  return true;
559
472
  }
560
- // ─── Self-Heal Runtime Records ────────────────────────────────────────────────
561
- /**
562
- * Self-heal: scan runtime records in .gsd/ and clear stale ones.
563
- * Clears dispatched records older than 1 hour (process crashed before
564
- * completing the unit). deriveState() handles re-derivation — no need
565
- * for completion key persistence here.
566
- */
567
- export async function selfHealRuntimeRecords(base, ctx) {
568
- try {
569
- const { listUnitRuntimeRecords } = await import("./unit-runtime.js");
570
- const records = listUnitRuntimeRecords(base);
571
- let healed = 0;
572
- const STALE_THRESHOLD_MS = 60 * 60 * 1000; // 1 hour
573
- const now = Date.now();
574
- for (const record of records) {
575
- const { unitType, unitId } = record;
576
- // Case 0 removed — roadmap checkbox auto-fix is no longer needed.
577
- // With DB-as-truth, stale checkboxes are fixed by repairStaleRenders().
578
- // Clear stale dispatched records (dispatched > 1h ago, process crashed)
579
- const age = now - (record.startedAt ?? 0);
580
- if (record.phase === "dispatched" && age > STALE_THRESHOLD_MS) {
581
- clearUnitRuntimeRecord(base, unitType, unitId);
582
- healed++;
583
- continue;
584
- }
585
- }
586
- if (healed > 0) {
587
- ctx.ui.notify(`Self-heal: cleared ${healed} stale runtime record(s).`, "info");
588
- }
589
- }
590
- catch (e) {
591
- // Non-fatal — self-heal should never block auto-mode start
592
- void e;
593
- }
594
- }
595
473
  // ─── Loop Remediation ─────────────────────────────────────────────────────────
596
474
  /**
597
475
  * Build concrete, manual remediation steps for a loop-detected unit failure.
@@ -24,7 +24,7 @@ import { nativeInit, nativeAddAll, nativeCommit, } from "./native-git-bridge.js"
24
24
  import { GitServiceImpl } from "./git-service.js";
25
25
  import { captureIntegrationBranch, detectWorktreeName, setActiveMilestoneId, } from "./worktree.js";
26
26
  import { getAutoWorktreePath } from "./auto-worktree.js";
27
- import { readResourceVersion } from "./auto-worktree-sync.js";
27
+ import { readResourceVersion, cleanStaleRuntimeUnits } from "./auto-worktree.js";
28
28
  import { initMetrics } from "./metrics.js";
29
29
  import { initRoutingHistory } from "./routing-history.js";
30
30
  import { restoreHookState, resetHookState } from "./post-unit-hooks.js";
@@ -33,6 +33,7 @@ import { snapshotSkills } from "./skill-discovery.js";
33
33
  import { isDbAvailable, getMilestone } from "./gsd-db.js";
34
34
  import { hideFooter } from "./auto-dashboard.js";
35
35
  import { debugLog, enableDebug, isDebugEnabled, getDebugLogPath, } from "./debug-logger.js";
36
+ import { parseUnitId } from "./unit-id.js";
36
37
  import { existsSync, mkdirSync, readdirSync, statSync, unlinkSync, } from "node:fs";
37
38
  import { join } from "node:path";
38
39
  import { sep as pathSep } from "node:path";
@@ -119,7 +120,7 @@ export async function bootstrapAutoSession(s, ctx, pi, base, verboseMode, reques
119
120
  ctx.ui.notify(`Another auto-mode session (PID ${crashLock.pid}) appears to be running.\nStop it with \`kill ${crashLock.pid}\` before starting a new session.`, "error");
120
121
  return releaseLockAndReturn();
121
122
  }
122
- const recoveredMid = crashLock.unitId.split("/")[0];
123
+ const recoveredMid = parseUnitId(crashLock.unitId).milestone;
123
124
  const milestoneAlreadyComplete = recoveredMid
124
125
  ? !!resolveMilestoneFile(base, recoveredMid, "SUMMARY")
125
126
  : false;
@@ -159,35 +160,7 @@ export async function bootstrapAutoSession(s, ctx, pi, base, verboseMode, reques
159
160
  // Invalidate caches before initial state derivation
160
161
  invalidateAllCaches();
161
162
  // Clean stale runtime unit files for completed milestones (#887)
162
- try {
163
- const runtimeUnitsDir = join(gsdRoot(base), "runtime", "units");
164
- if (existsSync(runtimeUnitsDir)) {
165
- for (const file of readdirSync(runtimeUnitsDir)) {
166
- if (!file.endsWith(".json"))
167
- continue;
168
- const midMatch = file.match(/(M\d+(?:-[a-z0-9]{6})?)/);
169
- if (!midMatch)
170
- continue;
171
- const mid = midMatch[1];
172
- if (resolveMilestoneFile(base, mid, "SUMMARY")) {
173
- try {
174
- unlinkSync(join(runtimeUnitsDir, file));
175
- }
176
- catch (e) {
177
- debugLog("stale-unit-cleanup-failed", {
178
- file,
179
- error: e instanceof Error ? e.message : String(e),
180
- });
181
- }
182
- }
183
- }
184
- }
185
- }
186
- catch (e) {
187
- debugLog("stale-unit-dir-cleanup-failed", {
188
- error: e instanceof Error ? e.message : String(e),
189
- });
190
- }
163
+ cleanStaleRuntimeUnits(gsdRoot(base), (mid) => !!resolveMilestoneFile(base, mid, "SUMMARY"));
191
164
  let state = await deriveState(base);
192
165
  // Stale worktree state recovery (#654)
193
166
  if (state.activeMilestone &&
@@ -155,7 +155,7 @@ export function startUnitSupervision(sctx) {
155
155
  const message = err instanceof Error ? err.message : String(err);
156
156
  console.error(`[idle-watchdog] Unhandled error: ${message}`);
157
157
  // Unblock any pending unit promise so the auto-loop is not orphaned.
158
- resolveAgentEndCancelled();
158
+ resolveAgentEndCancelled({ message: `Idle watchdog error: ${message}`, category: "idle", isTransient: true });
159
159
  try {
160
160
  ctx.ui.notify(`Idle watchdog error: ${message}`, "warning");
161
161
  }
@@ -188,7 +188,7 @@ export function startUnitSupervision(sctx) {
188
188
  const message = err instanceof Error ? err.message : String(err);
189
189
  console.error(`[hard-timeout] Unhandled error: ${message}`);
190
190
  // Unblock any pending unit promise so the auto-loop is not orphaned.
191
- resolveAgentEndCancelled();
191
+ resolveAgentEndCancelled({ message: `Hard timeout error: ${message}`, category: "timeout", isTransient: true });
192
192
  try {
193
193
  ctx.ui.notify(`Hard timeout error: ${message}`, "warning");
194
194
  }
@@ -10,6 +10,7 @@
10
10
  * checks the result and handles control flow.
11
11
  */
12
12
  import { resolveSlicePath } from "./paths.js";
13
+ import { parseUnitId } from "./unit-id.js";
13
14
  import { isDbAvailable, getTask } from "./gsd-db.js";
14
15
  import { loadEffectiveGSDPreferences } from "./preferences.js";
15
16
  import { runVerificationGate, formatFailureContext, captureRuntimeErrors, runDependencyAudit, } from "./verification-gate.js";
@@ -34,18 +35,15 @@ export async function runPostUnitVerification(vctx, pauseAuto) {
34
35
  const effectivePrefs = loadEffectiveGSDPreferences();
35
36
  const prefs = effectivePrefs?.preferences;
36
37
  // Read task plan verify field
37
- const parts = s.currentUnit.id.split("/");
38
+ const { milestone: mid, slice: sid, task: tid } = parseUnitId(s.currentUnit.id);
38
39
  let taskPlanVerify;
39
- if (parts.length >= 3) {
40
- const [mid, sid, tid] = parts;
40
+ if (mid && sid && tid) {
41
41
  if (isDbAvailable()) {
42
42
  taskPlanVerify = getTask(mid, sid, tid)?.verify;
43
43
  }
44
44
  // When DB unavailable, taskPlanVerify stays undefined — gate runs without task-specific checks
45
45
  }
46
46
  const result = runVerificationGate({
47
- basePath: s.basePath,
48
- unitId: s.currentUnit.id,
49
47
  cwd: s.basePath,
50
48
  preferenceCommands: prefs?.verification_commands,
51
49
  taskPlanVerify,
@@ -100,9 +98,8 @@ export async function runPostUnitVerification(vctx, pauseAuto) {
100
98
  }
101
99
  // Write verification evidence JSON
102
100
  const attempt = s.verificationRetryCount.get(s.currentUnit.id) ?? 0;
103
- if (parts.length >= 3) {
101
+ if (mid && sid && tid) {
104
102
  try {
105
- const [mid, sid, tid] = parts;
106
103
  const sDir = resolveSlicePath(s.basePath, mid, sid);
107
104
  if (sDir) {
108
105
  const tasksDir = join(sDir, "tasks");