@opengsd/gsd-pi 1.2.0-dev.955e4da0 → 1.2.0-dev.d6c5343c

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 (424) 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 +14 -34
  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/GSD-WORKFLOW.md +5 -4
  11. package/dist/resources/extensions/async-jobs/async-bash-tool.js +30 -64
  12. package/dist/resources/extensions/async-jobs/await-tool.js +80 -12
  13. package/dist/resources/extensions/async-jobs/index.js +65 -0
  14. package/dist/resources/extensions/async-jobs/job-manager.js +12 -1
  15. package/dist/resources/extensions/bg-shell/bg-shell-command.js +6 -6
  16. package/dist/resources/extensions/bg-shell/bg-shell-tool.js +10 -7
  17. package/dist/resources/extensions/bg-shell/overlay.js +9 -6
  18. package/dist/resources/extensions/bg-shell/process-manager.js +54 -25
  19. package/dist/resources/extensions/bg-shell/readiness-detector.js +11 -0
  20. package/dist/resources/extensions/bg-shell/utilities.js +3 -0
  21. package/dist/resources/extensions/browser-tools/engine/managed-gsd-browser.js +209 -88
  22. package/dist/resources/extensions/browser-tools/engine/selection.js +73 -5
  23. package/dist/resources/extensions/browser-tools/index.js +69 -12
  24. package/dist/resources/extensions/claude-code-cli/stream-adapter.js +30 -4
  25. package/dist/resources/extensions/gsd/auto/custom-verify-retry-store.js +17 -2
  26. package/dist/resources/extensions/gsd/auto/detect-stuck.js +33 -13
  27. package/dist/resources/extensions/gsd/auto/dispatch-history.js +105 -0
  28. package/dist/resources/extensions/gsd/auto/dispatch-key.js +37 -0
  29. package/dist/resources/extensions/gsd/auto/loop.js +4 -1
  30. package/dist/resources/extensions/gsd/auto/orchestrator.js +61 -44
  31. package/dist/resources/extensions/gsd/auto/phases.js +2 -2
  32. package/dist/resources/extensions/gsd/auto-direct-dispatch.js +8 -32
  33. package/dist/resources/extensions/gsd/auto-dispatch.js +40 -57
  34. package/dist/resources/extensions/gsd/auto-model-selection.js +25 -6
  35. package/dist/resources/extensions/gsd/auto-post-unit.js +23 -8
  36. package/dist/resources/extensions/gsd/auto-prompts.js +81 -19
  37. package/dist/resources/extensions/gsd/auto-start.js +18 -15
  38. package/dist/resources/extensions/gsd/auto-tool-tracking.js +18 -0
  39. package/dist/resources/extensions/gsd/auto-unit-tool-scope.js +12 -20
  40. package/dist/resources/extensions/gsd/auto-verification.js +9 -28
  41. package/dist/resources/extensions/gsd/auto-worktree.js +30 -90
  42. package/dist/resources/extensions/gsd/auto.js +4 -13
  43. package/dist/resources/extensions/gsd/bootstrap/agent-end-recovery.js +3 -2
  44. package/dist/resources/extensions/gsd/bootstrap/dynamic-tools.js +23 -6
  45. package/dist/resources/extensions/gsd/bootstrap/register-extension.js +19 -0
  46. package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +212 -48
  47. package/dist/resources/extensions/gsd/bootstrap/write-gate.js +303 -77
  48. package/dist/resources/extensions/gsd/branch-patterns.js +2 -0
  49. package/dist/resources/extensions/gsd/browser-daemon-auto-prep.js +83 -0
  50. package/dist/resources/extensions/gsd/browser-evidence.js +8 -2
  51. package/dist/resources/extensions/gsd/captures.js +4 -6
  52. package/dist/resources/extensions/gsd/consent-question.js +337 -0
  53. package/dist/resources/extensions/gsd/consent-verdict.js +63 -0
  54. package/dist/resources/extensions/gsd/constants.js +0 -2
  55. package/dist/resources/extensions/gsd/crash-recovery.js +4 -12
  56. package/dist/resources/extensions/gsd/db/queries.js +26 -0
  57. package/dist/resources/extensions/gsd/dispatch-guard.js +10 -35
  58. package/dist/resources/extensions/gsd/doctor-environment.js +2 -6
  59. package/dist/resources/extensions/gsd/doctor-format.js +9 -6
  60. package/dist/resources/extensions/gsd/doctor-runtime-checks.js +13 -15
  61. package/dist/resources/extensions/gsd/engine-hook-contract.js +70 -0
  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/files.js +33 -19
  65. package/dist/resources/extensions/gsd/guidance.js +158 -0
  66. package/dist/resources/extensions/gsd/guided-flow.js +17 -2
  67. package/dist/resources/extensions/gsd/markdown-renderer.js +10 -0
  68. package/dist/resources/extensions/gsd/mcp-filter.js +2 -19
  69. package/dist/resources/extensions/gsd/mcp-tool-name.js +5 -13
  70. package/dist/resources/extensions/gsd/memory-consolidation-scanner.js +1 -1
  71. package/dist/resources/extensions/gsd/migrate/safety.js +4 -1
  72. package/dist/resources/extensions/gsd/milestone-closeout.js +13 -23
  73. package/dist/resources/extensions/gsd/notification-store.js +11 -4
  74. package/dist/resources/extensions/gsd/parallel-monitor-overlay.js +6 -4
  75. package/dist/resources/extensions/gsd/parsers-legacy.js +16 -4
  76. package/dist/resources/extensions/gsd/paths.js +27 -0
  77. package/dist/resources/extensions/gsd/pre-execution-checks.js +91 -3
  78. package/dist/resources/extensions/gsd/preferences-models.js +14 -48
  79. package/dist/resources/extensions/gsd/prompts/complete-slice.md +2 -2
  80. package/dist/resources/extensions/gsd/prompts/plan-slice.md +1 -1
  81. package/dist/resources/extensions/gsd/prompts/refine-slice.md +1 -1
  82. package/dist/resources/extensions/gsd/prompts/replan-slice.md +1 -1
  83. package/dist/resources/extensions/gsd/prompts/run-uat.md +6 -4
  84. package/dist/resources/extensions/gsd/prompts/system.md +5 -2
  85. package/dist/resources/extensions/gsd/provider-error-guidance.js +1 -5
  86. package/dist/resources/extensions/gsd/provider-switch-observer.js +1 -1
  87. package/dist/resources/extensions/gsd/publication.js +87 -0
  88. package/dist/resources/extensions/gsd/reactive-graph.js +8 -1
  89. package/dist/resources/extensions/gsd/recovery-classification.js +37 -94
  90. package/dist/resources/extensions/gsd/safety/destructive-confirmation.js +108 -0
  91. package/dist/resources/extensions/gsd/state.js +6 -20
  92. package/dist/resources/extensions/gsd/stop-notice.js +57 -0
  93. package/dist/resources/extensions/gsd/tool-presentation-plan.js +4 -4
  94. package/dist/resources/extensions/gsd/tool-surface-readiness.js +56 -0
  95. package/dist/resources/extensions/gsd/tools/complete-slice.js +20 -10
  96. package/dist/resources/extensions/gsd/tools/exec-tool.js +9 -7
  97. package/dist/resources/extensions/gsd/tools/plan-slice.js +12 -6
  98. package/dist/resources/extensions/gsd/uat-policy.js +42 -16
  99. package/dist/resources/extensions/gsd/unit-closeout.js +138 -0
  100. package/dist/resources/extensions/gsd/unit-context-composer.js +74 -1
  101. package/dist/resources/extensions/gsd/unit-context-manifest.js +4 -27
  102. package/dist/resources/extensions/gsd/unit-registry.js +337 -0
  103. package/dist/resources/extensions/gsd/unit-tool-contracts.js +9 -182
  104. package/dist/resources/extensions/gsd/verdict-parser.js +1 -1
  105. package/dist/resources/extensions/gsd/web-app-uat.js +45 -8
  106. package/dist/resources/extensions/gsd/workflow-tool-surface.js +1 -1
  107. package/dist/resources/extensions/gsd/worktree-git-recovery.js +15 -9
  108. package/dist/resources/extensions/gsd/worktree-lifecycle.js +3 -2
  109. package/dist/resources/extensions/gsd/worktree-root.js +11 -0
  110. package/dist/resources/extensions/gsd/worktree-session-state.js +4 -5
  111. package/dist/resources/extensions/search-the-web/native-search.js +5 -3
  112. package/dist/resources/extensions/shared/browser-contract.js +59 -0
  113. package/dist/resources/extensions/shared/gsd-browser-cli.js +96 -5
  114. package/dist/resources/shared/package.json +3 -0
  115. package/dist/resources/skills/create-skill/references/executable-code.md +1 -1
  116. package/dist/resources/skills/create-skill/workflows/add-reference.md +8 -3
  117. package/dist/resources/skills/create-skill/workflows/add-script.md +4 -2
  118. package/dist/resources/skills/create-skill/workflows/add-template.md +3 -1
  119. package/dist/resources/skills/create-skill/workflows/add-workflow.md +8 -3
  120. package/dist/resources/skills/create-skill/workflows/upgrade-to-router.md +10 -5
  121. package/dist/resources/skills/create-skill/workflows/verify-skill.md +9 -4
  122. package/dist/resources/skills/spike-wrap-up/SKILL.md +9 -9
  123. package/dist/tsconfig.extensions.tsbuildinfo +1 -1
  124. package/dist/web/standalone/.next/BUILD_ID +1 -1
  125. package/dist/web/standalone/.next/app-path-routes-manifest.json +12 -12
  126. package/dist/web/standalone/.next/build-manifest.json +3 -3
  127. package/dist/web/standalone/.next/prerender-manifest.json +3 -3
  128. package/dist/web/standalone/.next/react-loadable-manifest.json +1 -1
  129. package/dist/web/standalone/.next/server/app/_global-error.html +1 -1
  130. package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
  131. package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  132. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
  133. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
  134. package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  135. package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  136. package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  137. package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
  138. package/dist/web/standalone/.next/server/app/_not-found.rsc +1 -1
  139. package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
  140. package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  141. package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +1 -1
  142. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  143. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  144. package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
  145. package/dist/web/standalone/.next/server/app/api/update/route.js +1 -1
  146. package/dist/web/standalone/.next/server/app/api/update/route.js.nft.json +1 -1
  147. package/dist/web/standalone/.next/server/app/index.html +1 -1
  148. package/dist/web/standalone/.next/server/app/index.rsc +1 -1
  149. package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +1 -1
  150. package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +1 -1
  151. package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
  152. package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +1 -1
  153. package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
  154. package/dist/web/standalone/.next/server/app-paths-manifest.json +12 -12
  155. package/dist/web/standalone/.next/server/chunks/5124.js +1 -1
  156. package/dist/web/standalone/.next/server/chunks/8357.js +1 -1
  157. package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
  158. package/dist/web/standalone/.next/server/middleware-react-loadable-manifest.js +1 -1
  159. package/dist/web/standalone/.next/server/pages/404.html +1 -1
  160. package/dist/web/standalone/.next/server/pages/500.html +1 -1
  161. package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
  162. package/dist/web/standalone/.next/static/chunks/{796.cf859a427a2cb2ac.js → 796.e0bdc932325d7e03.js} +1 -1
  163. package/dist/web/standalone/.next/static/chunks/{webpack-fbea77b5f9953368.js → webpack-f0285ce91d4ec9ef.js} +1 -1
  164. package/dist/web/standalone/package.json +1 -1
  165. package/dist/worktree-cli.js +3 -6
  166. package/dist/worktree-status-banner.js +7 -15
  167. package/package.json +1 -1
  168. package/packages/cloud-mcp-gateway/package.json +2 -2
  169. package/packages/contracts/dist/rpc.d.ts +1 -0
  170. package/packages/contracts/dist/rpc.d.ts.map +1 -1
  171. package/packages/contracts/dist/rpc.js.map +1 -1
  172. package/packages/contracts/dist/workflow.d.ts +4 -0
  173. package/packages/contracts/dist/workflow.d.ts.map +1 -1
  174. package/packages/contracts/dist/workflow.js.map +1 -1
  175. package/packages/contracts/package.json +1 -1
  176. package/packages/daemon/package.json +4 -4
  177. package/packages/gsd-agent-core/package.json +5 -5
  178. package/packages/gsd-agent-modes/dist/modes/interactive/components/tool-execution.d.ts +5 -0
  179. package/packages/gsd-agent-modes/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
  180. package/packages/gsd-agent-modes/dist/modes/interactive/components/tool-execution.js +5 -0
  181. package/packages/gsd-agent-modes/dist/modes/interactive/components/tool-execution.js.map +1 -1
  182. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-controller.d.ts.map +1 -1
  183. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-controller.js +7 -0
  184. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-controller.js.map +1 -1
  185. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/input-controller.d.ts.map +1 -1
  186. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/input-controller.js +8 -1
  187. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/input-controller.js.map +1 -1
  188. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-chat-render.d.ts.map +1 -1
  189. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-chat-render.js +11 -1
  190. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-chat-render.js.map +1 -1
  191. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-selectors-auth.d.ts.map +1 -1
  192. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-selectors-auth.js +4 -4
  193. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-selectors-auth.js.map +1 -1
  194. package/packages/gsd-agent-modes/dist/modes/rpc/rpc-mode.d.ts.map +1 -1
  195. package/packages/gsd-agent-modes/dist/modes/rpc/rpc-mode.js +3 -1
  196. package/packages/gsd-agent-modes/dist/modes/rpc/rpc-mode.js.map +1 -1
  197. package/packages/gsd-agent-modes/package.json +7 -7
  198. package/packages/mcp-server/dist/cli.js +6 -3
  199. package/packages/mcp-server/dist/cli.js.map +1 -1
  200. package/packages/mcp-server/dist/workflow-tools.d.ts +8 -0
  201. package/packages/mcp-server/dist/workflow-tools.d.ts.map +1 -1
  202. package/packages/mcp-server/dist/workflow-tools.js +17 -1
  203. package/packages/mcp-server/dist/workflow-tools.js.map +1 -1
  204. package/packages/mcp-server/package.json +3 -3
  205. package/packages/native/package.json +1 -1
  206. package/packages/pi-agent-core/dist/harness/env/nodejs.d.ts +1 -0
  207. package/packages/pi-agent-core/dist/harness/env/nodejs.d.ts.map +1 -1
  208. package/packages/pi-agent-core/dist/harness/env/nodejs.js +34 -3
  209. package/packages/pi-agent-core/dist/harness/env/nodejs.js.map +1 -1
  210. package/packages/pi-agent-core/dist/index.d.ts +1 -0
  211. package/packages/pi-agent-core/dist/index.d.ts.map +1 -1
  212. package/packages/pi-agent-core/dist/index.js +3 -0
  213. package/packages/pi-agent-core/dist/index.js.map +1 -1
  214. package/packages/pi-agent-core/package.json +1 -1
  215. package/packages/pi-ai/README.md +1 -0
  216. package/packages/pi-ai/dist/image-models.generated.d.ts +2 -2
  217. package/packages/pi-ai/dist/image-models.generated.js +6 -6
  218. package/packages/pi-ai/dist/image-models.generated.js.map +1 -1
  219. package/packages/pi-ai/dist/models.generated.d.ts +35 -125
  220. package/packages/pi-ai/dist/models.generated.d.ts.map +1 -1
  221. package/packages/pi-ai/dist/models.generated.js +46 -120
  222. package/packages/pi-ai/dist/models.generated.js.map +1 -1
  223. package/packages/pi-ai/package.json +3 -2
  224. package/packages/pi-coding-agent/dist/core/auth-storage.d.ts +2 -2
  225. package/packages/pi-coding-agent/dist/core/auth-storage.d.ts.map +1 -1
  226. package/packages/pi-coding-agent/dist/core/auth-storage.js +19 -13
  227. package/packages/pi-coding-agent/dist/core/auth-storage.js.map +1 -1
  228. package/packages/pi-coding-agent/dist/core/provider-readiness.d.ts.map +1 -1
  229. package/packages/pi-coding-agent/dist/core/provider-readiness.js +13 -6
  230. package/packages/pi-coding-agent/dist/core/provider-readiness.js.map +1 -1
  231. package/packages/pi-coding-agent/dist/core/tools/bash.d.ts +11 -0
  232. package/packages/pi-coding-agent/dist/core/tools/bash.d.ts.map +1 -1
  233. package/packages/pi-coding-agent/dist/core/tools/bash.js +53 -11
  234. package/packages/pi-coding-agent/dist/core/tools/bash.js.map +1 -1
  235. package/packages/pi-coding-agent/dist/index.d.ts +1 -1
  236. package/packages/pi-coding-agent/dist/index.d.ts.map +1 -1
  237. package/packages/pi-coding-agent/dist/index.js +1 -1
  238. package/packages/pi-coding-agent/dist/index.js.map +1 -1
  239. package/packages/pi-coding-agent/dist/utils/shell.d.ts +28 -2
  240. package/packages/pi-coding-agent/dist/utils/shell.d.ts.map +1 -1
  241. package/packages/pi-coding-agent/dist/utils/shell.js +56 -10
  242. package/packages/pi-coding-agent/dist/utils/shell.js.map +1 -1
  243. package/packages/pi-coding-agent/package.json +7 -7
  244. package/packages/pi-tui/dist/tui.d.ts.map +1 -1
  245. package/packages/pi-tui/dist/tui.js +9 -0
  246. package/packages/pi-tui/dist/tui.js.map +1 -1
  247. package/packages/pi-tui/package.json +2 -2
  248. package/packages/rpc-client/package.json +2 -2
  249. package/pkg/package.json +1 -1
  250. package/src/resources/GSD-WORKFLOW.md +5 -4
  251. package/src/resources/extensions/async-jobs/async-bash-cancel.test.ts +360 -0
  252. package/src/resources/extensions/async-jobs/async-bash-tool.ts +33 -56
  253. package/src/resources/extensions/async-jobs/await-tool.test.ts +139 -0
  254. package/src/resources/extensions/async-jobs/await-tool.ts +82 -12
  255. package/src/resources/extensions/async-jobs/index.ts +79 -0
  256. package/src/resources/extensions/async-jobs/job-manager.ts +21 -1
  257. package/src/resources/extensions/bg-shell/bg-shell-command.ts +6 -6
  258. package/src/resources/extensions/bg-shell/bg-shell-tool.ts +10 -6
  259. package/src/resources/extensions/bg-shell/overlay.ts +9 -5
  260. package/src/resources/extensions/bg-shell/process-manager.ts +50 -25
  261. package/src/resources/extensions/bg-shell/readiness-detector.ts +12 -0
  262. package/src/resources/extensions/bg-shell/tests/lifecycle-and-utilities.test.ts +48 -1
  263. package/src/resources/extensions/bg-shell/utilities.ts +3 -0
  264. package/src/resources/extensions/browser-tools/engine/managed-gsd-browser.ts +265 -98
  265. package/src/resources/extensions/browser-tools/engine/selection.ts +90 -4
  266. package/src/resources/extensions/browser-tools/index.ts +71 -13
  267. package/src/resources/extensions/browser-tools/tests/browser-engine-selection.test.mjs +83 -13
  268. package/src/resources/extensions/browser-tools/tests/gsd-browser-launch-config.test.mjs +29 -1
  269. package/src/resources/extensions/browser-tools/tests/managed-gsd-browser-tools.test.mjs +136 -0
  270. package/src/resources/extensions/claude-code-cli/stream-adapter.ts +34 -4
  271. package/src/resources/extensions/gsd/auto/custom-verify-retry-store.ts +21 -3
  272. package/src/resources/extensions/gsd/auto/detect-stuck.ts +32 -9
  273. package/src/resources/extensions/gsd/auto/dispatch-history.ts +152 -0
  274. package/src/resources/extensions/gsd/auto/dispatch-key.ts +39 -0
  275. package/src/resources/extensions/gsd/auto/loop.ts +4 -1
  276. package/src/resources/extensions/gsd/auto/orchestrator.ts +70 -46
  277. package/src/resources/extensions/gsd/auto/phases.ts +2 -2
  278. package/src/resources/extensions/gsd/auto-direct-dispatch.ts +8 -32
  279. package/src/resources/extensions/gsd/auto-dispatch.ts +38 -52
  280. package/src/resources/extensions/gsd/auto-model-selection.ts +25 -5
  281. package/src/resources/extensions/gsd/auto-post-unit.ts +25 -8
  282. package/src/resources/extensions/gsd/auto-prompts.ts +118 -35
  283. package/src/resources/extensions/gsd/auto-start.ts +18 -17
  284. package/src/resources/extensions/gsd/auto-tool-tracking.ts +19 -0
  285. package/src/resources/extensions/gsd/auto-unit-tool-scope.ts +14 -21
  286. package/src/resources/extensions/gsd/auto-verification.ts +8 -26
  287. package/src/resources/extensions/gsd/auto-worktree.ts +30 -93
  288. package/src/resources/extensions/gsd/auto.ts +8 -15
  289. package/src/resources/extensions/gsd/bootstrap/agent-end-recovery.ts +3 -5
  290. package/src/resources/extensions/gsd/bootstrap/dynamic-tools.ts +23 -6
  291. package/src/resources/extensions/gsd/bootstrap/register-extension.ts +24 -0
  292. package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +251 -47
  293. package/src/resources/extensions/gsd/bootstrap/write-gate.ts +352 -84
  294. package/src/resources/extensions/gsd/branch-patterns.ts +3 -0
  295. package/src/resources/extensions/gsd/browser-daemon-auto-prep.ts +108 -0
  296. package/src/resources/extensions/gsd/browser-evidence.ts +18 -2
  297. package/src/resources/extensions/gsd/captures.ts +4 -6
  298. package/src/resources/extensions/gsd/consent-question.ts +416 -0
  299. package/src/resources/extensions/gsd/consent-verdict.ts +86 -0
  300. package/src/resources/extensions/gsd/constants.ts +0 -3
  301. package/src/resources/extensions/gsd/crash-recovery.ts +3 -9
  302. package/src/resources/extensions/gsd/db/queries.ts +37 -0
  303. package/src/resources/extensions/gsd/dispatch-guard.ts +8 -31
  304. package/src/resources/extensions/gsd/doctor-environment.ts +2 -7
  305. package/src/resources/extensions/gsd/doctor-format.ts +12 -7
  306. package/src/resources/extensions/gsd/doctor-runtime-checks.ts +13 -15
  307. package/src/resources/extensions/gsd/engine-hook-contract.ts +79 -0
  308. package/src/resources/extensions/gsd/error-classifier.ts +11 -0
  309. package/src/resources/extensions/gsd/exec-sandbox.ts +49 -9
  310. package/src/resources/extensions/gsd/files.ts +33 -12
  311. package/src/resources/extensions/gsd/guidance.ts +217 -0
  312. package/src/resources/extensions/gsd/guided-flow.ts +16 -2
  313. package/src/resources/extensions/gsd/markdown-renderer.ts +11 -0
  314. package/src/resources/extensions/gsd/mcp-filter.ts +2 -23
  315. package/src/resources/extensions/gsd/mcp-tool-name.ts +6 -11
  316. package/src/resources/extensions/gsd/memory-consolidation-scanner.ts +1 -1
  317. package/src/resources/extensions/gsd/migrate/safety.ts +4 -1
  318. package/src/resources/extensions/gsd/milestone-closeout.ts +13 -23
  319. package/src/resources/extensions/gsd/notification-store.ts +26 -3
  320. package/src/resources/extensions/gsd/parallel-monitor-overlay.ts +6 -4
  321. package/src/resources/extensions/gsd/parsers-legacy.ts +16 -4
  322. package/src/resources/extensions/gsd/paths.ts +33 -0
  323. package/src/resources/extensions/gsd/pre-execution-checks.ts +109 -3
  324. package/src/resources/extensions/gsd/preferences-models.ts +12 -47
  325. package/src/resources/extensions/gsd/prompts/complete-slice.md +2 -2
  326. package/src/resources/extensions/gsd/prompts/plan-slice.md +1 -1
  327. package/src/resources/extensions/gsd/prompts/refine-slice.md +1 -1
  328. package/src/resources/extensions/gsd/prompts/replan-slice.md +1 -1
  329. package/src/resources/extensions/gsd/prompts/run-uat.md +6 -4
  330. package/src/resources/extensions/gsd/prompts/system.md +5 -2
  331. package/src/resources/extensions/gsd/provider-error-guidance.ts +4 -9
  332. package/src/resources/extensions/gsd/provider-switch-observer.ts +1 -1
  333. package/src/resources/extensions/gsd/publication.ts +122 -0
  334. package/src/resources/extensions/gsd/reactive-graph.ts +11 -1
  335. package/src/resources/extensions/gsd/recovery-classification.ts +42 -96
  336. package/src/resources/extensions/gsd/safety/destructive-confirmation.ts +134 -0
  337. package/src/resources/extensions/gsd/state.ts +9 -21
  338. package/src/resources/extensions/gsd/stop-notice.ts +75 -0
  339. package/src/resources/extensions/gsd/tests/auto-model-selection.test.ts +22 -0
  340. package/src/resources/extensions/gsd/tests/auto-orchestrator.test.ts +101 -26
  341. package/src/resources/extensions/gsd/tests/browser-automation-contract-fixture.ts +39 -0
  342. package/src/resources/extensions/gsd/tests/browser-contract.test.ts +44 -0
  343. package/src/resources/extensions/gsd/tests/browser-daemon-auto-prep.test.ts +144 -0
  344. package/src/resources/extensions/gsd/tests/checkout-branch-stash-guard.test.ts +66 -1
  345. package/src/resources/extensions/gsd/tests/clear-stale-autostart.test.ts +22 -0
  346. package/src/resources/extensions/gsd/tests/commands-verdict.test.ts +8 -7
  347. package/src/resources/extensions/gsd/tests/complete-slice-verification-gate.test.ts +42 -0
  348. package/src/resources/extensions/gsd/tests/consent-question.test.ts +336 -0
  349. package/src/resources/extensions/gsd/tests/custom-verify-retry-store.test.ts +67 -0
  350. package/src/resources/extensions/gsd/tests/deep-project-auto-loop.test.ts +10 -10
  351. package/src/resources/extensions/gsd/tests/destructive-confirmation.test.ts +303 -0
  352. package/src/resources/extensions/gsd/tests/dispatch-history.test.ts +273 -0
  353. package/src/resources/extensions/gsd/tests/dispatch-run-uat-browser-tools.test.ts +2 -1
  354. package/src/resources/extensions/gsd/tests/dynamic-bash-no-cap.test.ts +132 -0
  355. package/src/resources/extensions/gsd/tests/engine-hook-contract.test.ts +148 -0
  356. package/src/resources/extensions/gsd/tests/exec-graceful-kill.test.ts +193 -0
  357. package/src/resources/extensions/gsd/tests/exec-tool.test.ts +29 -1
  358. package/src/resources/extensions/gsd/tests/extension-bootstrap-isolation.test.ts +35 -1
  359. package/src/resources/extensions/gsd/tests/gsd-db.test.ts +27 -0
  360. package/src/resources/extensions/gsd/tests/guidance.test.ts +148 -0
  361. package/src/resources/extensions/gsd/tests/integration/auto-worktree-milestone-merge.test.ts +53 -11
  362. package/src/resources/extensions/gsd/tests/integration/auto-worktree.test.ts +73 -58
  363. package/src/resources/extensions/gsd/tests/integration/gsd-integration-fixture.ts +80 -0
  364. package/src/resources/extensions/gsd/tests/integration/run-uat.test.ts +199 -0
  365. package/src/resources/extensions/gsd/tests/mcp-project-config.test.ts +3 -1
  366. package/src/resources/extensions/gsd/tests/model-unittype-mapping.test.ts +32 -1
  367. package/src/resources/extensions/gsd/tests/notification-store.test.ts +32 -0
  368. package/src/resources/extensions/gsd/tests/oauth-api-model-routing.test.ts +167 -0
  369. package/src/resources/extensions/gsd/tests/parallel-research-dispatch.test.ts +18 -0
  370. package/src/resources/extensions/gsd/tests/parsers-legacy-importers.test.ts +139 -0
  371. package/src/resources/extensions/gsd/tests/pre-execution-checks.test.ts +193 -1
  372. package/src/resources/extensions/gsd/tests/prompt-db.test.ts +124 -6
  373. package/src/resources/extensions/gsd/tests/provider-error-guidance.test.ts +3 -3
  374. package/src/resources/extensions/gsd/tests/publication.test.ts +120 -0
  375. package/src/resources/extensions/gsd/tests/register-hooks-depth-verification.test.ts +157 -0
  376. package/src/resources/extensions/gsd/tests/runtime-invariant-modules.test.ts +1 -0
  377. package/src/resources/extensions/gsd/tests/stop-notice.test.ts +70 -0
  378. package/src/resources/extensions/gsd/tests/token-tool-gating.test.ts +76 -0
  379. package/src/resources/extensions/gsd/tests/tool-invocation-error-loop-break.test.ts +8 -0
  380. package/src/resources/extensions/gsd/tests/tool-surface-readiness.test.ts +155 -0
  381. package/src/resources/extensions/gsd/tests/uat-policy.test.ts +112 -29
  382. package/src/resources/extensions/gsd/tests/unit-closeout.test.ts +209 -0
  383. package/src/resources/extensions/gsd/tests/unit-context-composer.test.ts +67 -2
  384. package/src/resources/extensions/gsd/tests/unit-registry.test.ts +163 -0
  385. package/src/resources/extensions/gsd/tests/web-app-uat.test.ts +44 -1
  386. package/src/resources/extensions/gsd/tests/workflow-mcp.test.ts +2 -2
  387. package/src/resources/extensions/gsd/tests/workflow-tool-executors.test.ts +2 -2
  388. package/src/resources/extensions/gsd/tests/write-gate-seam.test.ts +358 -0
  389. package/src/resources/extensions/gsd/tests/write-gate.test.ts +67 -1
  390. package/src/resources/extensions/gsd/tool-presentation-plan.ts +4 -4
  391. package/src/resources/extensions/gsd/tool-surface-readiness.ts +76 -0
  392. package/src/resources/extensions/gsd/tools/complete-slice.ts +20 -10
  393. package/src/resources/extensions/gsd/tools/exec-tool.ts +8 -7
  394. package/src/resources/extensions/gsd/tools/plan-slice.ts +12 -6
  395. package/src/resources/extensions/gsd/uat-policy.ts +62 -16
  396. package/src/resources/extensions/gsd/unit-closeout.ts +201 -0
  397. package/src/resources/extensions/gsd/unit-context-composer.ts +111 -1
  398. package/src/resources/extensions/gsd/unit-context-manifest.ts +4 -28
  399. package/src/resources/extensions/gsd/unit-registry.ts +412 -0
  400. package/src/resources/extensions/gsd/unit-tool-contracts.ts +27 -192
  401. package/src/resources/extensions/gsd/verdict-parser.ts +1 -1
  402. package/src/resources/extensions/gsd/web-app-uat.ts +51 -8
  403. package/src/resources/extensions/gsd/workflow-tool-surface.ts +4 -1
  404. package/src/resources/extensions/gsd/worktree-git-recovery.ts +15 -9
  405. package/src/resources/extensions/gsd/worktree-lifecycle.ts +3 -8
  406. package/src/resources/extensions/gsd/worktree-root.ts +12 -0
  407. package/src/resources/extensions/gsd/worktree-session-state.ts +3 -5
  408. package/src/resources/extensions/search-the-web/native-search.ts +5 -3
  409. package/src/resources/extensions/shared/browser-contract.ts +66 -0
  410. package/src/resources/extensions/shared/gsd-browser-cli.ts +119 -5
  411. package/src/resources/shared/package.json +3 -0
  412. package/src/resources/skills/create-skill/references/executable-code.md +1 -1
  413. package/src/resources/skills/create-skill/workflows/add-reference.md +8 -3
  414. package/src/resources/skills/create-skill/workflows/add-script.md +4 -2
  415. package/src/resources/skills/create-skill/workflows/add-template.md +3 -1
  416. package/src/resources/skills/create-skill/workflows/add-workflow.md +8 -3
  417. package/src/resources/skills/create-skill/workflows/upgrade-to-router.md +10 -5
  418. package/src/resources/skills/create-skill/workflows/verify-skill.md +9 -4
  419. package/src/resources/skills/spike-wrap-up/SKILL.md +9 -9
  420. package/dist/resources/extensions/gsd/user-input-boundary.js +0 -218
  421. package/src/resources/extensions/gsd/tests/user-input-boundary.test.ts +0 -173
  422. package/src/resources/extensions/gsd/user-input-boundary.ts +0 -216
  423. /package/dist/web/standalone/.next/static/{C24pqUd-aru-l0Dp0gLZP → jmTLg6xZmAuq_LIqKOxrH}/_buildManifest.js +0 -0
  424. /package/dist/web/standalone/.next/static/{C24pqUd-aru-l0Dp0gLZP → jmTLg6xZmAuq_LIqKOxrH}/_ssgManifest.js +0 -0
