@opengsd/gsd-pi 1.2.0-dev.b1abb545 → 1.2.0-dev.fb12b103

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 (520) hide show
  1. package/dist/cli-style.d.ts +17 -0
  2. package/dist/cli-style.js +28 -0
  3. package/dist/cli.js +1 -1
  4. package/dist/headless-events.d.ts +4 -2
  5. package/dist/headless-events.js +7 -29
  6. package/dist/models-resolver.d.ts +3 -13
  7. package/dist/models-resolver.js +3 -22
  8. package/dist/resource-loader.js +2 -14
  9. package/dist/resources/.managed-resources-content-hash +1 -1
  10. package/dist/resources/extensions/async-jobs/async-bash-tool.js +30 -64
  11. package/dist/resources/extensions/async-jobs/await-tool.js +80 -12
  12. package/dist/resources/extensions/async-jobs/index.js +65 -0
  13. package/dist/resources/extensions/async-jobs/job-manager.js +12 -1
  14. package/dist/resources/extensions/bg-shell/bg-shell-command.js +6 -6
  15. package/dist/resources/extensions/bg-shell/bg-shell-tool.js +10 -7
  16. package/dist/resources/extensions/bg-shell/overlay.js +9 -6
  17. package/dist/resources/extensions/bg-shell/process-manager.js +54 -25
  18. package/dist/resources/extensions/bg-shell/readiness-detector.js +11 -0
  19. package/dist/resources/extensions/bg-shell/utilities.js +5 -2
  20. package/dist/resources/extensions/browser-tools/engine/managed-gsd-browser.js +209 -88
  21. package/dist/resources/extensions/browser-tools/engine/selection.js +73 -5
  22. package/dist/resources/extensions/browser-tools/index.js +69 -12
  23. package/dist/resources/extensions/claude-code-cli/models.js +9 -0
  24. package/dist/resources/extensions/claude-code-cli/stream-adapter.js +38 -6
  25. package/dist/resources/extensions/gsd/auto/orchestrator.js +40 -9
  26. package/dist/resources/extensions/gsd/auto/phases.js +6 -1
  27. package/dist/resources/extensions/gsd/auto-dispatch.js +12 -1
  28. package/dist/resources/extensions/gsd/auto-model-selection.js +25 -6
  29. package/dist/resources/extensions/gsd/auto-post-unit.js +19 -8
  30. package/dist/resources/extensions/gsd/auto-prompts.js +15 -10
  31. package/dist/resources/extensions/gsd/auto-start.js +21 -21
  32. package/dist/resources/extensions/gsd/auto-tool-tracking.js +18 -0
  33. package/dist/resources/extensions/gsd/auto-unit-tool-scope.js +7 -16
  34. package/dist/resources/extensions/gsd/auto-worktree-repair.js +10 -2
  35. package/dist/resources/extensions/gsd/auto-worktree.js +35 -352
  36. package/dist/resources/extensions/gsd/auto.js +8 -20
  37. package/dist/resources/extensions/gsd/bootstrap/agent-end-recovery.js +3 -2
  38. package/dist/resources/extensions/gsd/bootstrap/dynamic-tools.js +32 -12
  39. package/dist/resources/extensions/gsd/bootstrap/register-extension.js +19 -0
  40. package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +151 -20
  41. package/dist/resources/extensions/gsd/bootstrap/write-gate.js +30 -4
  42. package/dist/resources/extensions/gsd/branch-patterns.js +2 -0
  43. package/dist/resources/extensions/gsd/browser-daemon-auto-prep.js +83 -0
  44. package/dist/resources/extensions/gsd/browser-evidence.js +8 -2
  45. package/dist/resources/extensions/gsd/captures.js +5 -15
  46. package/dist/resources/extensions/gsd/closeout-recovery.js +3 -2
  47. package/dist/resources/extensions/gsd/commands/catalog.js +6 -62
  48. package/dist/resources/extensions/gsd/constants.js +0 -2
  49. package/dist/resources/extensions/gsd/crash-recovery.js +4 -12
  50. package/dist/resources/extensions/gsd/db/engine.js +755 -0
  51. package/dist/resources/extensions/gsd/db/queries.js +372 -0
  52. package/dist/resources/extensions/gsd/db/sql-constants.js +11 -0
  53. package/dist/resources/extensions/gsd/db/writers/cascades.js +194 -0
  54. package/dist/resources/extensions/gsd/db/writers/import-restore.js +182 -0
  55. package/dist/resources/extensions/gsd/db/writers/memory.js +149 -0
  56. package/dist/resources/extensions/gsd/db/writers/reconcile.js +458 -0
  57. package/dist/resources/extensions/gsd/db/writers/status.js +70 -0
  58. package/dist/resources/extensions/gsd/doctor-environment.js +5 -11
  59. package/dist/resources/extensions/gsd/doctor-format.js +9 -6
  60. package/dist/resources/extensions/gsd/doctor-git-checks.js +4 -3
  61. package/dist/resources/extensions/gsd/doctor-runtime-checks.js +21 -16
  62. package/dist/resources/extensions/gsd/error-classifier.js +9 -0
  63. package/dist/resources/extensions/gsd/exec-sandbox.js +30 -10
  64. package/dist/resources/extensions/gsd/git-service.js +1 -0
  65. package/dist/resources/extensions/gsd/gitignore.js +3 -0
  66. package/dist/resources/extensions/gsd/gsd-db.js +171 -2048
  67. package/dist/resources/extensions/gsd/guidance.js +98 -0
  68. package/dist/resources/extensions/gsd/guided-flow.js +51 -5
  69. package/dist/resources/extensions/gsd/mcp-filter.js +2 -19
  70. package/dist/resources/extensions/gsd/mcp-tool-name.js +5 -13
  71. package/dist/resources/extensions/gsd/memory-consolidation-scanner.js +1 -1
  72. package/dist/resources/extensions/gsd/migrate/safety.js +20 -9
  73. package/dist/resources/extensions/gsd/migration-auto-check.js +24 -3
  74. package/dist/resources/extensions/gsd/model-cost-table.js +1 -0
  75. package/dist/resources/extensions/gsd/model-router.js +3 -0
  76. package/dist/resources/extensions/gsd/notification-store.js +11 -4
  77. package/dist/resources/extensions/gsd/parallel-merge.js +14 -11
  78. package/dist/resources/extensions/gsd/parallel-monitor-overlay.js +11 -7
  79. package/dist/resources/extensions/gsd/paths.js +37 -24
  80. package/dist/resources/extensions/gsd/pre-execution-checks.js +91 -3
  81. package/dist/resources/extensions/gsd/preferences-models.js +14 -48
  82. package/dist/resources/extensions/gsd/preferences.js +14 -0
  83. package/dist/resources/extensions/gsd/prompts/complete-slice.md +1 -1
  84. package/dist/resources/extensions/gsd/prompts/plan-slice.md +1 -1
  85. package/dist/resources/extensions/gsd/prompts/refine-slice.md +1 -1
  86. package/dist/resources/extensions/gsd/prompts/replan-slice.md +1 -1
  87. package/dist/resources/extensions/gsd/prompts/run-uat.md +1 -1
  88. package/dist/resources/extensions/gsd/prompts/system.md +5 -2
  89. package/dist/resources/extensions/gsd/provider-error-guidance.js +1 -5
  90. package/dist/resources/extensions/gsd/provider-switch-observer.js +1 -1
  91. package/dist/resources/extensions/gsd/publication.js +87 -0
  92. package/dist/resources/extensions/gsd/recovery-classification.js +41 -87
  93. package/dist/resources/extensions/gsd/safety/destructive-confirmation.js +108 -0
  94. package/dist/resources/extensions/gsd/safety/evidence-collector.js +37 -4
  95. package/dist/resources/extensions/gsd/safety/evidence-cross-ref.js +7 -2
  96. package/dist/resources/extensions/gsd/safety/file-change-validator.js +10 -0
  97. package/dist/resources/extensions/gsd/state-transition-matrix.js +38 -0
  98. package/dist/resources/extensions/gsd/state.js +1 -20
  99. package/dist/resources/extensions/gsd/status-guards.js +56 -8
  100. package/dist/resources/extensions/gsd/stop-notice.js +57 -0
  101. package/dist/resources/extensions/gsd/tool-surface-readiness.js +56 -0
  102. package/dist/resources/extensions/gsd/tools/complete-slice.js +24 -43
  103. package/dist/resources/extensions/gsd/tools/exec-tool.js +10 -8
  104. package/dist/resources/extensions/gsd/tools/plan-slice.js +12 -6
  105. package/dist/resources/extensions/gsd/tools/reopen-milestone.js +11 -29
  106. package/dist/resources/extensions/gsd/tools/reopen-slice.js +14 -33
  107. package/dist/resources/extensions/gsd/tools/skip-slice.js +18 -36
  108. package/dist/resources/extensions/gsd/uat-policy.js +2 -1
  109. package/dist/resources/extensions/gsd/undo.js +8 -7
  110. package/dist/resources/extensions/gsd/unit-closeout.js +138 -0
  111. package/dist/resources/extensions/gsd/unit-context-composer.js +74 -1
  112. package/dist/resources/extensions/gsd/unit-context-manifest.js +4 -27
  113. package/dist/resources/extensions/gsd/unit-registry.js +337 -0
  114. package/dist/resources/extensions/gsd/unit-tool-contracts.js +9 -182
  115. package/dist/resources/extensions/gsd/web-app-uat.js +45 -8
  116. package/dist/resources/extensions/gsd/workflow-tool-surface.js +1 -1
  117. package/dist/resources/extensions/gsd/worktree-git-recovery.js +293 -0
  118. package/dist/resources/extensions/gsd/worktree-lifecycle.js +9 -1
  119. package/dist/resources/extensions/gsd/worktree-manager.js +45 -28
  120. package/dist/resources/extensions/gsd/worktree-placement.js +59 -0
  121. package/dist/resources/extensions/gsd/worktree-reentry.js +12 -8
  122. package/dist/resources/extensions/gsd/worktree-root.js +28 -6
  123. package/dist/resources/extensions/gsd/worktree-safety.js +8 -5
  124. package/dist/resources/extensions/gsd/worktree-session-state.js +12 -11
  125. package/dist/resources/extensions/search-the-web/native-search.js +5 -3
  126. package/dist/resources/extensions/shared/browser-contract.js +59 -0
  127. package/dist/resources/extensions/shared/gsd-browser-cli.js +96 -5
  128. package/dist/resources/shared/package.json +3 -0
  129. package/dist/resources/skills/create-skill/references/executable-code.md +1 -1
  130. package/dist/resources/skills/create-skill/workflows/add-reference.md +8 -3
  131. package/dist/resources/skills/create-skill/workflows/add-script.md +4 -2
  132. package/dist/resources/skills/create-skill/workflows/add-template.md +3 -1
  133. package/dist/resources/skills/create-skill/workflows/add-workflow.md +8 -3
  134. package/dist/resources/skills/create-skill/workflows/upgrade-to-router.md +10 -5
  135. package/dist/resources/skills/create-skill/workflows/verify-skill.md +9 -4
  136. package/dist/resources/skills/gsd-browser/SKILL.md +1 -1
  137. package/dist/resources/skills/spike-wrap-up/SKILL.md +9 -9
  138. package/dist/tsconfig.extensions.tsbuildinfo +1 -1
  139. package/dist/web/standalone/.next/BUILD_ID +1 -1
  140. package/dist/web/standalone/.next/app-path-routes-manifest.json +10 -10
  141. package/dist/web/standalone/.next/build-manifest.json +3 -3
  142. package/dist/web/standalone/.next/prerender-manifest.json +3 -3
  143. package/dist/web/standalone/.next/react-loadable-manifest.json +1 -1
  144. package/dist/web/standalone/.next/server/app/_global-error.html +1 -1
  145. package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
  146. package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  147. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
  148. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
  149. package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  150. package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  151. package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  152. package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
  153. package/dist/web/standalone/.next/server/app/_not-found.rsc +1 -1
  154. package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
  155. package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  156. package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +1 -1
  157. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  158. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  159. package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
  160. package/dist/web/standalone/.next/server/app/api/boot/route.js.nft.json +1 -1
  161. package/dist/web/standalone/.next/server/app/api/bridge-terminal/input/route.js.nft.json +1 -1
  162. package/dist/web/standalone/.next/server/app/api/bridge-terminal/resize/route.js.nft.json +1 -1
  163. package/dist/web/standalone/.next/server/app/api/bridge-terminal/stream/route.js.nft.json +1 -1
  164. package/dist/web/standalone/.next/server/app/api/captures/route.js.nft.json +1 -1
  165. package/dist/web/standalone/.next/server/app/api/cleanup/route.js.nft.json +1 -1
  166. package/dist/web/standalone/.next/server/app/api/doctor/route.js.nft.json +1 -1
  167. package/dist/web/standalone/.next/server/app/api/export-data/route.js.nft.json +1 -1
  168. package/dist/web/standalone/.next/server/app/api/files/route.js.nft.json +1 -1
  169. package/dist/web/standalone/.next/server/app/api/forensics/route.js.nft.json +1 -1
  170. package/dist/web/standalone/.next/server/app/api/git/route.js.nft.json +1 -1
  171. package/dist/web/standalone/.next/server/app/api/history/route.js.nft.json +1 -1
  172. package/dist/web/standalone/.next/server/app/api/hooks/route.js.nft.json +1 -1
  173. package/dist/web/standalone/.next/server/app/api/inspect/route.js.nft.json +1 -1
  174. package/dist/web/standalone/.next/server/app/api/knowledge/route.js.nft.json +1 -1
  175. package/dist/web/standalone/.next/server/app/api/live-state/route.js.nft.json +1 -1
  176. package/dist/web/standalone/.next/server/app/api/mcp-connections/route.js.nft.json +1 -1
  177. package/dist/web/standalone/.next/server/app/api/notifications/route.js.nft.json +1 -1
  178. package/dist/web/standalone/.next/server/app/api/onboarding/route.js.nft.json +1 -1
  179. package/dist/web/standalone/.next/server/app/api/projects/route.js.nft.json +1 -1
  180. package/dist/web/standalone/.next/server/app/api/recovery/route.js.nft.json +1 -1
  181. package/dist/web/standalone/.next/server/app/api/session/browser/route.js.nft.json +1 -1
  182. package/dist/web/standalone/.next/server/app/api/session/command/route.js.nft.json +1 -1
  183. package/dist/web/standalone/.next/server/app/api/session/events/route.js.nft.json +1 -1
  184. package/dist/web/standalone/.next/server/app/api/session/manage/route.js.nft.json +1 -1
  185. package/dist/web/standalone/.next/server/app/api/settings-data/route.js.nft.json +1 -1
  186. package/dist/web/standalone/.next/server/app/api/shutdown/route.js.nft.json +1 -1
  187. package/dist/web/standalone/.next/server/app/api/skill-health/route.js.nft.json +1 -1
  188. package/dist/web/standalone/.next/server/app/api/steer/route.js.nft.json +1 -1
  189. package/dist/web/standalone/.next/server/app/api/switch-root/route.js.nft.json +1 -1
  190. package/dist/web/standalone/.next/server/app/api/terminal/sessions/route.js.nft.json +1 -1
  191. package/dist/web/standalone/.next/server/app/api/terminal/stream/route.js.nft.json +1 -1
  192. package/dist/web/standalone/.next/server/app/api/undo/route.js.nft.json +1 -1
  193. package/dist/web/standalone/.next/server/app/api/update/route.js +1 -1
  194. package/dist/web/standalone/.next/server/app/api/update/route.js.nft.json +1 -1
  195. package/dist/web/standalone/.next/server/app/api/visualizer/route.js.nft.json +1 -1
  196. package/dist/web/standalone/.next/server/app/index.html +1 -1
  197. package/dist/web/standalone/.next/server/app/index.rsc +1 -1
  198. package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +1 -1
  199. package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +1 -1
  200. package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
  201. package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +1 -1
  202. package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
  203. package/dist/web/standalone/.next/server/app-paths-manifest.json +10 -10
  204. package/dist/web/standalone/.next/server/chunks/5124.js +1 -1
  205. package/dist/web/standalone/.next/server/chunks/{5047.js → 5942.js} +2 -2
  206. package/dist/web/standalone/.next/server/chunks/8357.js +1 -1
  207. package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
  208. package/dist/web/standalone/.next/server/middleware-react-loadable-manifest.js +1 -1
  209. package/dist/web/standalone/.next/server/pages/404.html +1 -1
  210. package/dist/web/standalone/.next/server/pages/500.html +1 -1
  211. package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
  212. package/dist/web/standalone/.next/static/chunks/{796.cf859a427a2cb2ac.js → 796.e0bdc932325d7e03.js} +1 -1
  213. package/dist/web/standalone/.next/static/chunks/{webpack-fbea77b5f9953368.js → webpack-f0285ce91d4ec9ef.js} +1 -1
  214. package/dist/web/standalone/node_modules/node-pty/build/Makefile +1 -1
  215. package/dist/web/standalone/node_modules/postcss/lib/container.js +18 -26
  216. package/dist/web/standalone/node_modules/postcss/lib/css-syntax-error.js +14 -47
  217. package/dist/web/standalone/node_modules/postcss/lib/declaration.js +4 -4
  218. package/dist/web/standalone/node_modules/postcss/lib/fromJSON.js +3 -3
  219. package/dist/web/standalone/node_modules/postcss/lib/input.js +29 -54
  220. package/dist/web/standalone/node_modules/postcss/lib/lazy-result.js +37 -47
  221. package/dist/web/standalone/node_modules/postcss/lib/map-generator.js +9 -26
  222. package/dist/web/standalone/node_modules/postcss/lib/no-work-result.js +55 -57
  223. package/dist/web/standalone/node_modules/postcss/lib/node.js +31 -99
  224. package/dist/web/standalone/node_modules/postcss/lib/parse.js +1 -1
  225. package/dist/web/standalone/node_modules/postcss/lib/parser.js +9 -10
  226. package/dist/web/standalone/node_modules/postcss/lib/postcss.js +12 -12
  227. package/dist/web/standalone/node_modules/postcss/lib/previous-map.js +11 -30
  228. package/dist/web/standalone/node_modules/postcss/lib/processor.js +7 -7
  229. package/dist/web/standalone/node_modules/postcss/lib/result.js +5 -5
  230. package/dist/web/standalone/node_modules/postcss/lib/rule.js +6 -6
  231. package/dist/web/standalone/node_modules/postcss/lib/stringifier.js +28 -69
  232. package/dist/web/standalone/node_modules/postcss/lib/tokenize.js +2 -6
  233. package/dist/web/standalone/node_modules/postcss/package.json +48 -48
  234. package/dist/web/standalone/package.json +1 -1
  235. package/dist/worktree-cli.js +3 -6
  236. package/dist/worktree-status-banner.js +7 -11
  237. package/package.json +1 -1
  238. package/packages/cloud-mcp-gateway/package.json +2 -2
  239. package/packages/contracts/dist/rpc.d.ts +1 -0
  240. package/packages/contracts/dist/rpc.d.ts.map +1 -1
  241. package/packages/contracts/dist/rpc.js.map +1 -1
  242. package/packages/contracts/dist/workflow.d.ts +4 -0
  243. package/packages/contracts/dist/workflow.d.ts.map +1 -1
  244. package/packages/contracts/dist/workflow.js.map +1 -1
  245. package/packages/contracts/package.json +1 -1
  246. package/packages/daemon/package.json +4 -4
  247. package/packages/gsd-agent-core/package.json +5 -5
  248. package/packages/gsd-agent-modes/dist/modes/interactive/components/tool-execution.d.ts +5 -0
  249. package/packages/gsd-agent-modes/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
  250. package/packages/gsd-agent-modes/dist/modes/interactive/components/tool-execution.js +8 -0
  251. package/packages/gsd-agent-modes/dist/modes/interactive/components/tool-execution.js.map +1 -1
  252. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-controller.d.ts.map +1 -1
  253. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-controller.js +7 -0
  254. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-controller.js.map +1 -1
  255. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/input-controller.d.ts.map +1 -1
  256. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/input-controller.js +8 -1
  257. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/input-controller.js.map +1 -1
  258. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-chat-render.d.ts.map +1 -1
  259. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-chat-render.js +11 -1
  260. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-chat-render.js.map +1 -1
  261. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-selectors-auth.d.ts.map +1 -1
  262. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-selectors-auth.js +4 -4
  263. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-selectors-auth.js.map +1 -1
  264. package/packages/gsd-agent-modes/dist/modes/rpc/rpc-mode.d.ts.map +1 -1
  265. package/packages/gsd-agent-modes/dist/modes/rpc/rpc-mode.js +3 -1
  266. package/packages/gsd-agent-modes/dist/modes/rpc/rpc-mode.js.map +1 -1
  267. package/packages/gsd-agent-modes/package.json +7 -7
  268. package/packages/mcp-server/dist/cli.js +6 -3
  269. package/packages/mcp-server/dist/cli.js.map +1 -1
  270. package/packages/mcp-server/dist/workflow-tools.d.ts +8 -0
  271. package/packages/mcp-server/dist/workflow-tools.d.ts.map +1 -1
  272. package/packages/mcp-server/dist/workflow-tools.js +46 -21
  273. package/packages/mcp-server/dist/workflow-tools.js.map +1 -1
  274. package/packages/mcp-server/package.json +3 -3
  275. package/packages/native/package.json +1 -1
  276. package/packages/pi-agent-core/dist/harness/env/nodejs.d.ts +1 -0
  277. package/packages/pi-agent-core/dist/harness/env/nodejs.d.ts.map +1 -1
  278. package/packages/pi-agent-core/dist/harness/env/nodejs.js +34 -3
  279. package/packages/pi-agent-core/dist/harness/env/nodejs.js.map +1 -1
  280. package/packages/pi-agent-core/dist/index.d.ts +1 -0
  281. package/packages/pi-agent-core/dist/index.d.ts.map +1 -1
  282. package/packages/pi-agent-core/dist/index.js +3 -0
  283. package/packages/pi-agent-core/dist/index.js.map +1 -1
  284. package/packages/pi-agent-core/package.json +1 -1
  285. package/packages/pi-ai/dist/image-models.generated.d.ts +2 -2
  286. package/packages/pi-ai/dist/image-models.generated.js +6 -6
  287. package/packages/pi-ai/dist/image-models.generated.js.map +1 -1
  288. package/packages/pi-ai/dist/models.generated.d.ts +478 -484
  289. package/packages/pi-ai/dist/models.generated.d.ts.map +1 -1
  290. package/packages/pi-ai/dist/models.generated.js +500 -533
  291. package/packages/pi-ai/dist/models.generated.js.map +1 -1
  292. package/packages/pi-ai/package.json +1 -1
  293. package/packages/pi-coding-agent/dist/core/auth-storage.d.ts +2 -2
  294. package/packages/pi-coding-agent/dist/core/auth-storage.d.ts.map +1 -1
  295. package/packages/pi-coding-agent/dist/core/auth-storage.js +19 -13
  296. package/packages/pi-coding-agent/dist/core/auth-storage.js.map +1 -1
  297. package/packages/pi-coding-agent/dist/core/capability-patches.d.ts.map +1 -1
  298. package/packages/pi-coding-agent/dist/core/capability-patches.js +3 -1
  299. package/packages/pi-coding-agent/dist/core/capability-patches.js.map +1 -1
  300. package/packages/pi-coding-agent/dist/core/provider-readiness.d.ts.map +1 -1
  301. package/packages/pi-coding-agent/dist/core/provider-readiness.js +13 -6
  302. package/packages/pi-coding-agent/dist/core/provider-readiness.js.map +1 -1
  303. package/packages/pi-coding-agent/dist/core/tools/bash.d.ts +11 -0
  304. package/packages/pi-coding-agent/dist/core/tools/bash.d.ts.map +1 -1
  305. package/packages/pi-coding-agent/dist/core/tools/bash.js +53 -11
  306. package/packages/pi-coding-agent/dist/core/tools/bash.js.map +1 -1
  307. package/packages/pi-coding-agent/dist/index.d.ts +1 -1
  308. package/packages/pi-coding-agent/dist/index.d.ts.map +1 -1
  309. package/packages/pi-coding-agent/dist/index.js +1 -1
  310. package/packages/pi-coding-agent/dist/index.js.map +1 -1
  311. package/packages/pi-coding-agent/dist/utils/shell.d.ts +28 -2
  312. package/packages/pi-coding-agent/dist/utils/shell.d.ts.map +1 -1
  313. package/packages/pi-coding-agent/dist/utils/shell.js +56 -10
  314. package/packages/pi-coding-agent/dist/utils/shell.js.map +1 -1
  315. package/packages/pi-coding-agent/package.json +7 -7
  316. package/packages/pi-tui/dist/tui.d.ts.map +1 -1
  317. package/packages/pi-tui/dist/tui.js +9 -0
  318. package/packages/pi-tui/dist/tui.js.map +1 -1
  319. package/packages/pi-tui/package.json +2 -2
  320. package/packages/rpc-client/package.json +2 -2
  321. package/pkg/package.json +1 -1
  322. package/src/resources/extensions/async-jobs/async-bash-cancel.test.ts +360 -0
  323. package/src/resources/extensions/async-jobs/async-bash-tool.ts +33 -56
  324. package/src/resources/extensions/async-jobs/await-tool.test.ts +139 -0
  325. package/src/resources/extensions/async-jobs/await-tool.ts +82 -12
  326. package/src/resources/extensions/async-jobs/index.ts +79 -0
  327. package/src/resources/extensions/async-jobs/job-manager.ts +21 -1
  328. package/src/resources/extensions/bg-shell/bg-shell-command.ts +6 -6
  329. package/src/resources/extensions/bg-shell/bg-shell-tool.ts +10 -6
  330. package/src/resources/extensions/bg-shell/overlay.ts +9 -5
  331. package/src/resources/extensions/bg-shell/process-manager.ts +50 -25
  332. package/src/resources/extensions/bg-shell/readiness-detector.ts +12 -0
  333. package/src/resources/extensions/bg-shell/tests/lifecycle-and-utilities.test.ts +48 -1
  334. package/src/resources/extensions/bg-shell/utilities.ts +5 -2
  335. package/src/resources/extensions/browser-tools/engine/managed-gsd-browser.ts +265 -98
  336. package/src/resources/extensions/browser-tools/engine/selection.ts +90 -4
  337. package/src/resources/extensions/browser-tools/index.ts +71 -13
  338. package/src/resources/extensions/browser-tools/tests/browser-engine-selection.test.mjs +83 -13
  339. package/src/resources/extensions/browser-tools/tests/gsd-browser-launch-config.test.mjs +29 -1
  340. package/src/resources/extensions/browser-tools/tests/managed-gsd-browser-tools.test.mjs +136 -0
  341. package/src/resources/extensions/claude-code-cli/models.ts +9 -0
  342. package/src/resources/extensions/claude-code-cli/stream-adapter.ts +40 -4
  343. package/src/resources/extensions/claude-code-cli/tests/stream-adapter.test.ts +28 -0
  344. package/src/resources/extensions/gsd/auto/loop-deps.ts +1 -1
  345. package/src/resources/extensions/gsd/auto/orchestrator.ts +46 -10
  346. package/src/resources/extensions/gsd/auto/phases.ts +10 -1
  347. package/src/resources/extensions/gsd/auto-dispatch.ts +12 -0
  348. package/src/resources/extensions/gsd/auto-model-selection.ts +25 -5
  349. package/src/resources/extensions/gsd/auto-post-unit.ts +25 -7
  350. package/src/resources/extensions/gsd/auto-prompts.ts +40 -26
  351. package/src/resources/extensions/gsd/auto-start.ts +21 -22
  352. package/src/resources/extensions/gsd/auto-tool-tracking.ts +19 -0
  353. package/src/resources/extensions/gsd/auto-unit-tool-scope.ts +10 -17
  354. package/src/resources/extensions/gsd/auto-worktree-repair.ts +13 -2
  355. package/src/resources/extensions/gsd/auto-worktree.ts +41 -364
  356. package/src/resources/extensions/gsd/auto.ts +20 -24
  357. package/src/resources/extensions/gsd/bootstrap/agent-end-recovery.ts +3 -5
  358. package/src/resources/extensions/gsd/bootstrap/dynamic-tools.ts +33 -12
  359. package/src/resources/extensions/gsd/bootstrap/register-extension.ts +24 -0
  360. package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +180 -15
  361. package/src/resources/extensions/gsd/bootstrap/write-gate.ts +29 -3
  362. package/src/resources/extensions/gsd/branch-patterns.ts +3 -0
  363. package/src/resources/extensions/gsd/browser-daemon-auto-prep.ts +108 -0
  364. package/src/resources/extensions/gsd/browser-evidence.ts +18 -2
  365. package/src/resources/extensions/gsd/captures.ts +5 -16
  366. package/src/resources/extensions/gsd/closeout-recovery.ts +2 -1
  367. package/src/resources/extensions/gsd/commands/catalog.ts +6 -68
  368. package/src/resources/extensions/gsd/constants.ts +0 -3
  369. package/src/resources/extensions/gsd/crash-recovery.ts +3 -9
  370. package/src/resources/extensions/gsd/db/engine.ts +809 -0
  371. package/src/resources/extensions/gsd/db/queries.ts +453 -0
  372. package/src/resources/extensions/gsd/db/sql-constants.ts +12 -0
  373. package/src/resources/extensions/gsd/db/writers/cascades.ts +237 -0
  374. package/src/resources/extensions/gsd/db/writers/import-restore.ts +310 -0
  375. package/src/resources/extensions/gsd/db/writers/memory.ts +220 -0
  376. package/src/resources/extensions/gsd/db/writers/reconcile.ts +500 -0
  377. package/src/resources/extensions/gsd/db/writers/status.ts +88 -0
  378. package/src/resources/extensions/gsd/doctor-environment.ts +5 -13
  379. package/src/resources/extensions/gsd/doctor-format.ts +12 -7
  380. package/src/resources/extensions/gsd/doctor-git-checks.ts +3 -3
  381. package/src/resources/extensions/gsd/doctor-runtime-checks.ts +22 -17
  382. package/src/resources/extensions/gsd/error-classifier.ts +11 -0
  383. package/src/resources/extensions/gsd/exec-sandbox.ts +49 -9
  384. package/src/resources/extensions/gsd/git-service.ts +1 -0
  385. package/src/resources/extensions/gsd/gitignore.ts +3 -0
  386. package/src/resources/extensions/gsd/gsd-db.ts +173 -2373
  387. package/src/resources/extensions/gsd/guidance.ts +139 -0
  388. package/src/resources/extensions/gsd/guided-flow.ts +50 -5
  389. package/src/resources/extensions/gsd/mcp-filter.ts +2 -23
  390. package/src/resources/extensions/gsd/mcp-tool-name.ts +6 -11
  391. package/src/resources/extensions/gsd/memory-consolidation-scanner.ts +1 -1
  392. package/src/resources/extensions/gsd/migrate/safety.ts +18 -7
  393. package/src/resources/extensions/gsd/migration-auto-check.ts +28 -3
  394. package/src/resources/extensions/gsd/model-cost-table.ts +1 -0
  395. package/src/resources/extensions/gsd/model-router.ts +3 -0
  396. package/src/resources/extensions/gsd/notification-store.ts +26 -3
  397. package/src/resources/extensions/gsd/parallel-merge.ts +12 -9
  398. package/src/resources/extensions/gsd/parallel-monitor-overlay.ts +10 -7
  399. package/src/resources/extensions/gsd/paths.ts +42 -22
  400. package/src/resources/extensions/gsd/pre-execution-checks.ts +109 -3
  401. package/src/resources/extensions/gsd/preferences-models.ts +12 -47
  402. package/src/resources/extensions/gsd/preferences.ts +18 -0
  403. package/src/resources/extensions/gsd/prompts/complete-slice.md +1 -1
  404. package/src/resources/extensions/gsd/prompts/plan-slice.md +1 -1
  405. package/src/resources/extensions/gsd/prompts/refine-slice.md +1 -1
  406. package/src/resources/extensions/gsd/prompts/replan-slice.md +1 -1
  407. package/src/resources/extensions/gsd/prompts/run-uat.md +1 -1
  408. package/src/resources/extensions/gsd/prompts/system.md +5 -2
  409. package/src/resources/extensions/gsd/provider-error-guidance.ts +4 -9
  410. package/src/resources/extensions/gsd/provider-switch-observer.ts +1 -1
  411. package/src/resources/extensions/gsd/publication.ts +122 -0
  412. package/src/resources/extensions/gsd/recovery-classification.ts +47 -88
  413. package/src/resources/extensions/gsd/safety/destructive-confirmation.ts +134 -0
  414. package/src/resources/extensions/gsd/safety/evidence-collector.ts +36 -4
  415. package/src/resources/extensions/gsd/safety/evidence-cross-ref.ts +7 -2
  416. package/src/resources/extensions/gsd/safety/file-change-validator.ts +14 -0
  417. package/src/resources/extensions/gsd/state-transition-matrix.ts +42 -0
  418. package/src/resources/extensions/gsd/state.ts +4 -21
  419. package/src/resources/extensions/gsd/status-guards.ts +59 -8
  420. package/src/resources/extensions/gsd/stop-notice.ts +75 -0
  421. package/src/resources/extensions/gsd/tests/auto-loop.test.ts +123 -0
  422. package/src/resources/extensions/gsd/tests/auto-model-selection.test.ts +22 -0
  423. package/src/resources/extensions/gsd/tests/auto-orchestrator.test.ts +16 -19
  424. package/src/resources/extensions/gsd/tests/auto-paused-ui-cleanup.test.ts +3 -1
  425. package/src/resources/extensions/gsd/tests/auto-post-unit-evidence-crossref-4909.test.ts +46 -0
  426. package/src/resources/extensions/gsd/tests/auto-worktree-registry.test.ts +2 -2
  427. package/src/resources/extensions/gsd/tests/auto-worktree-repair.test.ts +4 -2
  428. package/src/resources/extensions/gsd/tests/browser-automation-contract-fixture.ts +39 -0
  429. package/src/resources/extensions/gsd/tests/browser-contract.test.ts +44 -0
  430. package/src/resources/extensions/gsd/tests/browser-daemon-auto-prep.test.ts +144 -0
  431. package/src/resources/extensions/gsd/tests/checkout-branch-stash-guard.test.ts +66 -1
  432. package/src/resources/extensions/gsd/tests/clear-stale-autostart.test.ts +44 -0
  433. package/src/resources/extensions/gsd/tests/commands-verdict.test.ts +8 -7
  434. package/src/resources/extensions/gsd/tests/destructive-confirmation.test.ts +303 -0
  435. package/src/resources/extensions/gsd/tests/dispatch-run-uat-browser-tools.test.ts +2 -1
  436. package/src/resources/extensions/gsd/tests/dynamic-bash-no-cap.test.ts +132 -0
  437. package/src/resources/extensions/gsd/tests/evidence-xref-gsd-exec.test.ts +157 -0
  438. package/src/resources/extensions/gsd/tests/exec-graceful-kill.test.ts +193 -0
  439. package/src/resources/extensions/gsd/tests/exec-tool.test.ts +29 -1
  440. package/src/resources/extensions/gsd/tests/extension-bootstrap-isolation.test.ts +35 -1
  441. package/src/resources/extensions/gsd/tests/file-change-validator.test.ts +33 -1
  442. package/src/resources/extensions/gsd/tests/guidance.test.ts +125 -0
  443. package/src/resources/extensions/gsd/tests/integration/auto-worktree-milestone-merge.test.ts +58 -15
  444. package/src/resources/extensions/gsd/tests/integration/auto-worktree.test.ts +74 -59
  445. package/src/resources/extensions/gsd/tests/integration/git-service.test.ts +3 -2
  446. package/src/resources/extensions/gsd/tests/integration/gsd-integration-fixture.ts +80 -0
  447. package/src/resources/extensions/gsd/tests/mcp-project-config.test.ts +3 -1
  448. package/src/resources/extensions/gsd/tests/migration-auto-check.test.ts +85 -1
  449. package/src/resources/extensions/gsd/tests/model-unittype-mapping.test.ts +32 -1
  450. package/src/resources/extensions/gsd/tests/notification-store.test.ts +32 -0
  451. package/src/resources/extensions/gsd/tests/oauth-api-model-routing.test.ts +167 -0
  452. package/src/resources/extensions/gsd/tests/pre-execution-checks.test.ts +193 -1
  453. package/src/resources/extensions/gsd/tests/provider-error-guidance.test.ts +3 -3
  454. package/src/resources/extensions/gsd/tests/publication.test.ts +120 -0
  455. package/src/resources/extensions/gsd/tests/recovery-classification-illegal-transition.test.ts +30 -0
  456. package/src/resources/extensions/gsd/tests/register-hooks-depth-verification.test.ts +248 -1
  457. package/src/resources/extensions/gsd/tests/runtime-invariant-modules.test.ts +1 -0
  458. package/src/resources/extensions/gsd/tests/safety-harness-false-positives.test.ts +38 -0
  459. package/src/resources/extensions/gsd/tests/session-switch-clears-pending-autostart.test.ts +108 -0
  460. package/src/resources/extensions/gsd/tests/single-writer-invariant.test.ts +43 -6
  461. package/src/resources/extensions/gsd/tests/state-transition-matrix.test.ts +36 -0
  462. package/src/resources/extensions/gsd/tests/status-guards.test.ts +38 -0
  463. package/src/resources/extensions/gsd/tests/stop-notice.test.ts +70 -0
  464. package/src/resources/extensions/gsd/tests/token-tool-gating.test.ts +76 -0
  465. package/src/resources/extensions/gsd/tests/tool-invocation-error-loop-break.test.ts +8 -0
  466. package/src/resources/extensions/gsd/tests/tool-surface-readiness.test.ts +155 -0
  467. package/src/resources/extensions/gsd/tests/uat-policy.test.ts +24 -29
  468. package/src/resources/extensions/gsd/tests/unit-closeout.test.ts +209 -0
  469. package/src/resources/extensions/gsd/tests/unit-context-composer.test.ts +67 -2
  470. package/src/resources/extensions/gsd/tests/unit-registry.test.ts +163 -0
  471. package/src/resources/extensions/gsd/tests/web-app-uat.test.ts +44 -1
  472. package/src/resources/extensions/gsd/tests/workflow-mcp.test.ts +2 -2
  473. package/src/resources/extensions/gsd/tests/workflow-tool-executors.test.ts +2 -2
  474. package/src/resources/extensions/gsd/tests/worktree-lifecycle.test.ts +41 -4
  475. package/src/resources/extensions/gsd/tests/worktree-manager.test.ts +22 -1
  476. package/src/resources/extensions/gsd/tests/worktree-placement.test.ts +113 -0
  477. package/src/resources/extensions/gsd/tests/worktree-reentry.test.ts +1 -1
  478. package/src/resources/extensions/gsd/tests/worktree-safety.test.ts +3 -1
  479. package/src/resources/extensions/gsd/tests/worktree-symlink-removal.test.ts +12 -6
  480. package/src/resources/extensions/gsd/tests/worktree-teardown-safety.test.ts +2 -2
  481. package/src/resources/extensions/gsd/tests/write-gate.test.ts +42 -0
  482. package/src/resources/extensions/gsd/tool-surface-readiness.ts +76 -0
  483. package/src/resources/extensions/gsd/tools/complete-slice.ts +23 -58
  484. package/src/resources/extensions/gsd/tools/exec-tool.ts +9 -8
  485. package/src/resources/extensions/gsd/tools/plan-slice.ts +12 -6
  486. package/src/resources/extensions/gsd/tools/reopen-milestone.ts +11 -38
  487. package/src/resources/extensions/gsd/tools/reopen-slice.ts +14 -42
  488. package/src/resources/extensions/gsd/tools/skip-slice.ts +18 -44
  489. package/src/resources/extensions/gsd/uat-policy.ts +2 -1
  490. package/src/resources/extensions/gsd/undo.ts +9 -8
  491. package/src/resources/extensions/gsd/unit-closeout.ts +201 -0
  492. package/src/resources/extensions/gsd/unit-context-composer.ts +111 -1
  493. package/src/resources/extensions/gsd/unit-context-manifest.ts +4 -28
  494. package/src/resources/extensions/gsd/unit-registry.ts +412 -0
  495. package/src/resources/extensions/gsd/unit-tool-contracts.ts +27 -192
  496. package/src/resources/extensions/gsd/web-app-uat.ts +51 -8
  497. package/src/resources/extensions/gsd/workflow-tool-surface.ts +4 -1
  498. package/src/resources/extensions/gsd/worktree-git-recovery.ts +314 -0
  499. package/src/resources/extensions/gsd/worktree-lifecycle.ts +10 -1
  500. package/src/resources/extensions/gsd/worktree-manager.ts +47 -28
  501. package/src/resources/extensions/gsd/worktree-placement.ts +63 -0
  502. package/src/resources/extensions/gsd/worktree-reentry.ts +10 -7
  503. package/src/resources/extensions/gsd/worktree-root.ts +29 -6
  504. package/src/resources/extensions/gsd/worktree-safety.ts +8 -5
  505. package/src/resources/extensions/gsd/worktree-session-state.ts +11 -11
  506. package/src/resources/extensions/search-the-web/native-search.ts +5 -3
  507. package/src/resources/extensions/shared/browser-contract.ts +66 -0
  508. package/src/resources/extensions/shared/gsd-browser-cli.ts +119 -5
  509. package/src/resources/shared/package.json +3 -0
  510. package/src/resources/skills/create-skill/references/executable-code.md +1 -1
  511. package/src/resources/skills/create-skill/workflows/add-reference.md +8 -3
  512. package/src/resources/skills/create-skill/workflows/add-script.md +4 -2
  513. package/src/resources/skills/create-skill/workflows/add-template.md +3 -1
  514. package/src/resources/skills/create-skill/workflows/add-workflow.md +8 -3
  515. package/src/resources/skills/create-skill/workflows/upgrade-to-router.md +10 -5
  516. package/src/resources/skills/create-skill/workflows/verify-skill.md +9 -4
  517. package/src/resources/skills/gsd-browser/SKILL.md +1 -1
  518. package/src/resources/skills/spike-wrap-up/SKILL.md +9 -9
  519. /package/dist/web/standalone/.next/static/{3PtrU9qGPEXwNLWkIyiqk → mU4QIDlpVHDdjDpeEKh5W}/_buildManifest.js +0 -0
  520. /package/dist/web/standalone/.next/static/{3PtrU9qGPEXwNLWkIyiqk → mU4QIDlpVHDdjDpeEKh5W}/_ssgManifest.js +0 -0
