@opengsd/gsd-pi 1.2.0-dev.955e4da0 → 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 (378) 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 +3 -0
  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/stream-adapter.js +30 -4
  24. package/dist/resources/extensions/gsd/auto/orchestrator.js +7 -5
  25. package/dist/resources/extensions/gsd/auto-dispatch.js +12 -1
  26. package/dist/resources/extensions/gsd/auto-model-selection.js +25 -6
  27. package/dist/resources/extensions/gsd/auto-post-unit.js +11 -2
  28. package/dist/resources/extensions/gsd/auto-prompts.js +15 -10
  29. package/dist/resources/extensions/gsd/auto-start.js +15 -10
  30. package/dist/resources/extensions/gsd/auto-tool-tracking.js +18 -0
  31. package/dist/resources/extensions/gsd/auto-unit-tool-scope.js +7 -16
  32. package/dist/resources/extensions/gsd/auto-worktree.js +30 -90
  33. package/dist/resources/extensions/gsd/auto.js +4 -13
  34. package/dist/resources/extensions/gsd/bootstrap/agent-end-recovery.js +3 -2
  35. package/dist/resources/extensions/gsd/bootstrap/dynamic-tools.js +23 -6
  36. package/dist/resources/extensions/gsd/bootstrap/register-extension.js +19 -0
  37. package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +122 -20
  38. package/dist/resources/extensions/gsd/bootstrap/write-gate.js +6 -2
  39. package/dist/resources/extensions/gsd/branch-patterns.js +2 -0
  40. package/dist/resources/extensions/gsd/browser-daemon-auto-prep.js +83 -0
  41. package/dist/resources/extensions/gsd/browser-evidence.js +8 -2
  42. package/dist/resources/extensions/gsd/captures.js +4 -6
  43. package/dist/resources/extensions/gsd/constants.js +0 -2
  44. package/dist/resources/extensions/gsd/crash-recovery.js +4 -12
  45. package/dist/resources/extensions/gsd/doctor-environment.js +2 -6
  46. package/dist/resources/extensions/gsd/doctor-format.js +9 -6
  47. package/dist/resources/extensions/gsd/doctor-runtime-checks.js +13 -15
  48. package/dist/resources/extensions/gsd/error-classifier.js +9 -0
  49. package/dist/resources/extensions/gsd/exec-sandbox.js +30 -10
  50. package/dist/resources/extensions/gsd/guidance.js +98 -0
  51. package/dist/resources/extensions/gsd/guided-flow.js +17 -2
  52. package/dist/resources/extensions/gsd/mcp-filter.js +2 -19
  53. package/dist/resources/extensions/gsd/mcp-tool-name.js +5 -13
  54. package/dist/resources/extensions/gsd/memory-consolidation-scanner.js +1 -1
  55. package/dist/resources/extensions/gsd/migrate/safety.js +4 -1
  56. package/dist/resources/extensions/gsd/notification-store.js +11 -4
  57. package/dist/resources/extensions/gsd/parallel-monitor-overlay.js +6 -4
  58. package/dist/resources/extensions/gsd/paths.js +27 -0
  59. package/dist/resources/extensions/gsd/pre-execution-checks.js +91 -3
  60. package/dist/resources/extensions/gsd/preferences-models.js +14 -48
  61. package/dist/resources/extensions/gsd/prompts/complete-slice.md +1 -1
  62. package/dist/resources/extensions/gsd/prompts/plan-slice.md +1 -1
  63. package/dist/resources/extensions/gsd/prompts/refine-slice.md +1 -1
  64. package/dist/resources/extensions/gsd/prompts/replan-slice.md +1 -1
  65. package/dist/resources/extensions/gsd/prompts/run-uat.md +1 -1
  66. package/dist/resources/extensions/gsd/prompts/system.md +5 -2
  67. package/dist/resources/extensions/gsd/provider-error-guidance.js +1 -5
  68. package/dist/resources/extensions/gsd/provider-switch-observer.js +1 -1
  69. package/dist/resources/extensions/gsd/publication.js +87 -0
  70. package/dist/resources/extensions/gsd/recovery-classification.js +37 -94
  71. package/dist/resources/extensions/gsd/safety/destructive-confirmation.js +108 -0
  72. package/dist/resources/extensions/gsd/state.js +1 -20
  73. package/dist/resources/extensions/gsd/stop-notice.js +57 -0
  74. package/dist/resources/extensions/gsd/tool-surface-readiness.js +56 -0
  75. package/dist/resources/extensions/gsd/tools/exec-tool.js +9 -7
  76. package/dist/resources/extensions/gsd/tools/plan-slice.js +12 -6
  77. package/dist/resources/extensions/gsd/uat-policy.js +2 -1
  78. package/dist/resources/extensions/gsd/unit-closeout.js +138 -0
  79. package/dist/resources/extensions/gsd/unit-context-composer.js +74 -1
  80. package/dist/resources/extensions/gsd/unit-context-manifest.js +4 -27
  81. package/dist/resources/extensions/gsd/unit-registry.js +337 -0
  82. package/dist/resources/extensions/gsd/unit-tool-contracts.js +9 -182
  83. package/dist/resources/extensions/gsd/web-app-uat.js +45 -8
  84. package/dist/resources/extensions/gsd/workflow-tool-surface.js +1 -1
  85. package/dist/resources/extensions/gsd/worktree-git-recovery.js +15 -9
  86. package/dist/resources/extensions/gsd/worktree-root.js +11 -0
  87. package/dist/resources/extensions/gsd/worktree-session-state.js +4 -5
  88. package/dist/resources/extensions/search-the-web/native-search.js +5 -3
  89. package/dist/resources/extensions/shared/browser-contract.js +59 -0
  90. package/dist/resources/extensions/shared/gsd-browser-cli.js +96 -5
  91. package/dist/resources/shared/package.json +3 -0
  92. package/dist/resources/skills/create-skill/references/executable-code.md +1 -1
  93. package/dist/resources/skills/create-skill/workflows/add-reference.md +8 -3
  94. package/dist/resources/skills/create-skill/workflows/add-script.md +4 -2
  95. package/dist/resources/skills/create-skill/workflows/add-template.md +3 -1
  96. package/dist/resources/skills/create-skill/workflows/add-workflow.md +8 -3
  97. package/dist/resources/skills/create-skill/workflows/upgrade-to-router.md +10 -5
  98. package/dist/resources/skills/create-skill/workflows/verify-skill.md +9 -4
  99. package/dist/resources/skills/spike-wrap-up/SKILL.md +9 -9
  100. package/dist/tsconfig.extensions.tsbuildinfo +1 -1
  101. package/dist/web/standalone/.next/BUILD_ID +1 -1
  102. package/dist/web/standalone/.next/app-path-routes-manifest.json +13 -13
  103. package/dist/web/standalone/.next/build-manifest.json +3 -3
  104. package/dist/web/standalone/.next/prerender-manifest.json +3 -3
  105. package/dist/web/standalone/.next/react-loadable-manifest.json +1 -1
  106. package/dist/web/standalone/.next/server/app/_global-error.html +1 -1
  107. package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
  108. package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  109. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
  110. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
  111. package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  112. package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  113. package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  114. package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
  115. package/dist/web/standalone/.next/server/app/_not-found.rsc +1 -1
  116. package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
  117. package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  118. package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +1 -1
  119. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  120. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  121. package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
  122. package/dist/web/standalone/.next/server/app/api/update/route.js +1 -1
  123. package/dist/web/standalone/.next/server/app/api/update/route.js.nft.json +1 -1
  124. package/dist/web/standalone/.next/server/app/index.html +1 -1
  125. package/dist/web/standalone/.next/server/app/index.rsc +1 -1
  126. package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +1 -1
  127. package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +1 -1
  128. package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
  129. package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +1 -1
  130. package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
  131. package/dist/web/standalone/.next/server/app-paths-manifest.json +13 -13
  132. package/dist/web/standalone/.next/server/chunks/5124.js +1 -1
  133. package/dist/web/standalone/.next/server/chunks/8357.js +1 -1
  134. package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
  135. package/dist/web/standalone/.next/server/middleware-react-loadable-manifest.js +1 -1
  136. package/dist/web/standalone/.next/server/pages/404.html +1 -1
  137. package/dist/web/standalone/.next/server/pages/500.html +1 -1
  138. package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
  139. package/dist/web/standalone/.next/static/chunks/{796.cf859a427a2cb2ac.js → 796.e0bdc932325d7e03.js} +1 -1
  140. package/dist/web/standalone/.next/static/chunks/{webpack-fbea77b5f9953368.js → webpack-f0285ce91d4ec9ef.js} +1 -1
  141. package/dist/web/standalone/node_modules/node-pty/build/Makefile +1 -1
  142. package/dist/web/standalone/node_modules/postcss/lib/container.js +18 -26
  143. package/dist/web/standalone/node_modules/postcss/lib/css-syntax-error.js +14 -47
  144. package/dist/web/standalone/node_modules/postcss/lib/declaration.js +4 -4
  145. package/dist/web/standalone/node_modules/postcss/lib/fromJSON.js +3 -3
  146. package/dist/web/standalone/node_modules/postcss/lib/input.js +29 -54
  147. package/dist/web/standalone/node_modules/postcss/lib/lazy-result.js +37 -47
  148. package/dist/web/standalone/node_modules/postcss/lib/map-generator.js +9 -26
  149. package/dist/web/standalone/node_modules/postcss/lib/no-work-result.js +55 -57
  150. package/dist/web/standalone/node_modules/postcss/lib/node.js +31 -99
  151. package/dist/web/standalone/node_modules/postcss/lib/parse.js +1 -1
  152. package/dist/web/standalone/node_modules/postcss/lib/parser.js +9 -10
  153. package/dist/web/standalone/node_modules/postcss/lib/postcss.js +12 -12
  154. package/dist/web/standalone/node_modules/postcss/lib/previous-map.js +11 -30
  155. package/dist/web/standalone/node_modules/postcss/lib/processor.js +7 -7
  156. package/dist/web/standalone/node_modules/postcss/lib/result.js +5 -5
  157. package/dist/web/standalone/node_modules/postcss/lib/rule.js +6 -6
  158. package/dist/web/standalone/node_modules/postcss/lib/stringifier.js +28 -69
  159. package/dist/web/standalone/node_modules/postcss/lib/tokenize.js +2 -6
  160. package/dist/web/standalone/node_modules/postcss/package.json +48 -48
  161. package/dist/web/standalone/package.json +1 -1
  162. package/dist/worktree-cli.js +3 -6
  163. package/dist/worktree-status-banner.js +7 -15
  164. package/package.json +1 -1
  165. package/packages/cloud-mcp-gateway/package.json +2 -2
  166. package/packages/contracts/dist/rpc.d.ts +1 -0
  167. package/packages/contracts/dist/rpc.d.ts.map +1 -1
  168. package/packages/contracts/dist/rpc.js.map +1 -1
  169. package/packages/contracts/dist/workflow.d.ts +4 -0
  170. package/packages/contracts/dist/workflow.d.ts.map +1 -1
  171. package/packages/contracts/dist/workflow.js.map +1 -1
  172. package/packages/contracts/package.json +1 -1
  173. package/packages/daemon/package.json +4 -4
  174. package/packages/gsd-agent-core/package.json +5 -5
  175. package/packages/gsd-agent-modes/dist/modes/interactive/components/tool-execution.d.ts +5 -0
  176. package/packages/gsd-agent-modes/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
  177. package/packages/gsd-agent-modes/dist/modes/interactive/components/tool-execution.js +5 -0
  178. package/packages/gsd-agent-modes/dist/modes/interactive/components/tool-execution.js.map +1 -1
  179. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-controller.d.ts.map +1 -1
  180. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-controller.js +7 -0
  181. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-controller.js.map +1 -1
  182. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/input-controller.d.ts.map +1 -1
  183. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/input-controller.js +8 -1
  184. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/input-controller.js.map +1 -1
  185. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-chat-render.d.ts.map +1 -1
  186. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-chat-render.js +11 -1
  187. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-chat-render.js.map +1 -1
  188. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-selectors-auth.d.ts.map +1 -1
  189. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-selectors-auth.js +4 -4
  190. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-selectors-auth.js.map +1 -1
  191. package/packages/gsd-agent-modes/dist/modes/rpc/rpc-mode.d.ts.map +1 -1
  192. package/packages/gsd-agent-modes/dist/modes/rpc/rpc-mode.js +3 -1
  193. package/packages/gsd-agent-modes/dist/modes/rpc/rpc-mode.js.map +1 -1
  194. package/packages/gsd-agent-modes/package.json +7 -7
  195. package/packages/mcp-server/dist/cli.js +6 -3
  196. package/packages/mcp-server/dist/cli.js.map +1 -1
  197. package/packages/mcp-server/dist/workflow-tools.d.ts +8 -0
  198. package/packages/mcp-server/dist/workflow-tools.d.ts.map +1 -1
  199. package/packages/mcp-server/dist/workflow-tools.js +17 -1
  200. package/packages/mcp-server/dist/workflow-tools.js.map +1 -1
  201. package/packages/mcp-server/package.json +3 -3
  202. package/packages/native/package.json +1 -1
  203. package/packages/pi-agent-core/dist/harness/env/nodejs.d.ts +1 -0
  204. package/packages/pi-agent-core/dist/harness/env/nodejs.d.ts.map +1 -1
  205. package/packages/pi-agent-core/dist/harness/env/nodejs.js +34 -3
  206. package/packages/pi-agent-core/dist/harness/env/nodejs.js.map +1 -1
  207. package/packages/pi-agent-core/dist/index.d.ts +1 -0
  208. package/packages/pi-agent-core/dist/index.d.ts.map +1 -1
  209. package/packages/pi-agent-core/dist/index.js +3 -0
  210. package/packages/pi-agent-core/dist/index.js.map +1 -1
  211. package/packages/pi-agent-core/package.json +1 -1
  212. package/packages/pi-ai/dist/models.generated.d.ts +94 -382
  213. package/packages/pi-ai/dist/models.generated.d.ts.map +1 -1
  214. package/packages/pi-ai/dist/models.generated.js +149 -422
  215. package/packages/pi-ai/dist/models.generated.js.map +1 -1
  216. package/packages/pi-ai/package.json +1 -1
  217. package/packages/pi-coding-agent/dist/core/auth-storage.d.ts +2 -2
  218. package/packages/pi-coding-agent/dist/core/auth-storage.d.ts.map +1 -1
  219. package/packages/pi-coding-agent/dist/core/auth-storage.js +19 -13
  220. package/packages/pi-coding-agent/dist/core/auth-storage.js.map +1 -1
  221. package/packages/pi-coding-agent/dist/core/provider-readiness.d.ts.map +1 -1
  222. package/packages/pi-coding-agent/dist/core/provider-readiness.js +13 -6
  223. package/packages/pi-coding-agent/dist/core/provider-readiness.js.map +1 -1
  224. package/packages/pi-coding-agent/dist/core/tools/bash.d.ts +11 -0
  225. package/packages/pi-coding-agent/dist/core/tools/bash.d.ts.map +1 -1
  226. package/packages/pi-coding-agent/dist/core/tools/bash.js +53 -11
  227. package/packages/pi-coding-agent/dist/core/tools/bash.js.map +1 -1
  228. package/packages/pi-coding-agent/dist/index.d.ts +1 -1
  229. package/packages/pi-coding-agent/dist/index.d.ts.map +1 -1
  230. package/packages/pi-coding-agent/dist/index.js +1 -1
  231. package/packages/pi-coding-agent/dist/index.js.map +1 -1
  232. package/packages/pi-coding-agent/dist/utils/shell.d.ts +28 -2
  233. package/packages/pi-coding-agent/dist/utils/shell.d.ts.map +1 -1
  234. package/packages/pi-coding-agent/dist/utils/shell.js +56 -10
  235. package/packages/pi-coding-agent/dist/utils/shell.js.map +1 -1
  236. package/packages/pi-coding-agent/package.json +7 -7
  237. package/packages/pi-tui/dist/tui.d.ts.map +1 -1
  238. package/packages/pi-tui/dist/tui.js +9 -0
  239. package/packages/pi-tui/dist/tui.js.map +1 -1
  240. package/packages/pi-tui/package.json +2 -2
  241. package/packages/rpc-client/package.json +2 -2
  242. package/pkg/package.json +1 -1
  243. package/src/resources/extensions/async-jobs/async-bash-cancel.test.ts +360 -0
  244. package/src/resources/extensions/async-jobs/async-bash-tool.ts +33 -56
  245. package/src/resources/extensions/async-jobs/await-tool.test.ts +139 -0
  246. package/src/resources/extensions/async-jobs/await-tool.ts +82 -12
  247. package/src/resources/extensions/async-jobs/index.ts +79 -0
  248. package/src/resources/extensions/async-jobs/job-manager.ts +21 -1
  249. package/src/resources/extensions/bg-shell/bg-shell-command.ts +6 -6
  250. package/src/resources/extensions/bg-shell/bg-shell-tool.ts +10 -6
  251. package/src/resources/extensions/bg-shell/overlay.ts +9 -5
  252. package/src/resources/extensions/bg-shell/process-manager.ts +50 -25
  253. package/src/resources/extensions/bg-shell/readiness-detector.ts +12 -0
  254. package/src/resources/extensions/bg-shell/tests/lifecycle-and-utilities.test.ts +48 -1
  255. package/src/resources/extensions/bg-shell/utilities.ts +3 -0
  256. package/src/resources/extensions/browser-tools/engine/managed-gsd-browser.ts +265 -98
  257. package/src/resources/extensions/browser-tools/engine/selection.ts +90 -4
  258. package/src/resources/extensions/browser-tools/index.ts +71 -13
  259. package/src/resources/extensions/browser-tools/tests/browser-engine-selection.test.mjs +83 -13
  260. package/src/resources/extensions/browser-tools/tests/gsd-browser-launch-config.test.mjs +29 -1
  261. package/src/resources/extensions/browser-tools/tests/managed-gsd-browser-tools.test.mjs +136 -0
  262. package/src/resources/extensions/claude-code-cli/stream-adapter.ts +34 -4
  263. package/src/resources/extensions/gsd/auto/orchestrator.ts +7 -5
  264. package/src/resources/extensions/gsd/auto-dispatch.ts +12 -0
  265. package/src/resources/extensions/gsd/auto-model-selection.ts +25 -5
  266. package/src/resources/extensions/gsd/auto-post-unit.ts +13 -2
  267. package/src/resources/extensions/gsd/auto-prompts.ts +40 -26
  268. package/src/resources/extensions/gsd/auto-start.ts +15 -10
  269. package/src/resources/extensions/gsd/auto-tool-tracking.ts +19 -0
  270. package/src/resources/extensions/gsd/auto-unit-tool-scope.ts +10 -17
  271. package/src/resources/extensions/gsd/auto-worktree.ts +30 -93
  272. package/src/resources/extensions/gsd/auto.ts +8 -15
  273. package/src/resources/extensions/gsd/bootstrap/agent-end-recovery.ts +3 -5
  274. package/src/resources/extensions/gsd/bootstrap/dynamic-tools.ts +23 -6
  275. package/src/resources/extensions/gsd/bootstrap/register-extension.ts +24 -0
  276. package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +151 -15
  277. package/src/resources/extensions/gsd/bootstrap/write-gate.ts +6 -2
  278. package/src/resources/extensions/gsd/branch-patterns.ts +3 -0
  279. package/src/resources/extensions/gsd/browser-daemon-auto-prep.ts +108 -0
  280. package/src/resources/extensions/gsd/browser-evidence.ts +18 -2
  281. package/src/resources/extensions/gsd/captures.ts +4 -6
  282. package/src/resources/extensions/gsd/constants.ts +0 -3
  283. package/src/resources/extensions/gsd/crash-recovery.ts +3 -9
  284. package/src/resources/extensions/gsd/doctor-environment.ts +2 -7
  285. package/src/resources/extensions/gsd/doctor-format.ts +12 -7
  286. package/src/resources/extensions/gsd/doctor-runtime-checks.ts +13 -15
  287. package/src/resources/extensions/gsd/error-classifier.ts +11 -0
  288. package/src/resources/extensions/gsd/exec-sandbox.ts +49 -9
  289. package/src/resources/extensions/gsd/guidance.ts +139 -0
  290. package/src/resources/extensions/gsd/guided-flow.ts +16 -2
  291. package/src/resources/extensions/gsd/mcp-filter.ts +2 -23
  292. package/src/resources/extensions/gsd/mcp-tool-name.ts +6 -11
  293. package/src/resources/extensions/gsd/memory-consolidation-scanner.ts +1 -1
  294. package/src/resources/extensions/gsd/migrate/safety.ts +4 -1
  295. package/src/resources/extensions/gsd/notification-store.ts +26 -3
  296. package/src/resources/extensions/gsd/parallel-monitor-overlay.ts +6 -4
  297. package/src/resources/extensions/gsd/paths.ts +33 -0
  298. package/src/resources/extensions/gsd/pre-execution-checks.ts +109 -3
  299. package/src/resources/extensions/gsd/preferences-models.ts +12 -47
  300. package/src/resources/extensions/gsd/prompts/complete-slice.md +1 -1
  301. package/src/resources/extensions/gsd/prompts/plan-slice.md +1 -1
  302. package/src/resources/extensions/gsd/prompts/refine-slice.md +1 -1
  303. package/src/resources/extensions/gsd/prompts/replan-slice.md +1 -1
  304. package/src/resources/extensions/gsd/prompts/run-uat.md +1 -1
  305. package/src/resources/extensions/gsd/prompts/system.md +5 -2
  306. package/src/resources/extensions/gsd/provider-error-guidance.ts +4 -9
  307. package/src/resources/extensions/gsd/provider-switch-observer.ts +1 -1
  308. package/src/resources/extensions/gsd/publication.ts +122 -0
  309. package/src/resources/extensions/gsd/recovery-classification.ts +42 -96
  310. package/src/resources/extensions/gsd/safety/destructive-confirmation.ts +134 -0
  311. package/src/resources/extensions/gsd/state.ts +4 -21
  312. package/src/resources/extensions/gsd/stop-notice.ts +75 -0
  313. package/src/resources/extensions/gsd/tests/auto-model-selection.test.ts +22 -0
  314. package/src/resources/extensions/gsd/tests/auto-orchestrator.test.ts +16 -19
  315. package/src/resources/extensions/gsd/tests/browser-automation-contract-fixture.ts +39 -0
  316. package/src/resources/extensions/gsd/tests/browser-contract.test.ts +44 -0
  317. package/src/resources/extensions/gsd/tests/browser-daemon-auto-prep.test.ts +144 -0
  318. package/src/resources/extensions/gsd/tests/checkout-branch-stash-guard.test.ts +66 -1
  319. package/src/resources/extensions/gsd/tests/clear-stale-autostart.test.ts +22 -0
  320. package/src/resources/extensions/gsd/tests/commands-verdict.test.ts +8 -7
  321. package/src/resources/extensions/gsd/tests/destructive-confirmation.test.ts +303 -0
  322. package/src/resources/extensions/gsd/tests/dispatch-run-uat-browser-tools.test.ts +2 -1
  323. package/src/resources/extensions/gsd/tests/dynamic-bash-no-cap.test.ts +132 -0
  324. package/src/resources/extensions/gsd/tests/exec-graceful-kill.test.ts +193 -0
  325. package/src/resources/extensions/gsd/tests/exec-tool.test.ts +29 -1
  326. package/src/resources/extensions/gsd/tests/extension-bootstrap-isolation.test.ts +35 -1
  327. package/src/resources/extensions/gsd/tests/guidance.test.ts +125 -0
  328. package/src/resources/extensions/gsd/tests/integration/auto-worktree-milestone-merge.test.ts +53 -11
  329. package/src/resources/extensions/gsd/tests/integration/auto-worktree.test.ts +73 -58
  330. package/src/resources/extensions/gsd/tests/integration/gsd-integration-fixture.ts +80 -0
  331. package/src/resources/extensions/gsd/tests/mcp-project-config.test.ts +3 -1
  332. package/src/resources/extensions/gsd/tests/model-unittype-mapping.test.ts +32 -1
  333. package/src/resources/extensions/gsd/tests/notification-store.test.ts +32 -0
  334. package/src/resources/extensions/gsd/tests/oauth-api-model-routing.test.ts +167 -0
  335. package/src/resources/extensions/gsd/tests/pre-execution-checks.test.ts +193 -1
  336. package/src/resources/extensions/gsd/tests/provider-error-guidance.test.ts +3 -3
  337. package/src/resources/extensions/gsd/tests/publication.test.ts +120 -0
  338. package/src/resources/extensions/gsd/tests/register-hooks-depth-verification.test.ts +157 -0
  339. package/src/resources/extensions/gsd/tests/runtime-invariant-modules.test.ts +1 -0
  340. package/src/resources/extensions/gsd/tests/stop-notice.test.ts +70 -0
  341. package/src/resources/extensions/gsd/tests/token-tool-gating.test.ts +76 -0
  342. package/src/resources/extensions/gsd/tests/tool-invocation-error-loop-break.test.ts +8 -0
  343. package/src/resources/extensions/gsd/tests/tool-surface-readiness.test.ts +155 -0
  344. package/src/resources/extensions/gsd/tests/uat-policy.test.ts +24 -29
  345. package/src/resources/extensions/gsd/tests/unit-closeout.test.ts +209 -0
  346. package/src/resources/extensions/gsd/tests/unit-context-composer.test.ts +67 -2
  347. package/src/resources/extensions/gsd/tests/unit-registry.test.ts +163 -0
  348. package/src/resources/extensions/gsd/tests/web-app-uat.test.ts +44 -1
  349. package/src/resources/extensions/gsd/tests/workflow-mcp.test.ts +2 -2
  350. package/src/resources/extensions/gsd/tests/workflow-tool-executors.test.ts +2 -2
  351. package/src/resources/extensions/gsd/tool-surface-readiness.ts +76 -0
  352. package/src/resources/extensions/gsd/tools/exec-tool.ts +8 -7
  353. package/src/resources/extensions/gsd/tools/plan-slice.ts +12 -6
  354. package/src/resources/extensions/gsd/uat-policy.ts +2 -1
  355. package/src/resources/extensions/gsd/unit-closeout.ts +201 -0
  356. package/src/resources/extensions/gsd/unit-context-composer.ts +111 -1
  357. package/src/resources/extensions/gsd/unit-context-manifest.ts +4 -28
  358. package/src/resources/extensions/gsd/unit-registry.ts +412 -0
  359. package/src/resources/extensions/gsd/unit-tool-contracts.ts +27 -192
  360. package/src/resources/extensions/gsd/web-app-uat.ts +51 -8
  361. package/src/resources/extensions/gsd/workflow-tool-surface.ts +4 -1
  362. package/src/resources/extensions/gsd/worktree-git-recovery.ts +15 -9
  363. package/src/resources/extensions/gsd/worktree-root.ts +12 -0
  364. package/src/resources/extensions/gsd/worktree-session-state.ts +3 -5
  365. package/src/resources/extensions/search-the-web/native-search.ts +5 -3
  366. package/src/resources/extensions/shared/browser-contract.ts +66 -0
  367. package/src/resources/extensions/shared/gsd-browser-cli.ts +119 -5
  368. package/src/resources/shared/package.json +3 -0
  369. package/src/resources/skills/create-skill/references/executable-code.md +1 -1
  370. package/src/resources/skills/create-skill/workflows/add-reference.md +8 -3
  371. package/src/resources/skills/create-skill/workflows/add-script.md +4 -2
  372. package/src/resources/skills/create-skill/workflows/add-template.md +3 -1
  373. package/src/resources/skills/create-skill/workflows/add-workflow.md +8 -3
  374. package/src/resources/skills/create-skill/workflows/upgrade-to-router.md +10 -5
  375. package/src/resources/skills/create-skill/workflows/verify-skill.md +9 -4
  376. package/src/resources/skills/spike-wrap-up/SKILL.md +9 -9
  377. /package/dist/web/standalone/.next/static/{C24pqUd-aru-l0Dp0gLZP → mU4QIDlpVHDdjDpeEKh5W}/_buildManifest.js +0 -0
  378. /package/dist/web/standalone/.next/static/{C24pqUd-aru-l0Dp0gLZP → mU4QIDlpVHDdjDpeEKh5W}/_ssgManifest.js +0 -0