@@ -13,7 +13,8 @@ import type { GSDEcosystemBeforeAgentStartHandler } from "../ecosystem/gsd-exten
13
13
  import { updateSnapshot } from "../ecosystem/gsd-extension-api.js";
14
14
 
15
15
  import { buildMilestoneFileName, clearPathCache, milestonesDir, resolveMilestonePath, resolveSliceFile, resolveSlicePath } from "../paths.js";
16
- import { applyAskUserQuestionsGateResult, canonicalToolName, clearDiscussionFlowState, formatPendingAskUserQuestionsGateMessage, isApprovalGateVerifiedInSnapshot, isMilestoneDepthVerified, isMilestoneDepthVerifiedInSnapshot, isQueuePhaseActive, loadWriteGateSnapshot, markApprovalGateVerified, markDepthVerified, refreshWriteGateStateFromDisk, resetWriteGateState, shouldBlockContextWrite, shouldBlockPlanningUnit, shouldBlockQueueExecution, shouldBlockWorktreeWrite, isGateQuestionId, setPendingGate, clearPendingGate, getPendingGate, shouldBlockPendingGate, shouldBlockPendingGateBash, extractDepthVerificationMilestoneId } from "./write-gate.js";
16
+ import { applyAskUserQuestionsGateResult, clearDiscussionFlowState, formatPendingAskUserQuestionsGateMessage, hostWriteGateAdapter, isApprovalGateVerifiedInSnapshot, isDepthConfirmationAnswer, isMilestoneDepthVerified, isMilestoneDepthVerifiedInSnapshot, isQueuePhaseActive, resetWriteGateState, shouldBlockContextWrite, shouldBlockPlanningUnit, shouldBlockQueueExecution, shouldBlockWorktreeWrite, isGateQuestionId, getPendingGate, shouldBlockPendingGate, shouldBlockPendingGateBash, extractDepthVerificationMilestoneId } from "./write-gate.js";
17
+ import { canonicalToolName } from "../engine-hook-contract.js";
17
18
  import { resolveManifest } from "../unit-context-manifest.js";