@@ -13,6 +13,7 @@ import { registerHooks } from "./register-hooks.js";
13
13
  import { registerShortcuts } from "./register-shortcuts.js";
14
14
  import { writeCrashLog } from "./crash-log.js";
15
15
  import { logWarning } from "../workflow-logger.js";
16
+ import { UNIT_TOOL_CONTRACTS } from "../unit-tool-contracts.js";
16
17
  // Static import so cmux event listeners are registered synchronously during
17
18
  // extension bootstrap. Prior implementation used `void import().then()` which
18
19
  // queued listener registration as a microtask — any CMUX_CHANNELS emit fired
@@ -30,6 +31,9 @@ const EPIPE_STORM_THRESHOLD = 100;
30
31
  const EPIPE_STORM_WINDOW_MS = 10_000;
31
32
  let epipeCount = 0;
32
33
  let epipeWindowStart = 0;
34
+ export const CRITICAL_GSD_WORKFLOW_TOOL_NAMES = [...new Set(Object.values(UNIT_TOOL_CONTRACTS)
35
+ .flatMap((contract) => contract.requiredWorkflowTools)
36
+ .filter((toolName) => toolName.startsWith("gsd_")))].sort();
33
37
  /** Write to stderr without ever re-throwing — stderr can EPIPE too, which would
34
38
  * re-enter this handler and re-loop. */