@@ -13,7 +13,7 @@ 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, canonicalToolName, clearDiscussionFlowState, formatPendingAskUserQuestionsGateMessage, isApprovalGateVerifiedInSnapshot, isDepthConfirmationAnswer, isMilestoneDepthVerified, isMilestoneDepthVerifiedInSnapshot, isQueuePhaseActive, loadWriteGateSnapshot, markApprovalGateVerified, markDepthVerified, refreshWriteGateStateFromDisk, resetWriteGateState, shouldBlockContextWrite, shouldBlockPlanningUnit, shouldBlockQueueExecution, shouldBlockWorktreeWrite, isGateQuestionId, setPendingGate, clearPendingGate, getPendingGate, shouldBlockPendingGate, shouldBlockPendingGateBash, extractDepthVerificationMilestoneId } from "./write-gate.js";
17
17
  import { resolveManifest } from "../unit-context-manifest.js";
18
18
  import { isBlockedStateFile, isBashWriteToStateFile, BLOCKED_WRITE_ERROR } from "../write-intercept.js";
19
19
  import { loadFile, saveFile, formatContinue } from "../files.js";
@@ -39,7 +39,14 @@ import { saveActivityLog } from "../activity-log.js";
39
39
  import { recordToolCall as safetyRecordToolCall, recordToolResult as safetyRecordToolResult, saveEvidenceToDisk } from "../safety/evidence-collector.js";