18
19
  import { isBlockedStateFile, isBashWriteToStateFile, BLOCKED_WRITE_ERROR } from "../write-intercept.js";
19
20
  import { loadFile, saveFile, formatContinue } from "../files.js";
@@ -39,7 +40,14 @@ import { saveActivityLog } from "../activity-log.js";
39
40
  import { recordToolCall as safetyRecordToolCall, recordToolResult as safetyRecordToolResult, saveEvidenceToDisk } from "../safety/evidence-collector.js";
40
41
  import { parseUnitId } from "../unit-id.js";
41
42
  import { classifyCommand } from "../safety/destructive-guard.js";
43
+ import {
44
+ confirmDestructiveCommand,
45
+ consumeDestructiveConfirmation,
46
+ isDestructiveConfirmGateId,
47
+ requestDestructiveConfirmation,
48
+ } from "../safety/destructive-confirmation.js";
42
49
  import { logWarning as safetyLogWarning } from "../workflow-logger.js";
50
+ import { isUnitCloseoutTool, runInteractiveUnitCloseout } from "../unit-closeout.js";
43
51
  import { installNotifyInterceptor } from "./notify-interceptor.js";
44
52
  import { initNotificationStore } from "../notification-store.js";
45
53
  import { initNotificationWidget } from "../notification-widget.js";