35
39
  function safeStderr(msg) {
@@ -121,6 +125,20 @@ export function installEpipeGuard() {
121
125
  process.on("unhandledRejection", _gsdRejectionGuard);
122
126
  }
123
127
  }
128
+ function assertCriticalGsdWorkflowToolsRegistered(pi) {
129
+ if (typeof pi.getAllTools !== "function")
130
+ return;
131
+ const registered = new Set(pi.getAllTools().map((tool) => tool.name));
132
+ const missing = CRITICAL_GSD_WORKFLOW_TOOL_NAMES.filter((toolName) => !registered.has(toolName));
133
+ if (missing.length === 0)
134
+ return;
135
+ const message = [
136
+ `Critical GSD workflow tool registration failed; missing required tool(s): ${missing.join(", ")}.`,
137
+ "Check earlier bootstrap warnings for the registration slot that failed.",
138
+ ].join(" ");
139
+ logWarning("bootstrap", message);
140
+ throw new Error(message);
141
+ }
124
142
  export function registerGsdExtension(pi) {
125
143
  // Note: registerGSDCommand is called by index.ts before this function,
126
144
  // so we intentionally skip it here to avoid double-registration.
@@ -186,4 +204,5 @@ export function registerGsdExtension(pi) {
186
204
  logWarning("bootstrap", `Failed to register ${name}: ${err instanceof Error ? err.message : String(err)}`);
187
205
  }
188
206
  }