40
40
  import { parseUnitId } from "../unit-id.js";
41
41
  import { classifyCommand } from "../safety/destructive-guard.js";
42
+ import {
43
+ confirmDestructiveCommand,
44
+ consumeDestructiveConfirmation,
45
+ isDestructiveConfirmGateId,
46
+ requestDestructiveConfirmation,
47
+ } from "../safety/destructive-confirmation.js";
42
48
  import { logWarning as safetyLogWarning } from "../workflow-logger.js";
49
+ import { isUnitCloseoutTool, runInteractiveUnitCloseout } from "../unit-closeout.js";
43
50
  import { installNotifyInterceptor } from "./notify-interceptor.js";
44
51
  import { initNotificationStore } from "../notification-store.js";
45
52
  import { initNotificationWidget } from "../notification-widget.js";
@@ -57,11 +64,14 @@ import { applyUnitSkillVisibility, unitHasSkillManifest } from "../skill-scope.j
57
64
  import { getGuidedUnitContext } from "../guided-unit-context.js";
58
65
  import { registerPlanMilestoneSchemaRecovery } from "./plan-milestone-schema-recovery.js";
59
66
  import { AUTO_UNIT_SCOPED_TOOLS, RUN_UAT_BROWSER_TOOL_NAMES, canonicalWorkflowToolName, isWorkflowAliasTool } from "../auto-unit-tool-scope.js";