@@ -48,28 +56,28 @@ import { resolveWorktreeProjectRoot } from "../worktree-root.js";
48
56
  import { extractSubagentAgentClasses } from "./subagent-input.js";
49
57
  import {
50
58
  approvalGateIdForUnit,
59
+ evaluateAskUserQuestionsRound,
60
+ formatUnansweredConsentQuestionMessage,
51
61
  isExplicitApprovalResponse,
52
62
  messageHasPendingAskUserQuestionsTool,
53
- shouldPauseForUserApprovalQuestion,
54
- } from "../user-input-boundary.js";
63
+ shouldPauseForQuestion,
64
+ } from "../consent-question.js";
55
65
  import { resolveSkillManifest } from "../skill-manifest.js";
56
66
  import { applyUnitSkillVisibility, unitHasSkillManifest } from "../skill-scope.js";
57
67
  import { getGuidedUnitContext } from "../guided-unit-context.js";
58
68
  import { registerPlanMilestoneSchemaRecovery } from "./plan-milestone-schema-recovery.js";
59
69
  import { AUTO_UNIT_SCOPED_TOOLS, RUN_UAT_BROWSER_TOOL_NAMES, canonicalWorkflowToolName, isWorkflowAliasTool } from "../auto-unit-tool-scope.js";
70
+ import { hasBrowserContractPrefix } from "../../shared/browser-contract.js";
60
71
  import { filterToolsForProvider } from "../model-router.js";