207
+ assertCriticalGsdWorkflowToolsRegistered(pi);
189
208
  }
@@ -7,7 +7,7 @@ import { isToolCallEventType } from "@gsd/pi-coding-agent";
7
7
  import { ALWAYS_PRESERVED_SHIM_TOOL_NAMES } from "@gsd/pi-ai";
8
8
  import { updateSnapshot } from "../ecosystem/gsd-extension-api.js";
9
9
  import { buildMilestoneFileName, clearPathCache, milestonesDir, resolveMilestonePath, resolveSliceFile, resolveSlicePath } from "../paths.js";
10
- import { applyAskUserQuestionsGateResult, canonicalToolName, clearDiscussionFlowState, formatPendingAskUserQuestionsGateMessage, isMilestoneDepthVerified, isQueuePhaseActive, markApprovalGateVerified, markDepthVerified, resetWriteGateState, shouldBlockContextWrite, shouldBlockPlanningUnit, shouldBlockQueueExecution, shouldBlockWorktreeWrite, isGateQuestionId, setPendingGate, clearPendingGate, getPendingGate, shouldBlockPendingGate, shouldBlockPendingGateBash, extractDepthVerificationMilestoneId } from "./write-gate.js";
10
+ import { applyAskUserQuestionsGateResult, canonicalToolName, clearDiscussionFlowState, formatPendingAskUserQuestionsGateMessage, isApprovalGateVerifiedInSnapshot, isDepthConfirmationAnswer, isMilestoneDepthVerified, isMilestoneDepthVerifiedInSnapshot, isQueuePhaseActive, markApprovalGateVerified, markDepthVerified, refreshWriteGateStateFromDisk, resetWriteGateState, shouldBlockContextWrite, shouldBlockPlanningUnit, shouldBlockQueueExecution, shouldBlockWorktreeWrite, isGateQuestionId, setPendingGate, clearPendingGate, getPendingGate, shouldBlockPendingGate, shouldBlockPendingGateBash, extractDepthVerificationMilestoneId } from "./write-gate.js";
11
11
  import { resolveManifest } from "../unit-context-manifest.js";