67
+ import { hasBrowserContractPrefix } from "../../shared/browser-contract.js";
60
68
  import { filterToolsForProvider } from "../model-router.js";
61
69
  import { mcpToolMatchesBaseName } from "../mcp-tool-name.js";
62
70
  import { RUN_UAT_READ_ONLY_TOOL_NAMES, RUN_UAT_WORKFLOW_TOOL_NAMES } from "../tool-presentation-plan.js";
63
71
  import { supportsSourceObservationsForUnit } from "../source-observations.js";
64
72
  import { clearPendingAutoStart } from "../pending-auto-start.js";
73
+ import { resolveWorkflowToolBasePath } from "./dynamic-tools.js";
74
+ import { getRequiredWorkflowToolsForUnit } from "../unit-tool-contracts.js";
65
75
 
66
76
  let approvalQuestionAbortInFlight = false;
67
77
 
@@ -178,7 +188,7 @@ function withPreservedShimTools(toolNames: readonly string[]): string[] {
178
188
 
179
189
  /** True for the browser automation tools (browser_navigate, browser_click, ...). */
180
190
  function isBrowserTool(toolName: string): boolean {
181
- return canonicalToolName(toolName).startsWith("browser_");
191
+ return hasBrowserContractPrefix(canonicalToolName(toolName));
182
192
  }
183
193
 
184
194
  /**
@@ -259,6 +269,7 @@ export function buildMinimalAutoGsdToolSet(
259
269
  activeToolNames: readonly string[],
260
270
  unitType: string | undefined,
261
271
  registeredToolNames: readonly string[] = activeToolNames,
272
+ warnOnUnresolvedRequiredTools = registeredToolNames !== activeToolNames,
262
273
  ): string[] {
263
274
  if (unitType === "run-uat") {
264
275
  return buildRunUatGsdToolSet(activeToolNames, registeredToolNames);
@@ -274,7 +285,36 @@ export function buildMinimalAutoGsdToolSet(
274
285
  [...activeToolNames, ...registeredToolNames],
275
286
  [...MINIMAL_GSD_TOOL_NAMES, ...unitTools],
276
287
  );
277
- return withPreservedShimTools([...new Set([...preserved, ...scoped])]);
288
+ const result = withPreservedShimTools([...new Set([...preserved, ...scoped])]);
289
+ warnIfRequiredWorkflowToolsUnresolved(unitType, result, warnOnUnresolvedRequiredTools);
290
+ return result;
291
+ }
292
+
293
+ function hasResolvedWorkflowTool(
294
+ resolvedToolNames: readonly string[],
295
+ requiredToolName: string,
296
+ ): boolean {
297
+ return resolvedToolNames.some(
298
+ (name) => name === requiredToolName || mcpToolMatchesBaseName(name, requiredToolName),
299
+ );
300
+ }
301
+
302
+ function warnIfRequiredWorkflowToolsUnresolved(
303
+ unitType: string | undefined,
304
+ scopedToolNames: readonly string[],
305
+ shouldWarn: boolean,
306
+ ): void {
307
+ if (!unitType || !shouldWarn) return;
308
+
309
+ const unresolved = getRequiredWorkflowToolsForUnit(unitType).filter(
310
+ (toolName) => !hasResolvedWorkflowTool(scopedToolNames, toolName),
311
+ );
312
+ if (unresolved.length === 0) return;
313
+
314
+ safetyLogWarning(
315
+ "bootstrap",
316
+ `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.`,
317
+ );
278
318
  }
279
319
 
280
320
  export function buildRunUatGsdToolSet(
@@ -327,6 +367,7 @@ export function buildRequestScopedGsdToolSet(
327
367
  requestCustomMessages: readonly { customType?: string }[] | undefined,
328
368
  registeredToolNames: readonly string[] = activeToolNames,
329
369
  guidedUnitType?: string,
370
+ warnOnUnresolvedRequiredTools = registeredToolNames !== activeToolNames,
330
371
  ): string[] | undefined {
331
372
  for (let index = (requestCustomMessages?.length ?? 0) - 1; index >= 0; index--) {
332
373
  const currentCustomType = requestCustomMessages?.[index]?.customType;
@@ -337,7 +378,12 @@ export function buildRequestScopedGsdToolSet(
337
378
  currentCustomType === "gsd-triage"
338
379
  ) {
339
380
  if (guidedUnitType) {
340
- return buildMinimalAutoGsdToolSet(activeToolNames, guidedUnitType, registeredToolNames);
381
+ return buildMinimalAutoGsdToolSet(
382
+ activeToolNames,
383
+ guidedUnitType,
384
+ registeredToolNames,
385
+ warnOnUnresolvedRequiredTools,
386
+ );
341
387
  }
342
388
  return buildMinimalGsdWorkflowToolSet(activeToolNames, registeredToolNames);
343
389
  }
@@ -386,11 +432,13 @@ function applyMinimalGsdToolSurface(pi: ExtensionAPI): void {
386
432
  const dash = getAutoRuntimeSnapshot();
387
433
  if (dash.active && dash.currentUnit) {
388
434
  const currentToolNames = pi.getActiveTools();
435
+ const hasRegisteredSurface = typeof pi.getAllTools === "function";
389
436
  const registeredToolNames = resolveRegisteredToolNames(pi, currentToolNames);
390
437
  const scopedToolNames = buildMinimalAutoGsdToolSet(
391
438
  currentToolNames,
392
439
  dash.currentUnit.type,
393
440
  registeredToolNames,
441
+ hasRegisteredSurface,
394
442
  );
395
443
  recordAutoToolSurfaceSnapshot({
396
444
  source: "runtime-scope",
@@ -412,9 +460,10 @@ export function scopeGsdWorkflowToolsForDispatch(
412
460
  ): ScopedGsdWorkflowState | null {
413
461
  if (isFullGsdToolSurfaceRequested()) return null;
414
462
  const current = pi.getActiveTools();
463
+ const hasRegisteredSurface = typeof pi.getAllTools === "function";
415
464
  const registeredToolNames = resolveRegisteredToolNames(pi, current);
416
465
  const scoped = unitType
417
- ? buildMinimalAutoGsdToolSet(current, unitType, registeredToolNames)
466
+ ? buildMinimalAutoGsdToolSet(current, unitType, registeredToolNames, hasRegisteredSurface)
418
467
  : buildMinimalGsdWorkflowToolSet(current, registeredToolNames);
419
468
  recordAutoToolSurfaceSnapshot({
420
469
  source: "dispatch-scope",
@@ -575,8 +624,7 @@ function activateDeferredApprovalGate(basePath: string): void {
575
624
  if (deferredApprovalGate?.basePath !== basePath) return;
576
625
  const gateId = deferredApprovalGate.gateId;
577
626
  deferredApprovalGate = null;
578
- refreshWriteGateStateFromDisk(basePath);
579
- const snapshot = loadWriteGateSnapshot(basePath);
627
+ const snapshot = refreshWriteGateStateFromDisk(basePath);
580
628
  const milestoneId = extractDepthVerificationMilestoneId(gateId);
581
629
  if (isApprovalGateVerifiedInSnapshot(snapshot, gateId)) return;
582
630
  if (milestoneId && isMilestoneDepthVerifiedInSnapshot(snapshot, milestoneId)) return;
@@ -600,6 +648,26 @@ function isContextDraftSummarySave(toolName: string, input: unknown): boolean {
600
648
  return (input as { artifact_type?: unknown }).artifact_type === "CONTEXT-DRAFT";
601
649
  }
602
650
 
651
+ /**
652
+ * External engines (claude-code-cli) deliver ask_user_questions results as
653
+ * relayed MCP tool results: the structured round payload arrives in
654
+ * `result.structuredContent`, not in pi-native `event.details`. Without this
655
+ * fallback, applyAskUserQuestionsGateResult sees no response for an answered
656
+ * gate question and lands in the "waiting" branch — leaving a re-armed gate
657
+ * permanently pending and the discuss→auto handoff blocked.
658
+ */
659
+ function resolveAskUserQuestionsGateDetails(event: { details?: unknown; result?: unknown }): any {
660
+ const hasRoundShape = (value: any): boolean =>
661
+ !!value && typeof value === "object" &&
662
+ (value.cancelled !== undefined || value.response !== undefined);
663
+
664
+ const details = event.details as any;
665
+ if (hasRoundShape(details)) return details;
666
+ const structured = (event.result as { structuredContent?: unknown } | undefined)?.structuredContent;
667
+ if (hasRoundShape(structured)) return structured;
668
+ return details ?? {};
669
+ }
670
+
603
671
  type StructuredQuestion = {
604
672
  id?: string;
605
673
  header?: string;
@@ -1328,23 +1396,39 @@ export function registerHooks(
1328
1396
 
1329
1397
  // Destructive command classification + hard gate in all modes.
1330
1398
  if (isToolCallEventType("bash", event)) {
1331
- const classification = classifyCommand(event.input.command);
1399
+ const command = event.input.command;
1400
+ const classification = classifyCommand(command);
1332
1401
  if (classification.destructive) {
1402
+ const guardBasePath = contextBasePath(ctx);
1403
+ // Escape hatch: if the user already confirmed this exact command via a
1404
+ // destructive_confirm gate, consume the one-shot token and let it run.
1405
+ // Without this, the block below loops forever — the model cannot satisfy
1406
+ // "confirm in the current turn" because nothing ever clears the gate.
1407
+ if (consumeDestructiveConfirmation(command, guardBasePath)) {
1408
+ safetyLogWarning("safety", `destructive command confirmed: ${classification.labels.join(", ")}`, {
1409
+ command: String(command).slice(0, 200),
1410
+ });
1411
+ return;
1412
+ }
1413
+ // Record the command as pending so an affirmative answer to a
1414
+ // destructive_confirm gate (handled in tool_result) can confirm it.
1415
+ requestDestructiveConfirmation(command, guardBasePath);
1333
1416
  const reason = [
1334
1417
  "HARD BLOCK: destructive Bash command requires explicit human confirmation.",
1335
1418
  `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.",
1419
+ "Call ask_user_questions with a question id containing \"destructive_confirm\"",
1420
+ "and a first option that affirms the action; wait for the user's response,",
1421
+ "then re-issue this exact command in the same turn to run it once.",
1338
1422
  ].join(" ");
1339
1423
  safetyLogWarning("safety", `destructive command: ${classification.labels.join(", ")}`, {
1340
- command: String(event.input.command).slice(0, 200),
1424
+ command: String(command).slice(0, 200),
1341
1425
  });
1342
1426
  if (ctx) {
1343
1427
  await maybePauseAutoForApprovalGate(
1344
1428
  ctx,
1345
1429
  pi,
1346
1430
  isAutoActive(),
1347
- "Depth confirmation is waiting for your answer — pausing auto-mode.",
1431
+ "Destructive-command confirmation is waiting for your answer — pausing auto-mode.",
1348
1432
  );
1349
1433
  }
1350
1434
  return { block: true, reason };
@@ -1382,13 +1466,27 @@ export function registerHooks(
1382
1466
  } else if (isAutoActive()) {
1383
1467
  clearToolInvocationError();
1384
1468
  }
1469
+ // Interactive Closeout adapter (ADR-032): auto-mode owns closeout for its
1470
+ // own units; interactive completions get the durable git subset (commit +
1471
+ // Closeout Git Verdict) instead of silently bypassing git.isolation.
1472
+ if (!event.isError && !isAutoActive() && isUnitCloseoutTool(toolName)) {
1473
+ try {
1474
+ runInteractiveUnitCloseout({
1475
+ basePath: resolveWorkflowToolBasePath(ctx, event.input as { milestone_id?: string }),
1476
+ canonicalToolName: toolName,
1477
+ input: event.input,
1478
+ });
1479
+ } catch (err) {
1480
+ safetyLogWarning("engine", `interactive unit closeout failed: ${err instanceof Error ? err.message : String(err)}`);
1481
+ }
1482
+ }
1385
1483
  if (toolName !== "ask_user_questions") return;
1386
1484
  const basePath = contextBasePath(ctx);
1387
1485
  const milestoneId = await getDiscussionMilestoneIdFor(basePath);
1388
1486
 
1389
- const details = event.details as any;
1487
+ const details = resolveAskUserQuestionsGateDetails(event);
1390
1488
 
1391
- const questions: any[] = (event.input as any)?.questions ?? [];
1489
+ const questions: any[] = (event.input as any)?.questions ?? details?.questions ?? [];
1392
1490
  const gateResult = applyAskUserQuestionsGateResult({
1393
1491
  basePath,
1394
1492
  questions,
@@ -1419,6 +1517,24 @@ export function registerHooks(
1419
1517
  }
1420
1518
 
1421
1519
  if (details?.cancelled || !details?.response) return;
1520
+
1521
+ // Destructive-command confirmation: an affirmative answer to a
1522
+ // destructive_confirm gate promotes the pending blocked command to a
1523
+ // one-shot confirmed token, which the bash tool_call guard consumes on the
1524
+ // next attempt. Rejecting/declining leaves the command blocked.
1525
+ // (Depth-verification gate handling now lives in
1526
+ // applyAskUserQuestionsGateResult above; only the destructive-confirm gate
1527
+ // is handled inline here.)
1528
+ for (const question of questions) {
1529
+ if (isDestructiveConfirmGateId(question?.id)) {
1530
+ const answer = details.response?.answers?.[question.id];
1531
+ if (isDepthConfirmationAnswer(answer?.selected, question.options)) {
1532
+ confirmDestructiveCommand(basePath);
1533
+ }
1534
+ break;
1535
+ }
1536
+ }
1537
+
1422
1538
  if (!milestoneId) return;
1423
1539
  await saveDiscussionQuestionRound(basePath, milestoneId, questions, details);
1424
1540
  });
@@ -1429,7 +1545,24 @@ export function registerHooks(
1429
1545
  if (toolName === "ask_user_questions") {
1430
1546
  const questionId = extractGateQuestionId(event.args);
1431
1547
  if (typeof questionId === "string") {
1432
- setPendingGate(questionId, basePath);
1548
+ // External engines (claude-code-cli) ingest the SDK turn's tool blocks
1549
+ // post-hoc, so this event can fire AFTER the workflow MCP child already
1550
+ // verified this gate and allowed the CONTEXT save. setPendingGate also
1551
+ // revokes verifiedDepthMilestones/verifiedApprovalGates, so an
1552
+ // unconditional re-arm here wipes the child's verification and leaves
1553
+ // the discuss→auto handoff permanently blocked. Skip the re-arm when
1554
+ // the snapshot already records this exact gate as verified — mirrors
1555
+ // activateDeferredApprovalGate's guard. Stale verified state cannot
1556
+ // leak into a later re-discussion: a successful handoff deletes the
1557
+ // snapshot via clearDiscussionFlowState.
1558
+ const snapshot = refreshWriteGateStateFromDisk(basePath);
1559
+ const gateMilestoneId = extractDepthVerificationMilestoneId(questionId);
1560
+ const alreadyVerified =
1561
+ isApprovalGateVerifiedInSnapshot(snapshot, questionId) ||
1562
+ isMilestoneDepthVerifiedInSnapshot(snapshot, gateMilestoneId);
1563
+ if (!alreadyVerified) {
1564
+ setPendingGate(questionId, basePath);
1565
+ }
1433
1566
  clearDeferredApprovalGate(basePath);
1434
1567
  }
1435
1568
  }
@@ -1528,6 +1661,7 @@ export function registerHooks(
1528
1661
  return surfaceReduced ? { toolNames: providerCompatible } : undefined;
1529
1662
  }
1530
1663
  const registeredToolNames = resolveRegisteredToolNames(pi, event.activeToolNames);
1664
+ const hasRegisteredSurface = typeof pi.getAllTools === "function";
1531
1665
  const compatibleRegisteredToolNames = filterToolsForProvider(
1532
1666
  registeredToolNames,
1533
1667
  event.selectedModelApi,
@@ -1542,6 +1676,7 @@ export function registerHooks(
1542
1676
  event.requestCustomMessages,
1543
1677
  requestRegisteredToolNames,
1544
1678
  guidedUnit?.unitType,
1679
+ hasRegisteredSurface,
1545
1680
  );
1546
1681
  if (requestScoped) {
1547
1682
  recordAutoToolSurfaceSnapshot({
@@ -1562,6 +1697,7 @@ export function registerHooks(
1562
1697
  dash.currentUnit.type === "run-uat" ? aliasFilteredCompatible : providerCompatible,
1563
1698
  dash.currentUnit.type,
1564
1699
  registeredForUnit,
1700
+ hasRegisteredSurface,
1565
1701
  );
1566
1702
  recordAutoToolSurfaceSnapshot({
1567
1703
  source: "provider-adjustment",
@@ -251,15 +251,19 @@ export function loadWriteGateSnapshot(basePath: string): WriteGateSnapshot {
251
251
  * verification there; without this refresh the extension host keeps stale
252
252
  * pending-gate memory and `activateDeferredApprovalGate` can re-arm a gate
253
253
  * that the subprocess already cleared on disk.
254
+ *
255
+ * Returns the snapshot used for the refresh so callers that need to inspect
256
+ * it (e.g. re-arm guards) avoid a second disk read.
254
257
  */
255
- export function refreshWriteGateStateFromDisk(basePath: string): void {
256
- if (!shouldPersistWriteGateSnapshot()) return;
258
+ export function refreshWriteGateStateFromDisk(basePath: string): WriteGateSnapshot {
257
259
  const snapshot = loadWriteGateSnapshot(basePath);
260
+ if (!shouldPersistWriteGateSnapshot()) return snapshot;
258
261
  const state = getWriteGateState(basePath);
259
262
  state.pendingGateId = snapshot.pendingGateId;
260
263
  state.activeQueuePhase = snapshot.activeQueuePhase;
261
264
  state.verifiedDepthMilestones = new Set(snapshot.verifiedDepthMilestones);
262
265
  state.verifiedApprovalGates = new Set(snapshot.verifiedApprovalGates ?? []);
266
+ return snapshot;
263
267
  }
264
268
 
265
269
  export function isDepthVerified(basePath: string = process.cwd()): boolean {
@@ -14,3 +14,6 @@ export const QUICK_BRANCH_RE = /^gsd\/quick\//;
14
14
 
15
15
  /** Matches GSD-generated workflow template branches, not arbitrary user gsd/* branches. */
16
16
  export const WORKFLOW_BRANCH_RE = /^gsd\/(?:hotfix|bugfix|small-feature|refactor|spike|security-audit|dep-upgrade|full-project)\//;
17
+
18
+ /** Auto-mode milestone branch prefix: milestone/<MID>. */
19
+ export const MILESTONE_BRANCH_PREFIX = "milestone/";
@@ -0,0 +1,108 @@
1
+ import { execFileSync } from "node:child_process";
2
+ import { resolve } from "node:path";
3
+
4
+ import {
5
+ resolveAmbientBrowserEngineResolution,
6
+ resolveBrowserEngineResolution,
7
+ type BrowserEngineMode,
8
+ } from "../browser-tools/engine/selection.js";
9
+ import {
10
+ resolveGsdBrowserCliAvailability,
11
+ resolveGsdBrowserDaemonStartInvocation,
12
+ } from "../shared/gsd-browser-cli.js";
13
+ import { uatTypeIncludesBrowser, type UatType } from "./uat-policy.js";
14
+
15
+ const DEFAULT_DAEMON_START_TIMEOUT_MS = 30_000;
16
+
17
+ function isEnvDisabled(value: string | undefined): boolean {
18
+ if (!value) return false;
19
+ const normalized = value.trim().toLowerCase();
20
+ return normalized === "0" || normalized === "false" || normalized === "off";
21
+ }
22
+
23
+ function isWarmUpDisabled(env: NodeJS.ProcessEnv = process.env): boolean {
24
+ const value = env.GSD_BROWSER_WARMUP?.trim().toLowerCase();
25
+ return value === "0" || value === "false" || value === "off";
26
+ }
27
+
28
+ export interface BrowserDaemonWarmContext {
29
+ uatType: UatType;
30
+ sessionProvider?: string;
31
+ sessionAuthMode?: "apiKey" | "oauth" | "externalCli" | "none";
32
+ sessionBaseUrl?: string;
33
+ projectRoot: string;
34
+ env?: NodeJS.ProcessEnv;
35
+ }
36
+
37
+ /** Active engine for warm-up: explicit env override, else session-committed ambient resolution. */
38
+ function resolveActiveBrowserEngine(projectRoot: string, env: NodeJS.ProcessEnv): BrowserEngineMode {
39
+ if (env.GSD_BROWSER_ENGINE?.trim()) {
40
+ return resolveBrowserEngineResolution(env, projectRoot).engine;
41
+ }
42
+ return resolveAmbientBrowserEngineResolution(projectRoot).engine;
43
+ }
44
+
45
+ export function shouldWarmBrowserDaemonForUat(ctx: BrowserDaemonWarmContext): boolean {
46
+ if (!uatTypeIncludesBrowser(ctx.uatType)) return false;
47
+
48
+ const env = ctx.env ?? process.env;
49
+ if (isWarmUpDisabled(env)) return false;
50
+ if (isEnvDisabled(env.GSD_BROWSER_MCP_ENABLED)) return false;
51
+
52
+ const availability = resolveGsdBrowserCliAvailability(env);
53
+ if (!availability.available) return false;
54
+
55
+ const projectRoot = resolve(ctx.projectRoot);
56
+ return resolveActiveBrowserEngine(projectRoot, env) === "gsd-browser";
57
+ }
58
+
59
+ export function ensureBrowserDaemonStarted(
60
+ projectRoot: string,
61
+ options: { env?: NodeJS.ProcessEnv; timeoutMs?: number } = {},
62
+ ): { ok: true } | { ok: false; error: string } {
63
+ const env = options.env ?? process.env;
64
+ const availability = resolveGsdBrowserCliAvailability(env);
65
+ if (!availability.available) {
66
+ return { ok: false, error: availability.detail };
67
+ }
68
+
69
+ let invocation: ReturnType<typeof resolveGsdBrowserDaemonStartInvocation>;
70
+ try {
71
+ invocation = resolveGsdBrowserDaemonStartInvocation(projectRoot, env);
72
+ } catch (error) {
73
+ return {
74
+ ok: false,
75
+ error: error instanceof Error ? error.message : String(error),
76
+ };
77
+ }
78
+
79
+ try {
80
+ execFileSync(invocation.command, invocation.args, {
81
+ cwd: invocation.cwd,
82
+ env: { ...process.env, ...env, ...(invocation.env ?? {}) },
83
+ stdio: ["ignore", "pipe", "pipe"],
84
+ timeout: options.timeoutMs ?? DEFAULT_DAEMON_START_TIMEOUT_MS,
85
+ encoding: "utf-8",
86
+ });
87
+ return { ok: true };
88
+ } catch (error) {
89
+ return {
90
+ ok: false,
91
+ error: error instanceof Error ? error.message : String(error),
92
+ };
93
+ }
94
+ }
95
+
96
+ /**
97
+ * Best-effort pre-warm of the gsd-browser session daemon before browser-backed
98
+ * run-uat dispatch. Returns an actionable stop reason when warm-up is required
99
+ * but fails; returns null when warm-up is skipped or succeeds.
100
+ */
101
+ export function prepareBrowserDaemonForUat(ctx: BrowserDaemonWarmContext): string | null {
102
+ if (!shouldWarmBrowserDaemonForUat(ctx)) return null;
103
+
104
+ const result = ensureBrowserDaemonStarted(ctx.projectRoot, { env: ctx.env });
105
+ if (result.ok) return null;
106
+
107
+ 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.`;
108
+ }
@@ -1,9 +1,25 @@
1
1
  // Project/App: gsd-pi
2
2
  // File Purpose: Shared browser-observable UAT requirement and evidence detection.
3
3
 
4
- 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;
4
+ import { BROWSER_EVIDENCE_SIGNAL_TOOL_NAMES } from "../shared/browser-contract.js";
5
+
6
+ // Alternation fragment over the contract's evidence-signal names, e.g.
7
+ // `browser_(?:assert|batch|...)`. The names are `browser_`-prefixed
8
+ // identifiers (pinned by tests/browser-contract.test.ts), so no escaping is
9
+ // needed.
10
+ const BROWSER_TOOL_SIGNAL = `browser_(?:${
11
+ BROWSER_EVIDENCE_SIGNAL_TOOL_NAMES.map((name) => name.slice("browser_".length)).join("|")
12
+ })`;
13
+
14
+ export const BROWSER_REQUIREMENT_RE = new RegExp(
15
+ 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`,
16
+ "i",
17
+ );
5
18
  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;
6
- export const BROWSER_RUNTIME_RE = /\b(?:browser|playwright|chrome|camoufox|browser_(?:assert|batch|find|verify|snapshot_refs)|screenshot|snapshot|file:\/\/|localhost)\b/i;
19
+ export const BROWSER_RUNTIME_RE = new RegExp(
20
+ String.raw`\b(?:browser|playwright|chrome|camoufox|${BROWSER_TOOL_SIGNAL}|screenshot|snapshot|file://|localhost)\b`,
21
+ "i",
22
+ );
7
23
  export const BROWSER_ACTION_RE = /\b(?:open(?:ed)?|navigate(?:d)?|click(?:ed)?|type(?:d)?|reload(?:ed)?|capture(?:d)?|screenshot|snapshot)\b/i;
8
24
  export const BROWSER_ASSERTION_RE = /\b(?:assert(?:ed|ion)?|observed|confirmed|verified|expected|visible|text|count|label|strikethrough|localstorage|screenshot|snapshot|passed)\b/i;
9
25
  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;
@@ -12,7 +12,7 @@ import { existsSync, readFileSync, writeFileSync, mkdirSync } from "node:fs";
12
12
  import { join, resolve } from "node:path";
13
13
  import { randomUUID } from "node:crypto";
14
14
  import { gsdRoot } from "./paths.js";
15
- import { findWorktreeSegment } from "./worktree-root.js";
15
+ import { projectRootFromWorktreePath } from "./worktree-root.js";
16
16
 
17
17
  // ─── Types ────────────────────────────────────────────────────────────────────
18
18
 
@@ -60,11 +60,9 @@ const VALID_CLASSIFICATIONS: readonly string[] = [
60
60
  * directory that contains `.gsd/worktrees/` — that's the project root.
61
61
  */
62
62
  export function resolveCapturesPath(basePath: string): string {
63
- const resolved = resolve(basePath);
64
- const segment = findWorktreeSegment(resolved.replaceAll("\\", "/"));
65
- if (segment) {
66
- // basePath is inside a worktree — resolve to project root
67
- const projectRoot = resolved.slice(0, segment.gsdIdx);
63
+ // If basePath is inside a worktree, resolve to the project root.
64
+ const projectRoot = projectRootFromWorktreePath(resolve(basePath));
65
+ if (projectRoot) {
68
66
  return join(projectRoot, ".gsd", CAPTURES_FILENAME);
69
67
  }
70
68
  return join(gsdRoot(basePath), CAPTURES_FILENAME);
@@ -9,9 +9,6 @@
9
9
  /** Default timeout for verification-gate commands (ms). */
10
10
  export const DEFAULT_COMMAND_TIMEOUT_MS = 120_000;
11
11
 
12
- /** Default timeout for the dynamic bash tool (seconds). */
13
- export const DEFAULT_BASH_TIMEOUT_SECS = 120;
14
-
15
12
  // ─── Cache Sizes ──────────────────────────────────────────────────────────────
16
13
 
17
14
  /** Max directory-listing cache entries before eviction (#611). */
@@ -39,6 +39,7 @@ import { markLatestActiveForWorkerCanceled, type DispatchStatus } from "./db/uni
39
39
  import { getRuntimeKv, setRuntimeKv, deleteRuntimeKv } from "./db/runtime-kv.js";
40
40
  import { _getAdapter, isDbAvailable } from "./gsd-db.js";
41
41
  import { gsdRoot, normalizeRealPath } from "./paths.js";
42
+ import { crashResumeHint } from "./guidance.js";
42
43
  import { atomicWriteSync } from "./atomic-write.js";
43
44
  import { effectiveLockFile } from "./session-lock.js";
44
45
  import { isInFlightRuntimePhase, listUnitRuntimeRecords, type AutoUnitRuntimeRecord } from "./unit-runtime.js";
@@ -321,15 +322,8 @@ export function formatCrashInfo(lock: LockData): string {
321
322
  ` PID: ${lock.pid}`,
322
323
  ];
323
324
 
324
- if (lock.unitType === "starting" && lock.unitId === "bootstrap") {
325
- lines.push(`No work was lost. Run /gsd auto to restart.`);
326
- } else if (lock.unitType.includes("research") || lock.unitType.includes("plan")) {
327
- lines.push(`The ${lock.unitType} unit may be incomplete. Run /gsd auto to re-run it.`);
328
- } else if (lock.unitType.includes("execute")) {
329
- lines.push(`Task execution was interrupted. Run /gsd auto to resume — completed work is preserved.`);
330
- } else if (lock.unitType.includes("complete")) {
331
- lines.push(`Slice/milestone completion was interrupted. Run /gsd auto to finish.`);
332
- }
325
+ const hint = crashResumeHint(lock.unitType, lock.unitId);
326
+ if (hint) lines.push(hint);
333
327
 
334
328
  return lines.join("\n");
335
329
  }
@@ -15,7 +15,7 @@ import { join } from "node:path";
15
15
 
16
16
  import type { DoctorIssue, DoctorIssueCode } from "./doctor-types.js";
17
17
  import { detectPythonExecutable } from "./python-resolver.js";
18
- import { findWorktreeSegment } from "./worktree-root.js";
18
+ import { projectRootFromWorktreePath } from "./worktree-root.js";
19
19
 
20
20
  // ── Types ──────────────────────────────────────────────────────────────────
21
21
 
@@ -50,12 +50,7 @@ const CMD_TIMEOUT = 5_000;
50
50
  function resolveWorktreeProjectRoot(basePath: string): string | null {
51
51
  const envRoot = process.env.GSD_WORKTREE;
52
52
  if (envRoot) return envRoot;
53
-
54
- const segment = findWorktreeSegment(basePath.replace(/\\/g, "/"));
55
- if (!segment) return null;
56
-
57
- // Everything before the worktree segment is the project root
58
- return basePath.slice(0, segment.gsdIdx);
53
+ return projectRootFromWorktreePath(basePath);
59
54
  }
60
55
 
61
56
  function tryExec(cmd: string, cwd: string): string | null {
@@ -1,4 +1,9 @@
1
- import type { DoctorIssue, DoctorIssueCode, DoctorReport, DoctorSummary } from "./doctor-types.js";
1
+ import type { DoctorIssue, DoctorIssueCode, DoctorReport, DoctorSummary, DoctorSeverity } from "./doctor-types.js";
2
+ import { doctorFixHint } from "./guidance.js";
3
+
4
+ function severityTag(severity: DoctorSeverity): string {
5
+ return severity === "error" ? "ERROR" : severity === "warning" ? "WARN" : "INFO";
6
+ }
2
7
 
3
8
  function matchesScope(unitId: string, scope?: string): boolean {
4
9
  if (!scope) return true;
@@ -53,8 +58,9 @@ export function formatDoctorReport(
53
58
  if (scopedIssues.length > 0) {
54
59
  lines.push("Priority issues:");
55
60
  for (const issue of scopedIssues.slice(0, maxIssues)) {
56
- const prefix = issue.severity === "error" ? "ERROR" : issue.severity === "warning" ? "WARN" : "INFO";
57
- lines.push(`- [${prefix}] ${issue.unitId}: ${issue.message}${issue.file ? ` (${issue.file})` : ""}`);
61
+ lines.push(`- [${severityTag(issue.severity)}] ${issue.unitId}: ${issue.message}${issue.file ? ` (${issue.file})` : ""}`);
62
+ const hint = doctorFixHint(issue.code);
63
+ if (hint && issue.severity !== "info") lines.push(` Fix: ${hint}`);
58
64
  }
59
65
  if (scopedIssues.length > maxIssues) {
60
66
  lines.push(`- ...and ${scopedIssues.length - maxIssues} more in scope`);
@@ -72,10 +78,9 @@ export function formatDoctorReport(
72
78
 
73
79
  export function formatDoctorIssuesForPrompt(issues: DoctorIssue[]): string {
74
80
  if (issues.length === 0) return "- No remaining issues in scope.";
75
- return issues.map(issue => {
76
- const prefix = issue.severity === "error" ? "ERROR" : issue.severity === "warning" ? "WARN" : "INFO";
77
- return `- [${prefix}] ${issue.unitId} | ${issue.code} | ${issue.message}${issue.file ? ` | file: ${issue.file}` : ""} | fixable: ${issue.fixable ? "yes" : "no"}`;
78
- }).join("\n");
81
+ return issues.map(issue =>
82
+ `- [${severityTag(issue.severity)}] ${issue.unitId} | ${issue.code} | ${issue.message}${issue.file ? ` | file: ${issue.file}` : ""} | fixable: ${issue.fixable ? "yes" : "no"}`
83
+ ).join("\n");
79
84
  }
80
85
 
81
86
  /**
@@ -425,22 +425,20 @@ export async function checkRuntimeHealth(
425
425
  missing.push(...criticalPatterns.filter(p => !existingLines.has(p)));
426
426
  }
427
427
 
428
- {
429
- if (missing.length > 0) {
430
- issues.push({
431
- severity: "warning",
432
- code: "gitignore_missing_patterns",
433
- scope: "project",
434
- unitId: "project",
435
- message: `${missing.length} critical GSD runtime pattern(s) missing from .gitignore: ${missing.join(", ")}`,
436
- file: ".gitignore",
437
- fixable: true,
438
- });
428
+ if (missing.length > 0) {
429
+ issues.push({
430
+ severity: "warning",
431
+ code: "gitignore_missing_patterns",
432
+ scope: "project",
433
+ unitId: "project",
434
+ message: `${missing.length} critical GSD runtime pattern(s) missing from .gitignore: ${missing.join(", ")}`,
435
+ file: ".gitignore",
436
+ fixable: true,
437
+ });
439
438
 
440
- if (shouldFix("gitignore_missing_patterns")) {
441
- ensureGitignore(basePath, { manageGitignore });
442
- fixesApplied.push("added missing GSD runtime patterns to .gitignore");
443
- }
439
+ if (shouldFix("gitignore_missing_patterns")) {
440
+ ensureGitignore(basePath, { manageGitignore });
441
+ fixesApplied.push("added missing GSD runtime patterns to .gitignore");
444
442
  }
445
443
  }
446
444
  }