61
72
  import { mcpToolMatchesBaseName } from "../mcp-tool-name.js";
62
73
  import { RUN_UAT_READ_ONLY_TOOL_NAMES, RUN_UAT_WORKFLOW_TOOL_NAMES } from "../tool-presentation-plan.js";
63
74
  import { supportsSourceObservationsForUnit } from "../source-observations.js";
64
75
  import { clearPendingAutoStart } from "../pending-auto-start.js";
76
+ import { resolveWorkflowToolBasePath } from "./dynamic-tools.js";
77
+ import { getRequiredWorkflowToolsForUnit } from "../unit-tool-contracts.js";
65
78
 
66
79
  let approvalQuestionAbortInFlight = false;
67
80
 
68
- interface DeferredApprovalGate {
69
- gateId: string;
70
- basePath: string;
71
- }
72
-
73
81
  type WelcomeScreenModule = {
74
82
  buildWelcomeScreenLines(opts: { version: string; remoteChannel?: string; width?: number }): string[];
75
83
  };
@@ -140,7 +148,13 @@ async function installWelcomeHeader(ctx: ExtensionContext): Promise<void> {
140
148
  }
141
149
  }
142
150
 
143
- let deferredApprovalGate: DeferredApprovalGate | null = null;
151
+ /**
152
+ * Approval gates whose durable arming is deferred until tool execution /
153
+ * agent end, keyed by basePath. A Map (not a single slot) so concurrent
154
+ * projects in one process cannot lose each other's deferred gate; entries
155
+ * are bounded — cleared on activation, session boundaries, and verification.
156
+ */
157
+ const deferredApprovalGates = new Map<string, string>();
144
158
 