12
12
  import { isBlockedStateFile, isBashWriteToStateFile, BLOCKED_WRITE_ERROR } from "../write-intercept.js";
13
13
  import { loadFile, saveFile, formatContinue } from "../files.js";
@@ -19,7 +19,9 @@ import { saveActivityLog } from "../activity-log.js";
19
19
  import { recordToolCall as safetyRecordToolCall, recordToolResult as safetyRecordToolResult, saveEvidenceToDisk } from "../safety/evidence-collector.js";
20
20
  import { parseUnitId } from "../unit-id.js";
21
21
  import { classifyCommand } from "../safety/destructive-guard.js";
22
+ import { confirmDestructiveCommand, consumeDestructiveConfirmation, isDestructiveConfirmGateId, requestDestructiveConfirmation, } from "../safety/destructive-confirmation.js";
22
23
  import { logWarning as safetyLogWarning } from "../workflow-logger.js";
24
+ import { isUnitCloseoutTool, runInteractiveUnitCloseout } from "../unit-closeout.js";
23
25
  import { installNotifyInterceptor } from "./notify-interceptor.js";
24
26
  import { initNotificationStore } from "../notification-store.js";
25
27
  import { initNotificationWidget } from "../notification-widget.js";
@@ -31,10 +33,14 @@ import { applyUnitSkillVisibility, unitHasSkillManifest } from "../skill-scope.j
31
33
  import { getGuidedUnitContext } from "../guided-unit-context.js";
32
34
  import { registerPlanMilestoneSchemaRecovery } from "./plan-milestone-schema-recovery.js";
33
35
  import { AUTO_UNIT_SCOPED_TOOLS, RUN_UAT_BROWSER_TOOL_NAMES, canonicalWorkflowToolName, isWorkflowAliasTool } from "../auto-unit-tool-scope.js";
36
+ import { hasBrowserContractPrefix } from "../../shared/browser-contract.js";
34
37
  import { filterToolsForProvider } from "../model-router.js";
35
38
  import { mcpToolMatchesBaseName } from "../mcp-tool-name.js";
36
39
  import { RUN_UAT_READ_ONLY_TOOL_NAMES, RUN_UAT_WORKFLOW_TOOL_NAMES } from "../tool-presentation-plan.js";
37
40
  import { supportsSourceObservationsForUnit } from "../source-observations.js";
41
+ import { clearPendingAutoStart } from "../pending-auto-start.js";
42
+ import { resolveWorkflowToolBasePath } from "./dynamic-tools.js";
43
+ import { getRequiredWorkflowToolsForUnit } from "../unit-tool-contracts.js";
38
44
  let approvalQuestionAbortInFlight = false;
39
45
  async function loadWelcomeScreenModule() {
40
46
  const candidates = [];
@@ -137,7 +143,7 @@ function withPreservedShimTools(toolNames) {
137
143
  }
138
144
  /** True for the browser automation tools (browser_navigate, browser_click, ...). */
139
145
  function isBrowserTool(toolName) {
140
- return canonicalToolName(toolName).startsWith("browser_");
146
+ return hasBrowserContractPrefix(canonicalToolName(toolName));
141
147
  }
142
148
  /**
143
149
  * True when any message in the request is driven by a GSD workflow command
@@ -199,7 +205,7 @@ export function buildMinimalGsdToolSet(activeToolNames) {
199
205
  const minimal = resolveScopedToolNames(activeToolNames, MINIMAL_GSD_TOOL_NAMES);
200
206
  return withPreservedShimTools([...new Set([...preserved, ...minimal])]);
201
207
  }
202
- export function buildMinimalAutoGsdToolSet(activeToolNames, unitType, registeredToolNames = activeToolNames) {
208
+ export function buildMinimalAutoGsdToolSet(activeToolNames, unitType, registeredToolNames = activeToolNames, warnOnUnresolvedRequiredTools = registeredToolNames !== activeToolNames) {
203
209
  if (unitType === "run-uat") {
204
210
  return buildRunUatGsdToolSet(activeToolNames, registeredToolNames);
205
211
  }
@@ -211,7 +217,20 @@ export function buildMinimalAutoGsdToolSet(activeToolNames, unitType, registered
211
217
  ...availableBaseTools,
212
218
  ])];
213
219
  const scoped = resolveScopedToolNames([...activeToolNames, ...registeredToolNames], [...MINIMAL_GSD_TOOL_NAMES, ...unitTools]);
214
- return withPreservedShimTools([...new Set([...preserved, ...scoped])]);
220
+ const result = withPreservedShimTools([...new Set([...preserved, ...scoped])]);
221
+ warnIfRequiredWorkflowToolsUnresolved(unitType, result, warnOnUnresolvedRequiredTools);
222
+ return result;
223
+ }
224
+ function hasResolvedWorkflowTool(resolvedToolNames, requiredToolName) {
225
+ return resolvedToolNames.some((name) => name === requiredToolName || mcpToolMatchesBaseName(name, requiredToolName));
226
+ }
227
+ function warnIfRequiredWorkflowToolsUnresolved(unitType, scopedToolNames, shouldWarn) {
228
+ if (!unitType || !shouldWarn)
229
+ return;
230
+ const unresolved = getRequiredWorkflowToolsForUnit(unitType).filter((toolName) => !hasResolvedWorkflowTool(scopedToolNames, toolName));
231
+ if (unresolved.length === 0)
232
+ return;
233
+ safetyLogWarning("bootstrap", `buildMinimalAutoGsdToolSet(${unitType}): required workflow tool(s) not in active/registered surface after scoping: ${unresolved.join(", ")}. Tool registration may have partially failed, provider filtering may have removed a required tool, or workflow MCP may be disconnected.`);
215
234
  }
216
235
  export function buildRunUatGsdToolSet(activeToolNames, registeredToolNames = activeToolNames) {
217
236
  const scoped = resolveScopedToolNames([...activeToolNames, ...registeredToolNames], [
@@ -237,7 +256,7 @@ export function buildMinimalGsdWorkflowToolSet(activeToolNames, registeredToolNa
237
256
  const scoped = resolveScopedToolNames([...activeToolNames, ...registeredToolNames], WORKFLOW_GSD_TOOL_NAMES);
238
257
  return withPreservedShimTools([...new Set([...preserved, ...scoped])]);
239
258
  }
240
- export function buildRequestScopedGsdToolSet(activeToolNames, requestCustomMessages, registeredToolNames = activeToolNames, guidedUnitType) {
259
+ export function buildRequestScopedGsdToolSet(activeToolNames, requestCustomMessages, registeredToolNames = activeToolNames, guidedUnitType, warnOnUnresolvedRequiredTools = registeredToolNames !== activeToolNames) {
241
260
  for (let index = (requestCustomMessages?.length ?? 0) - 1; index >= 0; index--) {
242
261
  const currentCustomType = requestCustomMessages?.[index]?.customType;
243
262
  if (currentCustomType === "gsd-run" ||
@@ -245,7 +264,7 @@ export function buildRequestScopedGsdToolSet(activeToolNames, requestCustomMessa
245
264
  currentCustomType === "gsd-doctor-heal" ||
246
265
  currentCustomType === "gsd-triage") {
247
266
  if (guidedUnitType) {
248
- return buildMinimalAutoGsdToolSet(activeToolNames, guidedUnitType, registeredToolNames);
267
+ return buildMinimalAutoGsdToolSet(activeToolNames, guidedUnitType, registeredToolNames, warnOnUnresolvedRequiredTools);
249
268
  }
250
269
  return buildMinimalGsdWorkflowToolSet(activeToolNames, registeredToolNames);
251
270
  }
@@ -279,8 +298,9 @@ function applyMinimalGsdToolSurface(pi) {
279
298
  const dash = getAutoRuntimeSnapshot();
280
299
  if (dash.active && dash.currentUnit) {
281
300
  const currentToolNames = pi.getActiveTools();
301
+ const hasRegisteredSurface = typeof pi.getAllTools === "function";
282
302
  const registeredToolNames = resolveRegisteredToolNames(pi, currentToolNames);
283
- const scopedToolNames = buildMinimalAutoGsdToolSet(currentToolNames, dash.currentUnit.type, registeredToolNames);
303
+ const scopedToolNames = buildMinimalAutoGsdToolSet(currentToolNames, dash.currentUnit.type, registeredToolNames, hasRegisteredSurface);
284
304
  recordAutoToolSurfaceSnapshot({
285
305
  source: "runtime-scope",
286
306
  unitType: dash.currentUnit.type,
@@ -299,9 +319,10 @@ export function scopeGsdWorkflowToolsForDispatch(pi, unitType) {
299
319
  if (isFullGsdToolSurfaceRequested())
300
320
  return null;
301
321
  const current = pi.getActiveTools();
322
+ const hasRegisteredSurface = typeof pi.getAllTools === "function";
302
323
  const registeredToolNames = resolveRegisteredToolNames(pi, current);
303
324
  const scoped = unitType
304
- ? buildMinimalAutoGsdToolSet(current, unitType, registeredToolNames)
325
+ ? buildMinimalAutoGsdToolSet(current, unitType, registeredToolNames, hasRegisteredSurface)
305
326
  : buildMinimalGsdWorkflowToolSet(current, registeredToolNames);
306
327
  recordAutoToolSurfaceSnapshot({
307
328
  source: "dispatch-scope",
@@ -444,8 +465,15 @@ function isShellExecutionTool(canonicalName) {
444
465
  function activateDeferredApprovalGate(basePath) {
445
466
  if (deferredApprovalGate?.basePath !== basePath)
446
467
  return;
447
- setPendingGate(deferredApprovalGate.gateId, basePath);
468
+ const gateId = deferredApprovalGate.gateId;
448
469
  deferredApprovalGate = null;
470
+ const snapshot = refreshWriteGateStateFromDisk(basePath);
471
+ const milestoneId = extractDepthVerificationMilestoneId(gateId);
472
+ if (isApprovalGateVerifiedInSnapshot(snapshot, gateId))
473
+ return;
474
+ if (milestoneId && isMilestoneDepthVerifiedInSnapshot(snapshot, milestoneId))
475
+ return;
476
+ setPendingGate(gateId, basePath);
449
477
  }
450
478
  function extractGateQuestionId(input) {
451
479
  const questions = input?.questions ?? [];
@@ -463,6 +491,25 @@ function isContextDraftSummarySave(toolName, input) {
463
491
  return false;
464
492
  return input.artifact_type === "CONTEXT-DRAFT";
465
493
  }
494
+ /**
495
+ * External engines (claude-code-cli) deliver ask_user_questions results as
496
+ * relayed MCP tool results: the structured round payload arrives in
497
+ * `result.structuredContent`, not in pi-native `event.details`. Without this
498
+ * fallback, applyAskUserQuestionsGateResult sees no response for an answered
499
+ * gate question and lands in the "waiting" branch — leaving a re-armed gate
500
+ * permanently pending and the discuss→auto handoff blocked.
501
+ */
502
+ function resolveAskUserQuestionsGateDetails(event) {
503
+ const hasRoundShape = (value) => !!value && typeof value === "object" &&
504
+ (value.cancelled !== undefined || value.response !== undefined);
505
+ const details = event.details;
506
+ if (hasRoundShape(details))
507
+ return details;
508
+ const structured = event.result?.structuredContent;
509
+ if (hasRoundShape(structured))
510
+ return structured;
511
+ return details ?? {};
512
+ }
466
513
  function selectedAnswerLabel(selected) {
467
514
  if (Array.isArray(selected))
468
515
  return selected.map(String).join(", ");
@@ -626,7 +673,7 @@ export function registerHooks(pi, ecosystemHandlers) {
626
673
  catch { /* non-fatal */ }
627
674
  }
628
675
  });