145
159
  export const MINIMAL_GSD_TOOL_NAMES = [
146
160
  "gsd_exec",
@@ -178,7 +192,7 @@ function withPreservedShimTools(toolNames: readonly string[]): string[] {
178
192
 
179
193
  /** True for the browser automation tools (browser_navigate, browser_click, ...). */
180
194
  function isBrowserTool(toolName: string): boolean {
181
- return canonicalToolName(toolName).startsWith("browser_");
195
+ return hasBrowserContractPrefix(canonicalToolName(toolName));
182
196
  }
183
197
 
184
198
  /**
@@ -259,6 +273,7 @@ export function buildMinimalAutoGsdToolSet(
259
273
  activeToolNames: readonly string[],
260
274
  unitType: string | undefined,
261
275
  registeredToolNames: readonly string[] = activeToolNames,
276
+ warnOnUnresolvedRequiredTools = registeredToolNames !== activeToolNames,
262
277
  ): string[] {
263
278
  if (unitType === "run-uat") {
264
279
  return buildRunUatGsdToolSet(activeToolNames, registeredToolNames);
@@ -274,7 +289,36 @@ export function buildMinimalAutoGsdToolSet(
274
289
  [...activeToolNames, ...registeredToolNames],
275
290
  [...MINIMAL_GSD_TOOL_NAMES, ...unitTools],
276
291
  );
277
- return withPreservedShimTools([...new Set([...preserved, ...scoped])]);
292
+ const result = withPreservedShimTools([...new Set([...preserved, ...scoped])]);
293
+ warnIfRequiredWorkflowToolsUnresolved(unitType, result, warnOnUnresolvedRequiredTools);
294
+ return result;
295
+ }
296
+
297
+ function hasResolvedWorkflowTool(
298
+ resolvedToolNames: readonly string[],
299
+ requiredToolName: string,
300
+ ): boolean {
301
+ return resolvedToolNames.some(
302
+ (name) => name === requiredToolName || mcpToolMatchesBaseName(name, requiredToolName),
303
+ );
304
+ }
305
+
306
+ function warnIfRequiredWorkflowToolsUnresolved(
307
+ unitType: string | undefined,
308
+ scopedToolNames: readonly string[],
309
+ shouldWarn: boolean,
310
+ ): void {
311
+ if (!unitType || !shouldWarn) return;
312
+
313
+ const unresolved = getRequiredWorkflowToolsForUnit(unitType).filter(
314
+ (toolName) => !hasResolvedWorkflowTool(scopedToolNames, toolName),
315
+ );
316
+ if (unresolved.length === 0) return;
317
+
318
+ safetyLogWarning(
319
+ "bootstrap",
320
+ `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.`,
321
+ );
278
322
  }
279
323
 
280
324
  export function buildRunUatGsdToolSet(
@@ -327,6 +371,7 @@ export function buildRequestScopedGsdToolSet(
327
371
  requestCustomMessages: readonly { customType?: string }[] | undefined,
328
372
  registeredToolNames: readonly string[] = activeToolNames,
329
373
  guidedUnitType?: string,
374
+ warnOnUnresolvedRequiredTools = registeredToolNames !== activeToolNames,
330
375
  ): string[] | undefined {
331
376
  for (let index = (requestCustomMessages?.length ?? 0) - 1; index >= 0; index--) {
332
377
  const currentCustomType = requestCustomMessages?.[index]?.customType;
@@ -337,7 +382,12 @@ export function buildRequestScopedGsdToolSet(
337
382
  currentCustomType === "gsd-triage"
338
383
  ) {
339
384
  if (guidedUnitType) {
340
- return buildMinimalAutoGsdToolSet(activeToolNames, guidedUnitType, registeredToolNames);
385
+ return buildMinimalAutoGsdToolSet(
386
+ activeToolNames,
387
+ guidedUnitType,
388
+ registeredToolNames,
389
+ warnOnUnresolvedRequiredTools,
390
+ );
341
391
  }
342
392
  return buildMinimalGsdWorkflowToolSet(activeToolNames, registeredToolNames);
343
393
  }
@@ -386,11 +436,13 @@ function applyMinimalGsdToolSurface(pi: ExtensionAPI): void {
386
436
  const dash = getAutoRuntimeSnapshot();
387
437
  if (dash.active && dash.currentUnit) {
388
438
  const currentToolNames = pi.getActiveTools();
439
+ const hasRegisteredSurface = typeof pi.getAllTools === "function";
389
440
  const registeredToolNames = resolveRegisteredToolNames(pi, currentToolNames);
390
441
  const scopedToolNames = buildMinimalAutoGsdToolSet(
391
442
  currentToolNames,
392
443
  dash.currentUnit.type,
393
444
  registeredToolNames,
445
+ hasRegisteredSurface,
394
446
  );
395
447
  recordAutoToolSurfaceSnapshot({
396
448
  source: "runtime-scope",
@@ -412,9 +464,10 @@ export function scopeGsdWorkflowToolsForDispatch(
412
464
  ): ScopedGsdWorkflowState | null {
413
465
  if (isFullGsdToolSurfaceRequested()) return null;
414
466
  const current = pi.getActiveTools();
467
+ const hasRegisteredSurface = typeof pi.getAllTools === "function";
415
468
  const registeredToolNames = resolveRegisteredToolNames(pi, current);
416
469
  const scoped = unitType
417
- ? buildMinimalAutoGsdToolSet(current, unitType, registeredToolNames)
470
+ ? buildMinimalAutoGsdToolSet(current, unitType, registeredToolNames, hasRegisteredSurface)
418
471
  : buildMinimalGsdWorkflowToolSet(current, registeredToolNames);
419
472
  recordAutoToolSurfaceSnapshot({
420
473
  source: "dispatch-scope",
@@ -509,13 +562,22 @@ async function applyCompactionThresholdOverride(ctx: ExtensionContext): Promise<
509
562
  }
510
563
 
511
564
  function clearDeferredApprovalGate(basePath?: string): void {
512
- if (!basePath || deferredApprovalGate?.basePath === basePath) {
513
- deferredApprovalGate = null;
565
+ if (!basePath) {
566
+ deferredApprovalGates.clear();
567
+ } else {
568
+ deferredApprovalGates.delete(basePath);
514
569
  }
515
570
  }
516
571
 
517
572
  function deferApprovalGate(gateId: string, basePath: string): void {
518
- deferredApprovalGate = { gateId, basePath };
573
+ // Verified-on-disk wins (same adapter policy as activation/re-arm): if the
574
+ // workflow MCP child already verified this gate, deferring would block
575
+ // tools for a gate that can never legitimately arm.
576
+ const snapshot = hostWriteGateAdapter.readState(basePath);
577
+ if (isApprovalGateVerifiedInSnapshot(snapshot, gateId)) return;
578
+ const milestoneId = extractDepthVerificationMilestoneId(gateId);
579
+ if (milestoneId && isMilestoneDepthVerifiedInSnapshot(snapshot, milestoneId)) return;
580
+ deferredApprovalGates.set(basePath, gateId);
519
581
  }
520
582
 
521
583
  function contextBasePath(ctx?: { cwd?: string }): string {
@@ -572,15 +634,13 @@ function isShellExecutionTool(canonicalName: string): boolean {
572
634
  }
573
635
 
574
636
  function activateDeferredApprovalGate(basePath: string): void {
575
- if (deferredApprovalGate?.basePath !== basePath) return;
576
- const gateId = deferredApprovalGate.gateId;
577
- deferredApprovalGate = null;
578
- refreshWriteGateStateFromDisk(basePath);
579
- const snapshot = loadWriteGateSnapshot(basePath);
580
- const milestoneId = extractDepthVerificationMilestoneId(gateId);
581
- if (isApprovalGateVerifiedInSnapshot(snapshot, gateId)) return;
582
- if (milestoneId && isMilestoneDepthVerifiedInSnapshot(snapshot, milestoneId)) return;
583
- setPendingGate(gateId, basePath);
637
+ const gateId = deferredApprovalGates.get(basePath);
638
+ if (gateId === undefined) return;
639
+ deferredApprovalGates.delete(basePath);
640
+ // hostWriteGateAdapter.setPending applies the verified-on-disk-wins merge
641
+ // policy: it refuses to arm (and thereby clobber) a gate the workflow MCP
642
+ // child already verified on disk.
643
+ hostWriteGateAdapter.setPending(gateId, basePath);
584
644
  }
585
645
 
586
646
  function extractGateQuestionId(input: unknown): string | undefined {
@@ -591,7 +651,7 @@ function extractGateQuestionId(input: unknown): string | undefined {
591
651
 
592
652
  function isApprovalGateBlocking(basePath: string): boolean {
593
653
  return Boolean(getPendingGate(basePath))
594
- || (deferredApprovalGate?.basePath === basePath);
654
+ || deferredApprovalGates.has(basePath);
595
655
  }
596
656
 
597
657
  function isContextDraftSummarySave(toolName: string, input: unknown): boolean {
@@ -600,6 +660,26 @@ function isContextDraftSummarySave(toolName: string, input: unknown): boolean {
600
660
  return (input as { artifact_type?: unknown }).artifact_type === "CONTEXT-DRAFT";
601
661
  }
602
662
 
663
+ /**
664
+ * External engines (claude-code-cli) deliver ask_user_questions results as
665
+ * relayed MCP tool results: the structured round payload arrives in
666
+ * `result.structuredContent`, not in pi-native `event.details`. Without this
667
+ * fallback, applyAskUserQuestionsGateResult sees no response for an answered
668
+ * gate question and lands in the "waiting" branch — leaving a re-armed gate
669
+ * permanently pending and the discuss→auto handoff blocked.
670
+ */
671
+ function resolveAskUserQuestionsGateDetails(event: { details?: unknown; result?: unknown }): any {
672
+ const hasRoundShape = (value: any): boolean =>
673
+ !!value && typeof value === "object" &&
674
+ (value.cancelled !== undefined || value.response !== undefined);
675
+
676
+ const details = event.details as any;
677
+ if (hasRoundShape(details)) return details;
678
+ const structured = (event.result as { structuredContent?: unknown } | undefined)?.structuredContent;
679
+ if (hasRoundShape(structured)) return structured;
680
+ return details ?? {};
681
+ }
682
+
603
683
  type StructuredQuestion = {
604
684
  id?: string;
605
685
  header?: string;
@@ -716,13 +796,14 @@ function shouldBlockDeferredApprovalTool(
716
796
  input: unknown,
717
797
  basePath: string,
718
798
  ): { block: boolean; reason?: string; displayReason?: string } {
719
- if (deferredApprovalGate?.basePath !== basePath) return { block: false };
799
+ const deferredGateId = deferredApprovalGates.get(basePath);
800
+ if (deferredGateId === undefined) return { block: false };
720
801
  if (toolName === "ask_user_questions") return { block: false };
721
802
  if (isContextDraftSummarySave(toolName, input)) return { block: false };
722
803
  return withDepthGateDisplayReason({
723
804
  block: true,
724
805
  reason: [
725
- `HARD BLOCK: Approval question "${deferredApprovalGate.gateId}" has been shown to the user.`,
806
+ `HARD BLOCK: Approval question "${deferredGateId}" has been shown to the user.`,
726
807
  `Only CONTEXT-DRAFT persistence may finish in this same assistant turn.`,
727
808
  `Wait for the user's answer before calling additional tools.`,
728
809
  ].join(" "),
@@ -852,10 +933,12 @@ export function registerHooks(
852
933
  const beforeAgentBasePath = contextBasePath(ctx);
853
934
  const pendingApprovalGate = getPendingGate(beforeAgentBasePath);
854
935
  if (pendingApprovalGate && isExplicitApprovalResponse(event.prompt, pendingApprovalGate)) {
855
- markApprovalGateVerified(pendingApprovalGate, beforeAgentBasePath);
936
+ // Host adapter explicitly: the ambient write-gate exports env-sniff the
937
+ // adapter per call and are reserved for the MCP child's import surface.
938
+ hostWriteGateAdapter.markApprovalGateVerified(pendingApprovalGate, beforeAgentBasePath);
856
939
  const milestoneId = extractDepthVerificationMilestoneId(pendingApprovalGate);
857
- if (milestoneId) markDepthVerified(milestoneId, beforeAgentBasePath);
858
- clearPendingGate(beforeAgentBasePath);
940
+ if (milestoneId) hostWriteGateAdapter.markDepthVerified(milestoneId, beforeAgentBasePath);
941
+ hostWriteGateAdapter.clearPending(beforeAgentBasePath);
859
942
  if (isAutoPaused() && !isAutoActive()) {
860
943
  const { resumeAutoAfterProviderDelay } = await import("./provider-error-resume.js");
861
944
  void resumeAutoAfterProviderDelay(pi, ctx).catch((err) => {
@@ -1079,7 +1162,7 @@ export function registerHooks(
1079
1162
  }
1080
1163
  }
1081
1164
 
1082
- if (!shouldPauseForUserApprovalQuestion(unitType, [event.message])) return;
1165
+ if (!shouldPauseForQuestion(unitType, [event.message])) return;
1083
1166
 
1084
1167
  const gateId = approvalGateIdForUnit(unitType, unitId);
1085
1168
  if (gateId) {
@@ -1094,7 +1177,7 @@ export function registerHooks(
1094
1177
 
1095
1178
  approvalQuestionAbortInFlight = true;
1096
1179
  ctx.ui.notify(
1097
- `${unitType}${unitId ? ` ${unitId}` : ""} is waiting for your approval - pausing before more tool calls run.`,
1180
+ `${unitType ?? "The discussion"}${unitId ? ` ${unitId}` : ""} is waiting for your approval - pausing before more tool calls run.`,
1098
1181
  "info",
1099
1182
  );
1100
1183
  // The durable pending gate is activated at agent_end so same-turn
@@ -1122,6 +1205,13 @@ export function registerHooks(
1122
1205
  }
1123
1206
  });
1124
1207
 
1208
+ // Engine hook contract (../engine-hook-contract.ts): tool_call is
1209
+ // NATIVE_ONLY_TOOL_HOOKS — it never fires under external engines
1210
+ // (claude-code-cli pre-executes tools). The guards below (loop guard,
1211
+ // pending/deferred gate blocks, queue guard, planning-unit tools policy,
1212
+ // worktree write gate, STATE.md single-writer, context-write depth gate)
1213
+ // are therefore native-engine enforcement only. The write-gate arming
1214
+ // concern has a universal mirror at tool_execution_start below.
1125
1215
  pi.on("tool_call", async (event, ctx) => {
1126
1216
  const discussionBasePath = contextBasePath(ctx);
1127
1217
  const toolName = canonicalToolName(event.toolName);
@@ -1309,6 +1399,11 @@ export function registerHooks(
1309
1399
  });
1310
1400
 
1311
1401
  // ── Safety harness: evidence collection + destructive command blocking ──
1402
+ // Engine hook contract: tool_call is NATIVE_ONLY_TOOL_HOOKS. Evidence
1403
+ // collection here is mirrored universally at tool_execution_start
1404
+ // (safetyRecordToolCall dedupes by toolCallId); the destructive-command
1405
+ // hard gate has NO universal mirror — blocking is impossible once an
1406
+ // external engine has already executed the command.
1312
1407
  pi.on("tool_call", async (event, ctx) => {
1313
1408
  markToolStart(event.toolCallId, event.toolName);
1314
1409
  safetyRecordToolCall(event.toolCallId, event.toolName, event.input as Record<string, unknown>);
@@ -1328,23 +1423,39 @@ export function registerHooks(
1328
1423
 
1329
1424
  // Destructive command classification + hard gate in all modes.
1330
1425
  if (isToolCallEventType("bash", event)) {
1331
- const classification = classifyCommand(event.input.command);
1426
+ const command = event.input.command;
1427
+ const classification = classifyCommand(command);
1332
1428
  if (classification.destructive) {
1429
+ const guardBasePath = contextBasePath(ctx);
1430
+ // Escape hatch: if the user already confirmed this exact command via a
1431
+ // destructive_confirm gate, consume the one-shot token and let it run.
1432
+ // Without this, the block below loops forever — the model cannot satisfy
1433
+ // "confirm in the current turn" because nothing ever clears the gate.
1434
+ if (consumeDestructiveConfirmation(command, guardBasePath)) {
1435
+ safetyLogWarning("safety", `destructive command confirmed: ${classification.labels.join(", ")}`, {
1436
+ command: String(command).slice(0, 200),
1437
+ });
1438
+ return;
1439
+ }
1440
+ // Record the command as pending so an affirmative answer to a
1441
+ // destructive_confirm gate (handled in tool_result) can confirm it.
1442
+ requestDestructiveConfirmation(command, guardBasePath);
1333
1443
  const reason = [
1334
1444
  "HARD BLOCK: destructive Bash command requires explicit human confirmation.",
1335
1445
  `Detected: ${classification.labels.join(", ")}`,
1336
- "Run this via ask_user_questions, wait for the user's response,",
1337
- "then issue the command only when confirmed in the current turn.",
1446
+ "Call ask_user_questions with a question id containing \"destructive_confirm\"",
1447
+ "and a first option that affirms the action; wait for the user's response,",
1448
+ "then re-issue this exact command in the same turn to run it once.",
1338
1449
  ].join(" ");
1339
1450
  safetyLogWarning("safety", `destructive command: ${classification.labels.join(", ")}`, {
1340
- command: String(event.input.command).slice(0, 200),
1451
+ command: String(command).slice(0, 200),
1341
1452
  });
1342
1453
  if (ctx) {
1343
1454
  await maybePauseAutoForApprovalGate(
1344
1455
  ctx,
1345
1456
  pi,
1346
1457
  isAutoActive(),
1347
- "Depth confirmation is waiting for your answer — pausing auto-mode.",
1458
+ "Destructive-command confirmation is waiting for your answer — pausing auto-mode.",
1348
1459
  );
1349
1460
  }
1350
1461
  return { block: true, reason };
@@ -1352,6 +1463,11 @@ export function registerHooks(
1352
1463
  }
1353
1464
  });
1354
1465
 
1466
+ // Engine hook contract: tool_result is NATIVE_ONLY_TOOL_HOOKS — external
1467
+ // engines skip it. Error classification and markToolEnd are mirrored
1468
+ // universally at tool_execution_end; the ask_user_questions gate lifecycle
1469
+ // here is paired with the tool_execution_start arming path, which external
1470
+ // engines do reach.
1355
1471
  pi.on("tool_result", async (event, ctx) => {
1356
1472
  if (isAutoActive() && typeof event.toolCallId === "string") {
1357
1473
  markToolEnd(event.toolCallId);
@@ -1382,13 +1498,27 @@ export function registerHooks(
1382
1498
  } else if (isAutoActive()) {
1383
1499
  clearToolInvocationError();
1384
1500
  }
1501
+ // Interactive Closeout adapter (ADR-032): auto-mode owns closeout for its
1502
+ // own units; interactive completions get the durable git subset (commit +
1503
+ // Closeout Git Verdict) instead of silently bypassing git.isolation.
1504
+ if (!event.isError && !isAutoActive() && isUnitCloseoutTool(toolName)) {
1505
+ try {
1506
+ runInteractiveUnitCloseout({
1507
+ basePath: resolveWorkflowToolBasePath(ctx, event.input as { milestone_id?: string }),
1508
+ canonicalToolName: toolName,
1509
+ input: event.input,
1510
+ });
1511
+ } catch (err) {
1512
+ safetyLogWarning("engine", `interactive unit closeout failed: ${err instanceof Error ? err.message : String(err)}`);
1513
+ }
1514
+ }
1385
1515
  if (toolName !== "ask_user_questions") return;
1386
1516
  const basePath = contextBasePath(ctx);
1387
1517
  const milestoneId = await getDiscussionMilestoneIdFor(basePath);
1388
1518
 
1389
- const details = event.details as any;
1519
+ const details = resolveAskUserQuestionsGateDetails(event);
1390
1520
 
1391
- const questions: any[] = (event.input as any)?.questions ?? [];
1521
+ const questions: any[] = (event.input as any)?.questions ?? details?.questions ?? [];
1392
1522
  const gateResult = applyAskUserQuestionsGateResult({
1393
1523
  basePath,
1394
1524
  questions,
@@ -1418,27 +1548,95 @@ export function registerHooks(
1418
1548
  clearDeferredApprovalGate(basePath);
1419
1549
  }
1420
1550
 
1421
- if (details?.cancelled || !details?.response) return;
1551
+ // ── Consent Question policy (consent-question.ts): one home for the
1552
+ // answer lifecycle of every ask_user_questions round. Per-question
1553
+ // verdicts come from the consent-verdict leaf — the same engine
1554
+ // applyAskUserQuestionsGateResult consumed above for gate persistence —
1555
+ // so empty answers on fail-closed kinds never pass as real answers (#528)
1556
+ // and cancellations get one unified handler.
1557
+ const roundOutcome = evaluateAskUserQuestionsRound(questions, details ?? {});
1558
+ if (roundOutcome === "cancelled") {
1559
+ resetToolCallLoopGuard();
1560
+ if (ctx) {
1561
+ await maybePauseAutoForApprovalGate(
1562
+ ctx,
1563
+ pi,
1564
+ true,
1565
+ "ask_user_questions was cancelled before receiving a response — pausing auto-mode until you respond.",
1566
+ );
1567
+ }
1568
+ return;
1569
+ }
1570
+ if (roundOutcome === "waiting") {
1571
+ resetToolCallLoopGuard();
1572
+ if (ctx) {
1573
+ await maybePauseAutoForApprovalGate(
1574
+ ctx,
1575
+ pi,
1576
+ true,
1577
+ "A user question received no answer — pausing auto-mode until you respond.",
1578
+ );
1579
+ }
1580
+ return {
1581
+ content: [{
1582
+ type: "text" as const,
1583
+ text: formatUnansweredConsentQuestionMessage(questions),
1584
+ }],
1585
+ };
1586
+ }
1587
+
1588
+ // Cancelled rounds already returned via roundOutcome === "cancelled".
1589
+ if (!details?.response) return;
1590
+
1591
+ // Destructive-command confirmation: an affirmative answer to a
1592
+ // destructive_confirm gate promotes the pending blocked command to a
1593
+ // one-shot confirmed token, which the bash tool_call guard consumes on the
1594
+ // next attempt. Rejecting/declining leaves the command blocked.
1595
+ // (Depth-verification gate handling now lives in
1596
+ // applyAskUserQuestionsGateResult above; only the destructive-confirm gate
1597
+ // is handled inline here.)
1598
+ for (const question of questions) {
1599
+ if (isDestructiveConfirmGateId(question?.id)) {
1600
+ const answer = details.response?.answers?.[question.id];
1601
+ if (isDepthConfirmationAnswer(answer?.selected, question.options)) {
1602
+ confirmDestructiveCommand(basePath);
1603
+ }
1604
+ break;
1605
+ }
1606
+ }
1607
+
1422
1608
  if (!milestoneId) return;
1423
1609
  await saveDiscussionQuestionRound(basePath, milestoneId, questions, details);
1424
1610
  });
1425
1611
 
1612
+ // Engine hook contract: tool_execution_start is UNIVERSAL_TOOL_HOOKS — the
1613
+ // only pre-execution event that fires for every tool call on every engine.
1614
+ // Universal mirrors live here: write-gate arming and evidence collection.
1426
1615
  pi.on("tool_execution_start", async (event, ctx) => {
1427
1616
  const basePath = contextBasePath(ctx);
1428
1617
  const toolName = canonicalToolName(event.toolName);
1429
1618
  if (toolName === "ask_user_questions") {
1430
1619
  const questionId = extractGateQuestionId(event.args);
1431
1620
  if (typeof questionId === "string") {
1432
- setPendingGate(questionId, basePath);
1621
+ // External engines (claude-code-cli) ingest the SDK turn's tool blocks
1622
+ // post-hoc, so this event can fire AFTER the workflow MCP child already
1623
+ // verified this gate and allowed the CONTEXT save. Arming also revokes
1624
+ // verifiedDepthMilestones/verifiedApprovalGates, so an unconditional
1625
+ // re-arm here would wipe the child's verification and leave the
1626
+ // discuss→auto handoff permanently blocked. hostWriteGateAdapter
1627
+ // .setPending applies the verified-on-disk-wins policy and skips the
1628
+ // re-arm in that case. Stale verified state cannot leak into a later
1629
+ // re-discussion: a successful handoff deletes the snapshot via
1630
+ // clearDiscussionFlowState.
1631
+ hostWriteGateAdapter.setPending(questionId, basePath);
1433
1632
  clearDeferredApprovalGate(basePath);
1434
1633
  }
1435
1634
  }
1436
1635
 
1437
- // Safety harness: record evidence here, not only in tool_call. External
1438
- // engines (claude-code-cli) pre-execute tools, so the agent loop skips
1439
- // beforeToolCall/tool_call for them tool_execution_start is the only
1440
- // event that fires for every tool call. recordToolCall dedupes by
1441
- // toolCallId, so native tools (which hit both events) record once.
1636
+ // Safety harness: record evidence here, not only in tool_call — see
1637
+ // ../engine-hook-contract.ts for why tool_call never fires under external
1638
+ // engines. recordToolCall dedupes by toolCallId, so native tools (which
1639
+ // hit both events) record once.
1442
1640
  safetyRecordToolCall(event.toolCallId, event.toolName, (event.args ?? {}) as Record<string, unknown>);
1443
1641
  const execDash = getAutoRuntimeSnapshot();
1444
1642
  if (execDash.basePath && execDash.currentUnit?.type === "execute-task") {
@@ -1452,6 +1650,9 @@ export function registerHooks(
1452
1650
  markToolStart(event.toolCallId, event.toolName);
1453
1651
  });
1454
1652
 
1653
+ // Engine hook contract: tool_execution_end is UNIVERSAL_TOOL_HOOKS — fires
1654
+ // for every finalized tool call on every engine, so error classification
1655
+ // and evidence persistence here cover external engines that skip tool_result.
1455
1656
  pi.on("tool_execution_end", async (event) => {
1456
1657
  markToolEnd(event.toolCallId);
1457
1658
  // #2883/#4974: Capture deterministic invocation/policy errors
@@ -1528,6 +1729,7 @@ export function registerHooks(
1528
1729
  return surfaceReduced ? { toolNames: providerCompatible } : undefined;
1529
1730
  }
1530
1731
  const registeredToolNames = resolveRegisteredToolNames(pi, event.activeToolNames);
1732
+ const hasRegisteredSurface = typeof pi.getAllTools === "function";
1531
1733
  const compatibleRegisteredToolNames = filterToolsForProvider(
1532
1734
  registeredToolNames,
1533
1735
  event.selectedModelApi,
@@ -1542,6 +1744,7 @@ export function registerHooks(
1542
1744
  event.requestCustomMessages,
1543
1745
  requestRegisteredToolNames,
1544
1746
  guidedUnit?.unitType,
1747
+ hasRegisteredSurface,
1545
1748
  );
1546
1749
  if (requestScoped) {
1547
1750
  recordAutoToolSurfaceSnapshot({
@@ -1562,6 +1765,7 @@ export function registerHooks(
1562
1765
  dash.currentUnit.type === "run-uat" ? aliasFilteredCompatible : providerCompatible,
1563
1766
  dash.currentUnit.type,
1564
1767
  registeredForUnit,
1768
+ hasRegisteredSurface,
1565
1769
  );
1566
1770
  recordAutoToolSurfaceSnapshot({
1567
1771
  source: "provider-adjustment",