629
- pi.on("session_switch", async (_event, ctx) => {
676
+ pi.on("session_switch", async (event, ctx) => {
630
677
  const basePath = contextBasePath(ctx);
631
678
  const preserveCloseoutSurface = isAutoCompletionStopInProgress();
632
679
  initSessionNotifications(ctx);
@@ -635,6 +682,13 @@ export function registerHooks(pi, ecosystemHandlers) {
635
682
  clearDeferredApprovalGate();
636
683
  await resetAskUserQuestionsTurnCache();
637
684
  clearDiscussionFlowState(basePath);
685
+ // /clear or /new destroys the conversation holding a discuss interview, so
686
+ // its pending discuss→auto handoff can never be answered — clear it. Resume
687
+ // restores the interview transcript, so the entry survives. Auto-mode's own
688
+ // newSession() calls are safe: the handoff consumes the entry on agent_end.
689
+ if (event.reason === "new") {
690
+ clearPendingAutoStart(basePath);
691
+ }
638
692
  await syncServiceTierStatus(ctx);
639
693
  await applyDisabledModelProviderPolicy(ctx);
640
694
  await applyCompactionThresholdOverride(ctx);
@@ -1056,19 +1110,35 @@ export function registerHooks(pi, ecosystemHandlers) {
1056
1110
  }
1057
1111
  // Destructive command classification + hard gate in all modes.
1058
1112
  if (isToolCallEventType("bash", event)) {
1059
- const classification = classifyCommand(event.input.command);
1113
+ const command = event.input.command;
1114
+ const classification = classifyCommand(command);
1060
1115
  if (classification.destructive) {
1116
+ const guardBasePath = contextBasePath(ctx);
1117
+ // Escape hatch: if the user already confirmed this exact command via a
1118
+ // destructive_confirm gate, consume the one-shot token and let it run.
1119
+ // Without this, the block below loops forever — the model cannot satisfy
1120
+ // "confirm in the current turn" because nothing ever clears the gate.
1121
+ if (consumeDestructiveConfirmation(command, guardBasePath)) {
1122
+ safetyLogWarning("safety", `destructive command confirmed: ${classification.labels.join(", ")}`, {
1123
+ command: String(command).slice(0, 200),
1124
+ });
1125
+ return;
1126
+ }
1127
+ // Record the command as pending so an affirmative answer to a
1128
+ // destructive_confirm gate (handled in tool_result) can confirm it.
1129
+ requestDestructiveConfirmation(command, guardBasePath);
1061
1130
  const reason = [
1062
1131
  "HARD BLOCK: destructive Bash command requires explicit human confirmation.",
1063
1132
  `Detected: ${classification.labels.join(", ")}`,
1064
- "Run this via ask_user_questions, wait for the user's response,",
1065
- "then issue the command only when confirmed in the current turn.",
1133
+ "Call ask_user_questions with a question id containing \"destructive_confirm\"",
1134
+ "and a first option that affirms the action; wait for the user's response,",
1135
+ "then re-issue this exact command in the same turn to run it once.",
1066
1136
  ].join(" ");
1067
1137
  safetyLogWarning("safety", `destructive command: ${classification.labels.join(", ")}`, {
1068
- command: String(event.input.command).slice(0, 200),
1138
+ command: String(command).slice(0, 200),
1069
1139
  });
1070
1140
  if (ctx) {
1071
- await maybePauseAutoForApprovalGate(ctx, pi, isAutoActive(), "Depth confirmation is waiting for your answer — pausing auto-mode.");
1141
+ await maybePauseAutoForApprovalGate(ctx, pi, isAutoActive(), "Destructive-command confirmation is waiting for your answer — pausing auto-mode.");
1072
1142
  }
1073
1143
  return { block: true, reason };
1074
1144
  }
@@ -1105,12 +1175,27 @@ export function registerHooks(pi, ecosystemHandlers) {
1105
1175
  else if (isAutoActive()) {
1106
1176
  clearToolInvocationError();
1107
1177
  }
1178
+ // Interactive Closeout adapter (ADR-032): auto-mode owns closeout for its
1179
+ // own units; interactive completions get the durable git subset (commit +
1180
+ // Closeout Git Verdict) instead of silently bypassing git.isolation.
1181
+ if (!event.isError && !isAutoActive() && isUnitCloseoutTool(toolName)) {
1182
+ try {
1183
+ runInteractiveUnitCloseout({
1184
+ basePath: resolveWorkflowToolBasePath(ctx, event.input),
1185
+ canonicalToolName: toolName,
1186
+ input: event.input,
1187
+ });
1188
+ }
1189
+ catch (err) {
1190
+ safetyLogWarning("engine", `interactive unit closeout failed: ${err instanceof Error ? err.message : String(err)}`);
1191
+ }
1192
+ }
1108
1193
  if (toolName !== "ask_user_questions")
1109
1194
  return;
1110
1195
  const basePath = contextBasePath(ctx);
1111
1196
  const milestoneId = await getDiscussionMilestoneIdFor(basePath);
1112
- const details = event.details;
1113
- const questions = event.input?.questions ?? [];
1197
+ const details = resolveAskUserQuestionsGateDetails(event);
1198
+ const questions = event.input?.questions ?? details?.questions ?? [];
1114
1199
  const gateResult = applyAskUserQuestionsGateResult({
1115
1200
  basePath,
1116
1201
  questions,
@@ -1136,6 +1221,22 @@ export function registerHooks(pi, ecosystemHandlers) {
1136
1221
  }
1137
1222
  if (details?.cancelled || !details?.response)
1138
1223
  return;
1224
+ // Destructive-command confirmation: an affirmative answer to a
1225
+ // destructive_confirm gate promotes the pending blocked command to a
1226
+ // one-shot confirmed token, which the bash tool_call guard consumes on the
1227
+ // next attempt. Rejecting/declining leaves the command blocked.
1228
+ // (Depth-verification gate handling now lives in
1229
+ // applyAskUserQuestionsGateResult above; only the destructive-confirm gate
1230
+ // is handled inline here.)
1231
+ for (const question of questions) {
1232
+ if (isDestructiveConfirmGateId(question?.id)) {
1233
+ const answer = details.response?.answers?.[question.id];
1234
+ if (isDepthConfirmationAnswer(answer?.selected, question.options)) {
1235
+ confirmDestructiveCommand(basePath);
1236
+ }
1237
+ break;
1238
+ }
1239
+ }
1139
1240
  if (!milestoneId)
1140
1241
  return;
1141
1242
  await saveDiscussionQuestionRound(basePath, milestoneId, questions, details);
@@ -1146,10 +1247,39 @@ export function registerHooks(pi, ecosystemHandlers) {
1146
1247
  if (toolName === "ask_user_questions") {
1147
1248
  const questionId = extractGateQuestionId(event.args);
1148
1249
  if (typeof questionId === "string") {
1149
- setPendingGate(questionId, basePath);
1250
+ // External engines (claude-code-cli) ingest the SDK turn's tool blocks
1251
+ // post-hoc, so this event can fire AFTER the workflow MCP child already
1252
+ // verified this gate and allowed the CONTEXT save. setPendingGate also
1253
+ // revokes verifiedDepthMilestones/verifiedApprovalGates, so an
1254
+ // unconditional re-arm here wipes the child's verification and leaves
1255
+ // the discuss→auto handoff permanently blocked. Skip the re-arm when
1256
+ // the snapshot already records this exact gate as verified — mirrors
1257
+ // activateDeferredApprovalGate's guard. Stale verified state cannot
1258
+ // leak into a later re-discussion: a successful handoff deletes the
1259
+ // snapshot via clearDiscussionFlowState.
1260
+ const snapshot = refreshWriteGateStateFromDisk(basePath);
1261
+ const gateMilestoneId = extractDepthVerificationMilestoneId(questionId);
1262
+ const alreadyVerified = isApprovalGateVerifiedInSnapshot(snapshot, questionId) ||
1263
+ isMilestoneDepthVerifiedInSnapshot(snapshot, gateMilestoneId);
1264
+ if (!alreadyVerified) {
1265
+ setPendingGate(questionId, basePath);
1266
+ }
1150
1267
  clearDeferredApprovalGate(basePath);
1151
1268
  }
1152
1269
  }
1270
+ // Safety harness: record evidence here, not only in tool_call. External
1271
+ // engines (claude-code-cli) pre-execute tools, so the agent loop skips
1272
+ // beforeToolCall/tool_call for them — tool_execution_start is the only
1273
+ // event that fires for every tool call. recordToolCall dedupes by
1274
+ // toolCallId, so native tools (which hit both events) record once.
1275
+ safetyRecordToolCall(event.toolCallId, event.toolName, (event.args ?? {}));
1276
+ const execDash = getAutoRuntimeSnapshot();
1277
+ if (execDash.basePath && execDash.currentUnit?.type === "execute-task") {
1278
+ const { milestone: xMid, slice: xSid, task: xTid } = parseUnitId(execDash.currentUnit.id);
1279
+ if (xMid && xSid && xTid) {
1280
+ saveEvidenceToDisk(execDash.basePath, xMid, xSid, xTid);
1281
+ }
1282
+ }
1153
1283
  if (!isAutoActive())
1154
1284
  return;
1155
1285
  markToolStart(event.toolCallId, event.toolName);
@@ -1223,12 +1353,13 @@ export function registerHooks(pi, ecosystemHandlers) {
1223
1353
  return surfaceReduced ? { toolNames: providerCompatible } : undefined;
1224
1354
  }
1225
1355
  const registeredToolNames = resolveRegisteredToolNames(pi, event.activeToolNames);
1356
+ const hasRegisteredSurface = typeof pi.getAllTools === "function";
1226
1357
  const compatibleRegisteredToolNames = filterToolsForProvider(registeredToolNames, event.selectedModelApi, event.selectedModelProvider).compatible.filter((name) => !(dropAliases && isWorkflowAliasTool(name)));
1227
1358
  const guidedUnit = getGuidedUnitContext();
1228
1359
  const requestRegisteredToolNames = guidedUnit?.unitType === "run-uat"
1229
1360
  ? compatibleRegisteredToolNames
1230
1361
  : registeredToolNames;
1231
- const requestScoped = buildRequestScopedGsdToolSet(guidedUnit?.unitType === "run-uat" ? aliasFilteredCompatible : providerCompatible, event.requestCustomMessages, requestRegisteredToolNames, guidedUnit?.unitType);
1362
+ const requestScoped = buildRequestScopedGsdToolSet(guidedUnit?.unitType === "run-uat" ? aliasFilteredCompatible : providerCompatible, event.requestCustomMessages, requestRegisteredToolNames, guidedUnit?.unitType, hasRegisteredSurface);
1232
1363
  if (requestScoped) {
1233
1364
  recordAutoToolSurfaceSnapshot({
1234
1365
  source: "provider-adjustment",
@@ -1244,7 +1375,7 @@ export function registerHooks(pi, ecosystemHandlers) {
1244
1375
  const registeredForUnit = dash.currentUnit.type === "run-uat"
1245
1376
  ? compatibleRegisteredToolNames
1246
1377
  : resolveRegisteredToolNames(pi, event.activeToolNames);
1247
- const scopedToolNames = buildMinimalAutoGsdToolSet(dash.currentUnit.type === "run-uat" ? aliasFilteredCompatible : providerCompatible, dash.currentUnit.type, registeredForUnit);
1378
+ const scopedToolNames = buildMinimalAutoGsdToolSet(dash.currentUnit.type === "run-uat" ? aliasFilteredCompatible : providerCompatible, dash.currentUnit.type, registeredForUnit, hasRegisteredSurface);
1248
1379
  recordAutoToolSurfaceSnapshot({
1249
1380
  source: "provider-adjustment",
1250
1381
  unitType: dash.currentUnit.type,
@@ -8,6 +8,7 @@ import { getIsolationMode } from "../preferences.js";
8
8
  import { compileSubagentPermissionContract } from "../unit-context-manifest.js";
9
9
  import { logWarning } from "../workflow-logger.js";
10
10
  import { isGsdWorktreePath, resolveWorktreeProjectRoot } from "../worktree-root.js";
11
+ import { worktreesDirs } from "../worktree-placement.js";
11
12
  /**
12
13
  * Regex matching milestone CONTEXT.md file names in both legacy M001
13
14
  * and unique M001-abc123 formats. Exported so regex-hardening tests
@@ -214,6 +215,27 @@ export function loadWriteGateSnapshot(basePath) {
214
215
  return currentWriteGateSnapshot(basePath);
215
216
  }
216
217
  }
218
+ /**
219
+ * Merge the persisted write-gate snapshot into the in-process Map entry.
220
+ * The workflow MCP server runs in a child process and records depth
221
+ * verification there; without this refresh the extension host keeps stale
222
+ * pending-gate memory and `activateDeferredApprovalGate` can re-arm a gate
223
+ * that the subprocess already cleared on disk.
224
+ *
225
+ * Returns the snapshot used for the refresh so callers that need to inspect
226
+ * it (e.g. re-arm guards) avoid a second disk read.
227
+ */
228
+ export function refreshWriteGateStateFromDisk(basePath) {
229
+ const snapshot = loadWriteGateSnapshot(basePath);
230
+ if (!shouldPersistWriteGateSnapshot())
231
+ return snapshot;
232
+ const state = getWriteGateState(basePath);
233
+ state.pendingGateId = snapshot.pendingGateId;
234
+ state.activeQueuePhase = snapshot.activeQueuePhase;
235
+ state.verifiedDepthMilestones = new Set(snapshot.verifiedDepthMilestones);
236
+ state.verifiedApprovalGates = new Set(snapshot.verifiedApprovalGates ?? []);
237
+ return snapshot;
238
+ }
217
239
  export function isDepthVerified(basePath = process.cwd()) {
218
240
  return getWriteGateState(basePath).verifiedDepthMilestones.size > 0;
219
241
  }
@@ -223,6 +245,7 @@ export function isDepthVerified(basePath = process.cwd()) {
223
245
  export function isMilestoneDepthVerified(milestoneId, basePath = process.cwd()) {
224
246
  if (!milestoneId)
225
247
  return false;
248
+ refreshWriteGateStateFromDisk(basePath);
226
249
  return getWriteGateState(basePath).verifiedDepthMilestones.has(milestoneId);
227
250
  }
228
251
  export function isMilestoneDepthVerifiedInSnapshot(snapshot, milestoneId) {
@@ -309,6 +332,7 @@ export function clearPendingGate(basePath) {
309
332
  * Get the currently pending gate, if any.
310
333
  */
311
334
  export function getPendingGate(basePath = process.cwd()) {
335
+ refreshWriteGateStateFromDisk(basePath);
312
336
  return getWriteGateState(basePath).pendingGateId;
313
337
  }
314
338
  /**
@@ -919,10 +943,12 @@ export function shouldBlockWorktreeWrite(toolName, targetPath, effectiveBasePath
919
943
  const realTarget = realpathOrResolve(absTarget);
920
944
  const realRoot = realpathOrResolve(projectRoot);
921
945
  const realGsd = realpathOrResolve(join(projectRoot, ".gsd"));
922
- const realWorktreesDir = realpathOrResolve(join(projectRoot, ".gsd", "worktrees"));
923
- // Allow writes inside the legitimate worktrees subtree.
924
- if (isPathContained(realTarget, realWorktreesDir))
925
- return { block: false };
946
+ // Allow writes inside a legitimate worktrees subtree (canonical
947
+ // .gsd-worktrees/ or legacy .gsd/worktrees/).
948
+ for (const container of worktreesDirs(projectRoot)) {
949
+ if (isPathContained(realTarget, realpathOrResolve(container)))
950
+ return { block: false };
951
+ }
926
952
  // Allow writes to .gsd/ planning artifacts, but reject siblings whose name
927
953
  // starts with "worktrees" (the worktrees-extra prefix trick — case 4).
928
954
  if (isPathContained(realTarget, realGsd)) {
@@ -11,3 +11,5 @@ export const SLICE_BRANCH_RE = /^gsd\/(?:([a-zA-Z0-9_-]+)\/)?(M\d+(?:-[a-z0-9]{6
11
11
  export const QUICK_BRANCH_RE = /^gsd\/quick\//;
12
12
  /** Matches GSD-generated workflow template branches, not arbitrary user gsd/* branches. */
13
13
  export const WORKFLOW_BRANCH_RE = /^gsd\/(?:hotfix|bugfix|small-feature|refactor|spike|security-audit|dep-upgrade|full-project)\//;
14
+ /** Auto-mode milestone branch prefix: milestone/<MID>. */
15
+ export const MILESTONE_BRANCH_PREFIX = "milestone/";
@@ -0,0 +1,83 @@
1
+ import { execFileSync } from "node:child_process";
2
+ import { resolve } from "node:path";
3
+ import { resolveAmbientBrowserEngineResolution, resolveBrowserEngineResolution, } from "../browser-tools/engine/selection.js";
4
+ import { resolveGsdBrowserCliAvailability, resolveGsdBrowserDaemonStartInvocation, } from "../shared/gsd-browser-cli.js";
5
+ import { uatTypeIncludesBrowser } from "./uat-policy.js";
6
+ const DEFAULT_DAEMON_START_TIMEOUT_MS = 30_000;
7
+ function isEnvDisabled(value) {
8
+ if (!value)
9
+ return false;
10
+ const normalized = value.trim().toLowerCase();
11
+ return normalized === "0" || normalized === "false" || normalized === "off";
12
+ }
13
+ function isWarmUpDisabled(env = process.env) {
14
+ const value = env.GSD_BROWSER_WARMUP?.trim().toLowerCase();
15
+ return value === "0" || value === "false" || value === "off";
16
+ }
17
+ /** Active engine for warm-up: explicit env override, else session-committed ambient resolution. */
18
+ function resolveActiveBrowserEngine(projectRoot, env) {
19
+ if (env.GSD_BROWSER_ENGINE?.trim()) {
20
+ return resolveBrowserEngineResolution(env, projectRoot).engine;
21
+ }
22
+ return resolveAmbientBrowserEngineResolution(projectRoot).engine;
23
+ }
24
+ export function shouldWarmBrowserDaemonForUat(ctx) {
25
+ if (!uatTypeIncludesBrowser(ctx.uatType))
26
+ return false;
27
+ const env = ctx.env ?? process.env;
28
+ if (isWarmUpDisabled(env))
29
+ return false;
30
+ if (isEnvDisabled(env.GSD_BROWSER_MCP_ENABLED))
31
+ return false;
32
+ const availability = resolveGsdBrowserCliAvailability(env);
33
+ if (!availability.available)
34
+ return false;
35
+ const projectRoot = resolve(ctx.projectRoot);
36
+ return resolveActiveBrowserEngine(projectRoot, env) === "gsd-browser";
37
+ }
38
+ export function ensureBrowserDaemonStarted(projectRoot, options = {}) {
39
+ const env = options.env ?? process.env;
40
+ const availability = resolveGsdBrowserCliAvailability(env);
41
+ if (!availability.available) {
42
+ return { ok: false, error: availability.detail };
43
+ }
44
+ let invocation;
45
+ try {
46
+ invocation = resolveGsdBrowserDaemonStartInvocation(projectRoot, env);
47
+ }
48
+ catch (error) {
49
+ return {
50
+ ok: false,
51
+ error: error instanceof Error ? error.message : String(error),
52
+ };
53
+ }
54
+ try {
55
+ execFileSync(invocation.command, invocation.args, {
56
+ cwd: invocation.cwd,
57
+ env: { ...process.env, ...env, ...(invocation.env ?? {}) },
58
+ stdio: ["ignore", "pipe", "pipe"],
59
+ timeout: options.timeoutMs ?? DEFAULT_DAEMON_START_TIMEOUT_MS,
60
+ encoding: "utf-8",
61
+ });
62
+ return { ok: true };
63
+ }
64
+ catch (error) {
65
+ return {
66
+ ok: false,
67
+ error: error instanceof Error ? error.message : String(error),
68
+ };
69
+ }
70
+ }
71
+ /**
72
+ * Best-effort pre-warm of the gsd-browser session daemon before browser-backed
73
+ * run-uat dispatch. Returns an actionable stop reason when warm-up is required
74
+ * but fails; returns null when warm-up is skipped or succeeds.
75
+ */
76
+ export function prepareBrowserDaemonForUat(ctx) {
77
+ if (!shouldWarmBrowserDaemonForUat(ctx))
78
+ return null;
79
+ const result = ensureBrowserDaemonStarted(ctx.projectRoot, { env: ctx.env });
80
+ if (result.ok)
81
+ return null;
82
+ return `Cannot dispatch browser-backed run-uat: gsd-browser daemon failed to start (${result.error}). Ensure Chrome/Chromium is installed, run \`gsd-browser daemon health\` with the project session flags from .mcp.json, or set GSD_BROWSER_PATH to a Chromium binary.`;
83
+ }
@@ -1,8 +1,14 @@
1
1
  // Project/App: gsd-pi
2
2
  // File Purpose: Shared browser-observable UAT requirement and evidence detection.
3
- export const BROWSER_REQUIREMENT_RE = /\b(?:file:\/\/|localhost|playwright|chrome|screenshot|snapshot|browser_(?:assert|batch|find|verify|snapshot_refs))\b|\b(?:open|launch|navigate|load|visit|serve|start)\b.{0,80}\b(?:browser|page|localhost|file:\/\/)\b|\bbrowser\s+(?:check|session|test|uat|tool|automation|interaction|flow)\b/i;
3
+ import { BROWSER_EVIDENCE_SIGNAL_TOOL_NAMES } from "../shared/browser-contract.js";
4
+ // Alternation fragment over the contract's evidence-signal names, e.g.
5
+ // `browser_(?:assert|batch|...)`. The names are `browser_`-prefixed
6
+ // identifiers (pinned by tests/browser-contract.test.ts), so no escaping is
7
+ // needed.
8
+ const BROWSER_TOOL_SIGNAL = `browser_(?:${BROWSER_EVIDENCE_SIGNAL_TOOL_NAMES.map((name) => name.slice("browser_".length)).join("|")})`;
9
+ export const BROWSER_REQUIREMENT_RE = new RegExp(String.raw `\b(?:file://|localhost|playwright|chrome|screenshot|snapshot|${BROWSER_TOOL_SIGNAL})\b|\b(?:open|launch|navigate|load|visit|serve|start)\b.{0,80}\b(?:browser|page|localhost|file://)\b|\bbrowser\s+(?:check|session|test|uat|tool|automation|interaction|flow)\b`, "i");
4
10
  export const NO_BROWSER_EVIDENCE_RE = /\b(?:no|without|not|wasn'?t|isn'?t)\s+(?:automated\s+)?(?:live\s+)?browser(?:\s+(?:session|test|uat))?|\bno\s+automated\s+browser\b|\bnot\s+conducted\b/i;
5
- export const BROWSER_RUNTIME_RE = /\b(?:browser|playwright|chrome|camoufox|browser_(?:assert|batch|find|verify|snapshot_refs)|screenshot|snapshot|file:\/\/|localhost)\b/i;
11
+ export const BROWSER_RUNTIME_RE = new RegExp(String.raw `\b(?:browser|playwright|chrome|camoufox|${BROWSER_TOOL_SIGNAL}|screenshot|snapshot|file://|localhost)\b`, "i");
6
12
  export const BROWSER_ACTION_RE = /\b(?:open(?:ed)?|navigate(?:d)?|click(?:ed)?|type(?:d)?|reload(?:ed)?|capture(?:d)?|screenshot|snapshot)\b/i;
7
13
  export const BROWSER_ASSERTION_RE = /\b(?:assert(?:ed|ion)?|observed|confirmed|verified|expected|visible|text|count|label|strikethrough|localstorage|screenshot|snapshot|passed)\b/i;
8
14
  const NON_REQUIREMENT_BROWSER_HEADING_RE = /^(?:not\s+proven|not\s+covered|out\s+of\s+scope|deferred|follow-?ups?|known\s+limitations|notes\s+for\s+tester)\b/i;
@@ -8,9 +8,10 @@
8
8
  * `.gsd/CAPTURES.md`, not the worktree's local `.gsd/`.
9
9
  */
10
10
  import { existsSync, readFileSync, writeFileSync, mkdirSync } from "node:fs";
11
- import { join, resolve, sep } from "node:path";
11
+ import { join, resolve } from "node:path";
12
12
  import { randomUUID } from "node:crypto";
13
13
  import { gsdRoot } from "./paths.js";
14
+ import { projectRootFromWorktreePath } from "./worktree-root.js";
14
15
  // ─── Constants ────────────────────────────────────────────────────────────────
15
16
  const CAPTURES_FILENAME = "CAPTURES.md";
16
17
  const VALID_CLASSIFICATIONS = [
@@ -29,20 +30,9 @@ const VALID_CLASSIFICATIONS = [
29
30
  * directory that contains `.gsd/worktrees/` — that's the project root.
30
31
  */
31
32
  export function resolveCapturesPath(basePath) {
32
- const resolved = resolve(basePath);
33
- // Direct layout: /.gsd/worktrees/
34
- const worktreeMarker = `${sep}.gsd${sep}worktrees${sep}`;
35
- let idx = resolved.indexOf(worktreeMarker);
36
- if (idx === -1) {
37
- // Symlink-resolved layout: /.gsd/projects/<hash>/worktrees/
38
- const symlinkRe = new RegExp(`\\${sep}\\.gsd\\${sep}projects\\${sep}[a-f0-9]+\\${sep}worktrees\\${sep}`);
39
- const match = resolved.match(symlinkRe);
40
- if (match && match.index !== undefined)
41
- idx = match.index;
42
- }
43
- if (idx !== -1) {
44
- // basePath is inside a worktree — resolve to project root
45
- const projectRoot = resolved.slice(0, idx);
33
+ // If basePath is inside a worktree, resolve to the project root.
34
+ const projectRoot = projectRootFromWorktreePath(resolve(basePath));
35
+ if (projectRoot) {
46
36
  return join(projectRoot, ".gsd", CAPTURES_FILENAME);
47
37
  }
48
38
  return join(gsdRoot(basePath), CAPTURES_FILENAME);
@@ -2,12 +2,13 @@
2
2
  // File Purpose: Closeout git failure discovery, retry, and manual resolution helpers.
3
3
  import { execFileSync } from "node:child_process";
4
4
  import { existsSync, realpathSync } from "node:fs";
5
- import { isAbsolute, join, resolve } from "node:path";
5
+ import { isAbsolute, resolve } from "node:path";
6
6
  import { GIT_NO_PROMPT_ENV } from "./git-constants.js";
7
7
  import { runTurnGitAction } from "./git-service.js";
8
8
  import { _getAdapter, upsertTurnGitTransaction } from "./gsd-db.js";
9
9
  import { probeGitConflictState } from "./git-conflict-state.js";
10
10
  import { parseUnitId } from "./unit-id.js";
11
+ import { worktreePathFor } from "./worktree-placement.js";
11
12
  function parseMetadata(value) {
12
13
  if (typeof value !== "string" || !value.trim())
13
14
  return {};
@@ -121,7 +122,7 @@ export function resolveCloseoutRecoveryBasePath(projectRoot, record) {
121
122
  const parsed = parseUnitId(record.unitId);
122
123
  const milestoneId = parsed.milestone ?? (/^M\d+(?:-[a-z0-9]{6})?/.exec(record.unitId)?.[0] ?? "");
123
124
  if (milestoneId) {
124
- const worktreePath = existingRealPath(join(projectRoot, ".gsd", "worktrees", milestoneId));
125
+ const worktreePath = existingRealPath(worktreePathFor(projectRoot, milestoneId));
125
126
  if (worktreePath)
126
127
  return worktreePath;
127
128
  }