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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (520) hide show
  1. package/dist/cli-style.d.ts +17 -0
  2. package/dist/cli-style.js +28 -0
  3. package/dist/cli.js +1 -1
  4. package/dist/headless-events.d.ts +4 -2
  5. package/dist/headless-events.js +7 -29
  6. package/dist/models-resolver.d.ts +3 -13
  7. package/dist/models-resolver.js +3 -22
  8. package/dist/resource-loader.js +2 -14
  9. package/dist/resources/.managed-resources-content-hash +1 -1
  10. package/dist/resources/extensions/async-jobs/async-bash-tool.js +30 -64
  11. package/dist/resources/extensions/async-jobs/await-tool.js +80 -12
  12. package/dist/resources/extensions/async-jobs/index.js +65 -0
  13. package/dist/resources/extensions/async-jobs/job-manager.js +12 -1
  14. package/dist/resources/extensions/bg-shell/bg-shell-command.js +6 -6
  15. package/dist/resources/extensions/bg-shell/bg-shell-tool.js +10 -7
  16. package/dist/resources/extensions/bg-shell/overlay.js +9 -6
  17. package/dist/resources/extensions/bg-shell/process-manager.js +54 -25
  18. package/dist/resources/extensions/bg-shell/readiness-detector.js +11 -0
  19. package/dist/resources/extensions/bg-shell/utilities.js +5 -2
  20. package/dist/resources/extensions/browser-tools/engine/managed-gsd-browser.js +209 -88
  21. package/dist/resources/extensions/browser-tools/engine/selection.js +73 -5
  22. package/dist/resources/extensions/browser-tools/index.js +69 -12
  23. package/dist/resources/extensions/claude-code-cli/models.js +9 -0
  24. package/dist/resources/extensions/claude-code-cli/stream-adapter.js +38 -6
  25. package/dist/resources/extensions/gsd/auto/orchestrator.js +40 -9
  26. package/dist/resources/extensions/gsd/auto/phases.js +6 -1
  27. package/dist/resources/extensions/gsd/auto-dispatch.js +12 -1
  28. package/dist/resources/extensions/gsd/auto-model-selection.js +25 -6
  29. package/dist/resources/extensions/gsd/auto-post-unit.js +19 -8
  30. package/dist/resources/extensions/gsd/auto-prompts.js +15 -10
  31. package/dist/resources/extensions/gsd/auto-start.js +21 -21
  32. package/dist/resources/extensions/gsd/auto-tool-tracking.js +18 -0
  33. package/dist/resources/extensions/gsd/auto-unit-tool-scope.js +7 -16
  34. package/dist/resources/extensions/gsd/auto-worktree-repair.js +10 -2
  35. package/dist/resources/extensions/gsd/auto-worktree.js +35 -352
  36. package/dist/resources/extensions/gsd/auto.js +8 -20
  37. package/dist/resources/extensions/gsd/bootstrap/agent-end-recovery.js +3 -2
  38. package/dist/resources/extensions/gsd/bootstrap/dynamic-tools.js +32 -12
  39. package/dist/resources/extensions/gsd/bootstrap/register-extension.js +19 -0
  40. package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +151 -20
  41. package/dist/resources/extensions/gsd/bootstrap/write-gate.js +30 -4
  42. package/dist/resources/extensions/gsd/branch-patterns.js +2 -0
  43. package/dist/resources/extensions/gsd/browser-daemon-auto-prep.js +83 -0
  44. package/dist/resources/extensions/gsd/browser-evidence.js +8 -2
  45. package/dist/resources/extensions/gsd/captures.js +5 -15
  46. package/dist/resources/extensions/gsd/closeout-recovery.js +3 -2
  47. package/dist/resources/extensions/gsd/commands/catalog.js +6 -62
  48. package/dist/resources/extensions/gsd/constants.js +0 -2
  49. package/dist/resources/extensions/gsd/crash-recovery.js +4 -12
  50. package/dist/resources/extensions/gsd/db/engine.js +755 -0
  51. package/dist/resources/extensions/gsd/db/queries.js +372 -0
  52. package/dist/resources/extensions/gsd/db/sql-constants.js +11 -0
  53. package/dist/resources/extensions/gsd/db/writers/cascades.js +194 -0
  54. package/dist/resources/extensions/gsd/db/writers/import-restore.js +182 -0
  55. package/dist/resources/extensions/gsd/db/writers/memory.js +149 -0
  56. package/dist/resources/extensions/gsd/db/writers/reconcile.js +458 -0
  57. package/dist/resources/extensions/gsd/db/writers/status.js +70 -0
  58. package/dist/resources/extensions/gsd/doctor-environment.js +5 -11
  59. package/dist/resources/extensions/gsd/doctor-format.js +9 -6
  60. package/dist/resources/extensions/gsd/doctor-git-checks.js +4 -3
  61. package/dist/resources/extensions/gsd/doctor-runtime-checks.js +21 -16
  62. package/dist/resources/extensions/gsd/error-classifier.js +9 -0
  63. package/dist/resources/extensions/gsd/exec-sandbox.js +30 -10
  64. package/dist/resources/extensions/gsd/git-service.js +1 -0
  65. package/dist/resources/extensions/gsd/gitignore.js +3 -0
  66. package/dist/resources/extensions/gsd/gsd-db.js +171 -2048
  67. package/dist/resources/extensions/gsd/guidance.js +98 -0
  68. package/dist/resources/extensions/gsd/guided-flow.js +51 -5
  69. package/dist/resources/extensions/gsd/mcp-filter.js +2 -19
  70. package/dist/resources/extensions/gsd/mcp-tool-name.js +5 -13
  71. package/dist/resources/extensions/gsd/memory-consolidation-scanner.js +1 -1
  72. package/dist/resources/extensions/gsd/migrate/safety.js +20 -9
  73. package/dist/resources/extensions/gsd/migration-auto-check.js +24 -3
  74. package/dist/resources/extensions/gsd/model-cost-table.js +1 -0
  75. package/dist/resources/extensions/gsd/model-router.js +3 -0
  76. package/dist/resources/extensions/gsd/notification-store.js +11 -4
  77. package/dist/resources/extensions/gsd/parallel-merge.js +14 -11
  78. package/dist/resources/extensions/gsd/parallel-monitor-overlay.js +11 -7
  79. package/dist/resources/extensions/gsd/paths.js +37 -24
  80. package/dist/resources/extensions/gsd/pre-execution-checks.js +91 -3
  81. package/dist/resources/extensions/gsd/preferences-models.js +14 -48
  82. package/dist/resources/extensions/gsd/preferences.js +14 -0
  83. package/dist/resources/extensions/gsd/prompts/complete-slice.md +1 -1
  84. package/dist/resources/extensions/gsd/prompts/plan-slice.md +1 -1
  85. package/dist/resources/extensions/gsd/prompts/refine-slice.md +1 -1
  86. package/dist/resources/extensions/gsd/prompts/replan-slice.md +1 -1
  87. package/dist/resources/extensions/gsd/prompts/run-uat.md +1 -1
  88. package/dist/resources/extensions/gsd/prompts/system.md +5 -2
  89. package/dist/resources/extensions/gsd/provider-error-guidance.js +1 -5
  90. package/dist/resources/extensions/gsd/provider-switch-observer.js +1 -1
  91. package/dist/resources/extensions/gsd/publication.js +87 -0
  92. package/dist/resources/extensions/gsd/recovery-classification.js +41 -87
  93. package/dist/resources/extensions/gsd/safety/destructive-confirmation.js +108 -0
  94. package/dist/resources/extensions/gsd/safety/evidence-collector.js +37 -4
  95. package/dist/resources/extensions/gsd/safety/evidence-cross-ref.js +7 -2
  96. package/dist/resources/extensions/gsd/safety/file-change-validator.js +10 -0
  97. package/dist/resources/extensions/gsd/state-transition-matrix.js +38 -0
  98. package/dist/resources/extensions/gsd/state.js +1 -20
  99. package/dist/resources/extensions/gsd/status-guards.js +56 -8
  100. package/dist/resources/extensions/gsd/stop-notice.js +57 -0
  101. package/dist/resources/extensions/gsd/tool-surface-readiness.js +56 -0
  102. package/dist/resources/extensions/gsd/tools/complete-slice.js +24 -43
  103. package/dist/resources/extensions/gsd/tools/exec-tool.js +10 -8
  104. package/dist/resources/extensions/gsd/tools/plan-slice.js +12 -6
  105. package/dist/resources/extensions/gsd/tools/reopen-milestone.js +11 -29
  106. package/dist/resources/extensions/gsd/tools/reopen-slice.js +14 -33
  107. package/dist/resources/extensions/gsd/tools/skip-slice.js +18 -36
  108. package/dist/resources/extensions/gsd/uat-policy.js +2 -1
  109. package/dist/resources/extensions/gsd/undo.js +8 -7
  110. package/dist/resources/extensions/gsd/unit-closeout.js +138 -0
  111. package/dist/resources/extensions/gsd/unit-context-composer.js +74 -1
  112. package/dist/resources/extensions/gsd/unit-context-manifest.js +4 -27
  113. package/dist/resources/extensions/gsd/unit-registry.js +337 -0
  114. package/dist/resources/extensions/gsd/unit-tool-contracts.js +9 -182
  115. package/dist/resources/extensions/gsd/web-app-uat.js +45 -8
  116. package/dist/resources/extensions/gsd/workflow-tool-surface.js +1 -1
  117. package/dist/resources/extensions/gsd/worktree-git-recovery.js +293 -0
  118. package/dist/resources/extensions/gsd/worktree-lifecycle.js +9 -1
  119. package/dist/resources/extensions/gsd/worktree-manager.js +45 -28
  120. package/dist/resources/extensions/gsd/worktree-placement.js +59 -0
  121. package/dist/resources/extensions/gsd/worktree-reentry.js +12 -8
  122. package/dist/resources/extensions/gsd/worktree-root.js +28 -6
  123. package/dist/resources/extensions/gsd/worktree-safety.js +8 -5
  124. package/dist/resources/extensions/gsd/worktree-session-state.js +12 -11
  125. package/dist/resources/extensions/search-the-web/native-search.js +5 -3
  126. package/dist/resources/extensions/shared/browser-contract.js +59 -0
  127. package/dist/resources/extensions/shared/gsd-browser-cli.js +96 -5
  128. package/dist/resources/shared/package.json +3 -0
  129. package/dist/resources/skills/create-skill/references/executable-code.md +1 -1
  130. package/dist/resources/skills/create-skill/workflows/add-reference.md +8 -3
  131. package/dist/resources/skills/create-skill/workflows/add-script.md +4 -2
  132. package/dist/resources/skills/create-skill/workflows/add-template.md +3 -1
  133. package/dist/resources/skills/create-skill/workflows/add-workflow.md +8 -3
  134. package/dist/resources/skills/create-skill/workflows/upgrade-to-router.md +10 -5
  135. package/dist/resources/skills/create-skill/workflows/verify-skill.md +9 -4
  136. package/dist/resources/skills/gsd-browser/SKILL.md +1 -1
  137. package/dist/resources/skills/spike-wrap-up/SKILL.md +9 -9
  138. package/dist/tsconfig.extensions.tsbuildinfo +1 -1
  139. package/dist/web/standalone/.next/BUILD_ID +1 -1
  140. package/dist/web/standalone/.next/app-path-routes-manifest.json +10 -10
  141. package/dist/web/standalone/.next/build-manifest.json +3 -3
  142. package/dist/web/standalone/.next/prerender-manifest.json +3 -3
  143. package/dist/web/standalone/.next/react-loadable-manifest.json +1 -1
  144. package/dist/web/standalone/.next/server/app/_global-error.html +1 -1
  145. package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
  146. package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  147. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
  148. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
  149. package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  150. package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  151. package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  152. package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
  153. package/dist/web/standalone/.next/server/app/_not-found.rsc +1 -1
  154. package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
  155. package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  156. package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +1 -1
  157. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  158. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  159. package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
  160. package/dist/web/standalone/.next/server/app/api/boot/route.js.nft.json +1 -1
  161. package/dist/web/standalone/.next/server/app/api/bridge-terminal/input/route.js.nft.json +1 -1
  162. package/dist/web/standalone/.next/server/app/api/bridge-terminal/resize/route.js.nft.json +1 -1
  163. package/dist/web/standalone/.next/server/app/api/bridge-terminal/stream/route.js.nft.json +1 -1
  164. package/dist/web/standalone/.next/server/app/api/captures/route.js.nft.json +1 -1
  165. package/dist/web/standalone/.next/server/app/api/cleanup/route.js.nft.json +1 -1
  166. package/dist/web/standalone/.next/server/app/api/doctor/route.js.nft.json +1 -1
  167. package/dist/web/standalone/.next/server/app/api/export-data/route.js.nft.json +1 -1
  168. package/dist/web/standalone/.next/server/app/api/files/route.js.nft.json +1 -1
  169. package/dist/web/standalone/.next/server/app/api/forensics/route.js.nft.json +1 -1
  170. package/dist/web/standalone/.next/server/app/api/git/route.js.nft.json +1 -1
  171. package/dist/web/standalone/.next/server/app/api/history/route.js.nft.json +1 -1
  172. package/dist/web/standalone/.next/server/app/api/hooks/route.js.nft.json +1 -1
  173. package/dist/web/standalone/.next/server/app/api/inspect/route.js.nft.json +1 -1
  174. package/dist/web/standalone/.next/server/app/api/knowledge/route.js.nft.json +1 -1
  175. package/dist/web/standalone/.next/server/app/api/live-state/route.js.nft.json +1 -1
  176. package/dist/web/standalone/.next/server/app/api/mcp-connections/route.js.nft.json +1 -1
  177. package/dist/web/standalone/.next/server/app/api/notifications/route.js.nft.json +1 -1
  178. package/dist/web/standalone/.next/server/app/api/onboarding/route.js.nft.json +1 -1
  179. package/dist/web/standalone/.next/server/app/api/projects/route.js.nft.json +1 -1
  180. package/dist/web/standalone/.next/server/app/api/recovery/route.js.nft.json +1 -1
  181. package/dist/web/standalone/.next/server/app/api/session/browser/route.js.nft.json +1 -1
  182. package/dist/web/standalone/.next/server/app/api/session/command/route.js.nft.json +1 -1
  183. package/dist/web/standalone/.next/server/app/api/session/events/route.js.nft.json +1 -1
  184. package/dist/web/standalone/.next/server/app/api/session/manage/route.js.nft.json +1 -1
  185. package/dist/web/standalone/.next/server/app/api/settings-data/route.js.nft.json +1 -1
  186. package/dist/web/standalone/.next/server/app/api/shutdown/route.js.nft.json +1 -1
  187. package/dist/web/standalone/.next/server/app/api/skill-health/route.js.nft.json +1 -1
  188. package/dist/web/standalone/.next/server/app/api/steer/route.js.nft.json +1 -1
  189. package/dist/web/standalone/.next/server/app/api/switch-root/route.js.nft.json +1 -1
  190. package/dist/web/standalone/.next/server/app/api/terminal/sessions/route.js.nft.json +1 -1
  191. package/dist/web/standalone/.next/server/app/api/terminal/stream/route.js.nft.json +1 -1
  192. package/dist/web/standalone/.next/server/app/api/undo/route.js.nft.json +1 -1
  193. package/dist/web/standalone/.next/server/app/api/update/route.js +1 -1
  194. package/dist/web/standalone/.next/server/app/api/update/route.js.nft.json +1 -1
  195. package/dist/web/standalone/.next/server/app/api/visualizer/route.js.nft.json +1 -1
  196. package/dist/web/standalone/.next/server/app/index.html +1 -1
  197. package/dist/web/standalone/.next/server/app/index.rsc +1 -1
  198. package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +1 -1
  199. package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +1 -1
  200. package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
  201. package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +1 -1
  202. package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
  203. package/dist/web/standalone/.next/server/app-paths-manifest.json +10 -10
  204. package/dist/web/standalone/.next/server/chunks/5124.js +1 -1
  205. package/dist/web/standalone/.next/server/chunks/{5047.js → 5942.js} +2 -2
  206. package/dist/web/standalone/.next/server/chunks/8357.js +1 -1
  207. package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
  208. package/dist/web/standalone/.next/server/middleware-react-loadable-manifest.js +1 -1
  209. package/dist/web/standalone/.next/server/pages/404.html +1 -1
  210. package/dist/web/standalone/.next/server/pages/500.html +1 -1
  211. package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
  212. package/dist/web/standalone/.next/static/chunks/{796.cf859a427a2cb2ac.js → 796.e0bdc932325d7e03.js} +1 -1
  213. package/dist/web/standalone/.next/static/chunks/{webpack-fbea77b5f9953368.js → webpack-f0285ce91d4ec9ef.js} +1 -1
  214. package/dist/web/standalone/node_modules/node-pty/build/Makefile +1 -1
  215. package/dist/web/standalone/node_modules/postcss/lib/container.js +18 -26
  216. package/dist/web/standalone/node_modules/postcss/lib/css-syntax-error.js +14 -47
  217. package/dist/web/standalone/node_modules/postcss/lib/declaration.js +4 -4
  218. package/dist/web/standalone/node_modules/postcss/lib/fromJSON.js +3 -3
  219. package/dist/web/standalone/node_modules/postcss/lib/input.js +29 -54
  220. package/dist/web/standalone/node_modules/postcss/lib/lazy-result.js +37 -47
  221. package/dist/web/standalone/node_modules/postcss/lib/map-generator.js +9 -26
  222. package/dist/web/standalone/node_modules/postcss/lib/no-work-result.js +55 -57
  223. package/dist/web/standalone/node_modules/postcss/lib/node.js +31 -99
  224. package/dist/web/standalone/node_modules/postcss/lib/parse.js +1 -1
  225. package/dist/web/standalone/node_modules/postcss/lib/parser.js +9 -10
  226. package/dist/web/standalone/node_modules/postcss/lib/postcss.js +12 -12
  227. package/dist/web/standalone/node_modules/postcss/lib/previous-map.js +11 -30
  228. package/dist/web/standalone/node_modules/postcss/lib/processor.js +7 -7
  229. package/dist/web/standalone/node_modules/postcss/lib/result.js +5 -5
  230. package/dist/web/standalone/node_modules/postcss/lib/rule.js +6 -6
  231. package/dist/web/standalone/node_modules/postcss/lib/stringifier.js +28 -69
  232. package/dist/web/standalone/node_modules/postcss/lib/tokenize.js +2 -6
  233. package/dist/web/standalone/node_modules/postcss/package.json +48 -48
  234. package/dist/web/standalone/package.json +1 -1
  235. package/dist/worktree-cli.js +3 -6
  236. package/dist/worktree-status-banner.js +7 -11
  237. package/package.json +1 -1
  238. package/packages/cloud-mcp-gateway/package.json +2 -2
  239. package/packages/contracts/dist/rpc.d.ts +1 -0
  240. package/packages/contracts/dist/rpc.d.ts.map +1 -1
  241. package/packages/contracts/dist/rpc.js.map +1 -1
  242. package/packages/contracts/dist/workflow.d.ts +4 -0
  243. package/packages/contracts/dist/workflow.d.ts.map +1 -1
  244. package/packages/contracts/dist/workflow.js.map +1 -1
  245. package/packages/contracts/package.json +1 -1
  246. package/packages/daemon/package.json +4 -4
  247. package/packages/gsd-agent-core/package.json +5 -5
  248. package/packages/gsd-agent-modes/dist/modes/interactive/components/tool-execution.d.ts +5 -0
  249. package/packages/gsd-agent-modes/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
  250. package/packages/gsd-agent-modes/dist/modes/interactive/components/tool-execution.js +8 -0
  251. package/packages/gsd-agent-modes/dist/modes/interactive/components/tool-execution.js.map +1 -1
  252. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-controller.d.ts.map +1 -1
  253. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-controller.js +7 -0
  254. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-controller.js.map +1 -1
  255. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/input-controller.d.ts.map +1 -1
  256. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/input-controller.js +8 -1
  257. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/input-controller.js.map +1 -1
  258. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-chat-render.d.ts.map +1 -1
  259. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-chat-render.js +11 -1
  260. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-chat-render.js.map +1 -1
  261. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-selectors-auth.d.ts.map +1 -1
  262. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-selectors-auth.js +4 -4
  263. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-selectors-auth.js.map +1 -1
  264. package/packages/gsd-agent-modes/dist/modes/rpc/rpc-mode.d.ts.map +1 -1
  265. package/packages/gsd-agent-modes/dist/modes/rpc/rpc-mode.js +3 -1
  266. package/packages/gsd-agent-modes/dist/modes/rpc/rpc-mode.js.map +1 -1
  267. package/packages/gsd-agent-modes/package.json +7 -7
  268. package/packages/mcp-server/dist/cli.js +6 -3
  269. package/packages/mcp-server/dist/cli.js.map +1 -1
  270. package/packages/mcp-server/dist/workflow-tools.d.ts +8 -0
  271. package/packages/mcp-server/dist/workflow-tools.d.ts.map +1 -1
  272. package/packages/mcp-server/dist/workflow-tools.js +46 -21
  273. package/packages/mcp-server/dist/workflow-tools.js.map +1 -1
  274. package/packages/mcp-server/package.json +3 -3
  275. package/packages/native/package.json +1 -1
  276. package/packages/pi-agent-core/dist/harness/env/nodejs.d.ts +1 -0
  277. package/packages/pi-agent-core/dist/harness/env/nodejs.d.ts.map +1 -1
  278. package/packages/pi-agent-core/dist/harness/env/nodejs.js +34 -3
  279. package/packages/pi-agent-core/dist/harness/env/nodejs.js.map +1 -1
  280. package/packages/pi-agent-core/dist/index.d.ts +1 -0
  281. package/packages/pi-agent-core/dist/index.d.ts.map +1 -1
  282. package/packages/pi-agent-core/dist/index.js +3 -0
  283. package/packages/pi-agent-core/dist/index.js.map +1 -1
  284. package/packages/pi-agent-core/package.json +1 -1
  285. package/packages/pi-ai/dist/image-models.generated.d.ts +2 -2
  286. package/packages/pi-ai/dist/image-models.generated.js +6 -6
  287. package/packages/pi-ai/dist/image-models.generated.js.map +1 -1
  288. package/packages/pi-ai/dist/models.generated.d.ts +478 -484
  289. package/packages/pi-ai/dist/models.generated.d.ts.map +1 -1
  290. package/packages/pi-ai/dist/models.generated.js +500 -533
  291. package/packages/pi-ai/dist/models.generated.js.map +1 -1
  292. package/packages/pi-ai/package.json +1 -1
  293. package/packages/pi-coding-agent/dist/core/auth-storage.d.ts +2 -2
  294. package/packages/pi-coding-agent/dist/core/auth-storage.d.ts.map +1 -1
  295. package/packages/pi-coding-agent/dist/core/auth-storage.js +19 -13
  296. package/packages/pi-coding-agent/dist/core/auth-storage.js.map +1 -1
  297. package/packages/pi-coding-agent/dist/core/capability-patches.d.ts.map +1 -1
  298. package/packages/pi-coding-agent/dist/core/capability-patches.js +3 -1
  299. package/packages/pi-coding-agent/dist/core/capability-patches.js.map +1 -1
  300. package/packages/pi-coding-agent/dist/core/provider-readiness.d.ts.map +1 -1
  301. package/packages/pi-coding-agent/dist/core/provider-readiness.js +13 -6
  302. package/packages/pi-coding-agent/dist/core/provider-readiness.js.map +1 -1
  303. package/packages/pi-coding-agent/dist/core/tools/bash.d.ts +11 -0
  304. package/packages/pi-coding-agent/dist/core/tools/bash.d.ts.map +1 -1
  305. package/packages/pi-coding-agent/dist/core/tools/bash.js +53 -11
  306. package/packages/pi-coding-agent/dist/core/tools/bash.js.map +1 -1
  307. package/packages/pi-coding-agent/dist/index.d.ts +1 -1
  308. package/packages/pi-coding-agent/dist/index.d.ts.map +1 -1
  309. package/packages/pi-coding-agent/dist/index.js +1 -1
  310. package/packages/pi-coding-agent/dist/index.js.map +1 -1
  311. package/packages/pi-coding-agent/dist/utils/shell.d.ts +28 -2
  312. package/packages/pi-coding-agent/dist/utils/shell.d.ts.map +1 -1
  313. package/packages/pi-coding-agent/dist/utils/shell.js +56 -10
  314. package/packages/pi-coding-agent/dist/utils/shell.js.map +1 -1
  315. package/packages/pi-coding-agent/package.json +7 -7
  316. package/packages/pi-tui/dist/tui.d.ts.map +1 -1
  317. package/packages/pi-tui/dist/tui.js +9 -0
  318. package/packages/pi-tui/dist/tui.js.map +1 -1
  319. package/packages/pi-tui/package.json +2 -2
  320. package/packages/rpc-client/package.json +2 -2
  321. package/pkg/package.json +1 -1
  322. package/src/resources/extensions/async-jobs/async-bash-cancel.test.ts +360 -0
  323. package/src/resources/extensions/async-jobs/async-bash-tool.ts +33 -56
  324. package/src/resources/extensions/async-jobs/await-tool.test.ts +139 -0
  325. package/src/resources/extensions/async-jobs/await-tool.ts +82 -12
  326. package/src/resources/extensions/async-jobs/index.ts +79 -0
  327. package/src/resources/extensions/async-jobs/job-manager.ts +21 -1
  328. package/src/resources/extensions/bg-shell/bg-shell-command.ts +6 -6
  329. package/src/resources/extensions/bg-shell/bg-shell-tool.ts +10 -6
  330. package/src/resources/extensions/bg-shell/overlay.ts +9 -5
  331. package/src/resources/extensions/bg-shell/process-manager.ts +50 -25
  332. package/src/resources/extensions/bg-shell/readiness-detector.ts +12 -0
  333. package/src/resources/extensions/bg-shell/tests/lifecycle-and-utilities.test.ts +48 -1
  334. package/src/resources/extensions/bg-shell/utilities.ts +5 -2
  335. package/src/resources/extensions/browser-tools/engine/managed-gsd-browser.ts +265 -98
  336. package/src/resources/extensions/browser-tools/engine/selection.ts +90 -4
  337. package/src/resources/extensions/browser-tools/index.ts +71 -13
  338. package/src/resources/extensions/browser-tools/tests/browser-engine-selection.test.mjs +83 -13
  339. package/src/resources/extensions/browser-tools/tests/gsd-browser-launch-config.test.mjs +29 -1
  340. package/src/resources/extensions/browser-tools/tests/managed-gsd-browser-tools.test.mjs +136 -0
  341. package/src/resources/extensions/claude-code-cli/models.ts +9 -0
  342. package/src/resources/extensions/claude-code-cli/stream-adapter.ts +40 -4
  343. package/src/resources/extensions/claude-code-cli/tests/stream-adapter.test.ts +28 -0
  344. package/src/resources/extensions/gsd/auto/loop-deps.ts +1 -1
  345. package/src/resources/extensions/gsd/auto/orchestrator.ts +46 -10
  346. package/src/resources/extensions/gsd/auto/phases.ts +10 -1
  347. package/src/resources/extensions/gsd/auto-dispatch.ts +12 -0
  348. package/src/resources/extensions/gsd/auto-model-selection.ts +25 -5
  349. package/src/resources/extensions/gsd/auto-post-unit.ts +25 -7
  350. package/src/resources/extensions/gsd/auto-prompts.ts +40 -26
  351. package/src/resources/extensions/gsd/auto-start.ts +21 -22
  352. package/src/resources/extensions/gsd/auto-tool-tracking.ts +19 -0
  353. package/src/resources/extensions/gsd/auto-unit-tool-scope.ts +10 -17
  354. package/src/resources/extensions/gsd/auto-worktree-repair.ts +13 -2
  355. package/src/resources/extensions/gsd/auto-worktree.ts +41 -364
  356. package/src/resources/extensions/gsd/auto.ts +20 -24
  357. package/src/resources/extensions/gsd/bootstrap/agent-end-recovery.ts +3 -5
  358. package/src/resources/extensions/gsd/bootstrap/dynamic-tools.ts +33 -12
  359. package/src/resources/extensions/gsd/bootstrap/register-extension.ts +24 -0
  360. package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +180 -15
  361. package/src/resources/extensions/gsd/bootstrap/write-gate.ts +29 -3
  362. package/src/resources/extensions/gsd/branch-patterns.ts +3 -0
  363. package/src/resources/extensions/gsd/browser-daemon-auto-prep.ts +108 -0
  364. package/src/resources/extensions/gsd/browser-evidence.ts +18 -2
  365. package/src/resources/extensions/gsd/captures.ts +5 -16
  366. package/src/resources/extensions/gsd/closeout-recovery.ts +2 -1
  367. package/src/resources/extensions/gsd/commands/catalog.ts +6 -68
  368. package/src/resources/extensions/gsd/constants.ts +0 -3
  369. package/src/resources/extensions/gsd/crash-recovery.ts +3 -9
  370. package/src/resources/extensions/gsd/db/engine.ts +809 -0
  371. package/src/resources/extensions/gsd/db/queries.ts +453 -0
  372. package/src/resources/extensions/gsd/db/sql-constants.ts +12 -0
  373. package/src/resources/extensions/gsd/db/writers/cascades.ts +237 -0
  374. package/src/resources/extensions/gsd/db/writers/import-restore.ts +310 -0
  375. package/src/resources/extensions/gsd/db/writers/memory.ts +220 -0
  376. package/src/resources/extensions/gsd/db/writers/reconcile.ts +500 -0
  377. package/src/resources/extensions/gsd/db/writers/status.ts +88 -0
  378. package/src/resources/extensions/gsd/doctor-environment.ts +5 -13
  379. package/src/resources/extensions/gsd/doctor-format.ts +12 -7
  380. package/src/resources/extensions/gsd/doctor-git-checks.ts +3 -3
  381. package/src/resources/extensions/gsd/doctor-runtime-checks.ts +22 -17
  382. package/src/resources/extensions/gsd/error-classifier.ts +11 -0
  383. package/src/resources/extensions/gsd/exec-sandbox.ts +49 -9
  384. package/src/resources/extensions/gsd/git-service.ts +1 -0
  385. package/src/resources/extensions/gsd/gitignore.ts +3 -0
  386. package/src/resources/extensions/gsd/gsd-db.ts +173 -2373
  387. package/src/resources/extensions/gsd/guidance.ts +139 -0
  388. package/src/resources/extensions/gsd/guided-flow.ts +50 -5
  389. package/src/resources/extensions/gsd/mcp-filter.ts +2 -23
  390. package/src/resources/extensions/gsd/mcp-tool-name.ts +6 -11
  391. package/src/resources/extensions/gsd/memory-consolidation-scanner.ts +1 -1
  392. package/src/resources/extensions/gsd/migrate/safety.ts +18 -7
  393. package/src/resources/extensions/gsd/migration-auto-check.ts +28 -3
  394. package/src/resources/extensions/gsd/model-cost-table.ts +1 -0
  395. package/src/resources/extensions/gsd/model-router.ts +3 -0
  396. package/src/resources/extensions/gsd/notification-store.ts +26 -3
  397. package/src/resources/extensions/gsd/parallel-merge.ts +12 -9
  398. package/src/resources/extensions/gsd/parallel-monitor-overlay.ts +10 -7
  399. package/src/resources/extensions/gsd/paths.ts +42 -22
  400. package/src/resources/extensions/gsd/pre-execution-checks.ts +109 -3
  401. package/src/resources/extensions/gsd/preferences-models.ts +12 -47
  402. package/src/resources/extensions/gsd/preferences.ts +18 -0
  403. package/src/resources/extensions/gsd/prompts/complete-slice.md +1 -1
  404. package/src/resources/extensions/gsd/prompts/plan-slice.md +1 -1
  405. package/src/resources/extensions/gsd/prompts/refine-slice.md +1 -1
  406. package/src/resources/extensions/gsd/prompts/replan-slice.md +1 -1
  407. package/src/resources/extensions/gsd/prompts/run-uat.md +1 -1
  408. package/src/resources/extensions/gsd/prompts/system.md +5 -2
  409. package/src/resources/extensions/gsd/provider-error-guidance.ts +4 -9
  410. package/src/resources/extensions/gsd/provider-switch-observer.ts +1 -1
  411. package/src/resources/extensions/gsd/publication.ts +122 -0
  412. package/src/resources/extensions/gsd/recovery-classification.ts +47 -88
  413. package/src/resources/extensions/gsd/safety/destructive-confirmation.ts +134 -0
  414. package/src/resources/extensions/gsd/safety/evidence-collector.ts +36 -4
  415. package/src/resources/extensions/gsd/safety/evidence-cross-ref.ts +7 -2
  416. package/src/resources/extensions/gsd/safety/file-change-validator.ts +14 -0
  417. package/src/resources/extensions/gsd/state-transition-matrix.ts +42 -0
  418. package/src/resources/extensions/gsd/state.ts +4 -21
  419. package/src/resources/extensions/gsd/status-guards.ts +59 -8
  420. package/src/resources/extensions/gsd/stop-notice.ts +75 -0
  421. package/src/resources/extensions/gsd/tests/auto-loop.test.ts +123 -0
  422. package/src/resources/extensions/gsd/tests/auto-model-selection.test.ts +22 -0
  423. package/src/resources/extensions/gsd/tests/auto-orchestrator.test.ts +16 -19
  424. package/src/resources/extensions/gsd/tests/auto-paused-ui-cleanup.test.ts +3 -1
  425. package/src/resources/extensions/gsd/tests/auto-post-unit-evidence-crossref-4909.test.ts +46 -0
  426. package/src/resources/extensions/gsd/tests/auto-worktree-registry.test.ts +2 -2
  427. package/src/resources/extensions/gsd/tests/auto-worktree-repair.test.ts +4 -2
  428. package/src/resources/extensions/gsd/tests/browser-automation-contract-fixture.ts +39 -0
  429. package/src/resources/extensions/gsd/tests/browser-contract.test.ts +44 -0
  430. package/src/resources/extensions/gsd/tests/browser-daemon-auto-prep.test.ts +144 -0
  431. package/src/resources/extensions/gsd/tests/checkout-branch-stash-guard.test.ts +66 -1
  432. package/src/resources/extensions/gsd/tests/clear-stale-autostart.test.ts +44 -0
  433. package/src/resources/extensions/gsd/tests/commands-verdict.test.ts +8 -7
  434. package/src/resources/extensions/gsd/tests/destructive-confirmation.test.ts +303 -0
  435. package/src/resources/extensions/gsd/tests/dispatch-run-uat-browser-tools.test.ts +2 -1
  436. package/src/resources/extensions/gsd/tests/dynamic-bash-no-cap.test.ts +132 -0
  437. package/src/resources/extensions/gsd/tests/evidence-xref-gsd-exec.test.ts +157 -0
  438. package/src/resources/extensions/gsd/tests/exec-graceful-kill.test.ts +193 -0
  439. package/src/resources/extensions/gsd/tests/exec-tool.test.ts +29 -1
  440. package/src/resources/extensions/gsd/tests/extension-bootstrap-isolation.test.ts +35 -1
  441. package/src/resources/extensions/gsd/tests/file-change-validator.test.ts +33 -1
  442. package/src/resources/extensions/gsd/tests/guidance.test.ts +125 -0
  443. package/src/resources/extensions/gsd/tests/integration/auto-worktree-milestone-merge.test.ts +58 -15
  444. package/src/resources/extensions/gsd/tests/integration/auto-worktree.test.ts +74 -59
  445. package/src/resources/extensions/gsd/tests/integration/git-service.test.ts +3 -2
  446. package/src/resources/extensions/gsd/tests/integration/gsd-integration-fixture.ts +80 -0
  447. package/src/resources/extensions/gsd/tests/mcp-project-config.test.ts +3 -1
  448. package/src/resources/extensions/gsd/tests/migration-auto-check.test.ts +85 -1
  449. package/src/resources/extensions/gsd/tests/model-unittype-mapping.test.ts +32 -1
  450. package/src/resources/extensions/gsd/tests/notification-store.test.ts +32 -0
  451. package/src/resources/extensions/gsd/tests/oauth-api-model-routing.test.ts +167 -0
  452. package/src/resources/extensions/gsd/tests/pre-execution-checks.test.ts +193 -1
  453. package/src/resources/extensions/gsd/tests/provider-error-guidance.test.ts +3 -3
  454. package/src/resources/extensions/gsd/tests/publication.test.ts +120 -0
  455. package/src/resources/extensions/gsd/tests/recovery-classification-illegal-transition.test.ts +30 -0
  456. package/src/resources/extensions/gsd/tests/register-hooks-depth-verification.test.ts +248 -1
  457. package/src/resources/extensions/gsd/tests/runtime-invariant-modules.test.ts +1 -0
  458. package/src/resources/extensions/gsd/tests/safety-harness-false-positives.test.ts +38 -0
  459. package/src/resources/extensions/gsd/tests/session-switch-clears-pending-autostart.test.ts +108 -0
  460. package/src/resources/extensions/gsd/tests/single-writer-invariant.test.ts +43 -6
  461. package/src/resources/extensions/gsd/tests/state-transition-matrix.test.ts +36 -0
  462. package/src/resources/extensions/gsd/tests/status-guards.test.ts +38 -0
  463. package/src/resources/extensions/gsd/tests/stop-notice.test.ts +70 -0
  464. package/src/resources/extensions/gsd/tests/token-tool-gating.test.ts +76 -0
  465. package/src/resources/extensions/gsd/tests/tool-invocation-error-loop-break.test.ts +8 -0
  466. package/src/resources/extensions/gsd/tests/tool-surface-readiness.test.ts +155 -0
  467. package/src/resources/extensions/gsd/tests/uat-policy.test.ts +24 -29
  468. package/src/resources/extensions/gsd/tests/unit-closeout.test.ts +209 -0
  469. package/src/resources/extensions/gsd/tests/unit-context-composer.test.ts +67 -2
  470. package/src/resources/extensions/gsd/tests/unit-registry.test.ts +163 -0
  471. package/src/resources/extensions/gsd/tests/web-app-uat.test.ts +44 -1
  472. package/src/resources/extensions/gsd/tests/workflow-mcp.test.ts +2 -2
  473. package/src/resources/extensions/gsd/tests/workflow-tool-executors.test.ts +2 -2
  474. package/src/resources/extensions/gsd/tests/worktree-lifecycle.test.ts +41 -4
  475. package/src/resources/extensions/gsd/tests/worktree-manager.test.ts +22 -1
  476. package/src/resources/extensions/gsd/tests/worktree-placement.test.ts +113 -0
  477. package/src/resources/extensions/gsd/tests/worktree-reentry.test.ts +1 -1
  478. package/src/resources/extensions/gsd/tests/worktree-safety.test.ts +3 -1
  479. package/src/resources/extensions/gsd/tests/worktree-symlink-removal.test.ts +12 -6
  480. package/src/resources/extensions/gsd/tests/worktree-teardown-safety.test.ts +2 -2
  481. package/src/resources/extensions/gsd/tests/write-gate.test.ts +42 -0
  482. package/src/resources/extensions/gsd/tool-surface-readiness.ts +76 -0
  483. package/src/resources/extensions/gsd/tools/complete-slice.ts +23 -58
  484. package/src/resources/extensions/gsd/tools/exec-tool.ts +9 -8
  485. package/src/resources/extensions/gsd/tools/plan-slice.ts +12 -6
  486. package/src/resources/extensions/gsd/tools/reopen-milestone.ts +11 -38
  487. package/src/resources/extensions/gsd/tools/reopen-slice.ts +14 -42
  488. package/src/resources/extensions/gsd/tools/skip-slice.ts +18 -44
  489. package/src/resources/extensions/gsd/uat-policy.ts +2 -1
  490. package/src/resources/extensions/gsd/undo.ts +9 -8
  491. package/src/resources/extensions/gsd/unit-closeout.ts +201 -0
  492. package/src/resources/extensions/gsd/unit-context-composer.ts +111 -1
  493. package/src/resources/extensions/gsd/unit-context-manifest.ts +4 -28
  494. package/src/resources/extensions/gsd/unit-registry.ts +412 -0
  495. package/src/resources/extensions/gsd/unit-tool-contracts.ts +27 -192
  496. package/src/resources/extensions/gsd/web-app-uat.ts +51 -8
  497. package/src/resources/extensions/gsd/workflow-tool-surface.ts +4 -1
  498. package/src/resources/extensions/gsd/worktree-git-recovery.ts +314 -0
  499. package/src/resources/extensions/gsd/worktree-lifecycle.ts +10 -1
  500. package/src/resources/extensions/gsd/worktree-manager.ts +47 -28
  501. package/src/resources/extensions/gsd/worktree-placement.ts +63 -0
  502. package/src/resources/extensions/gsd/worktree-reentry.ts +10 -7
  503. package/src/resources/extensions/gsd/worktree-root.ts +29 -6
  504. package/src/resources/extensions/gsd/worktree-safety.ts +8 -5
  505. package/src/resources/extensions/gsd/worktree-session-state.ts +11 -11
  506. package/src/resources/extensions/search-the-web/native-search.ts +5 -3
  507. package/src/resources/extensions/shared/browser-contract.ts +66 -0
  508. package/src/resources/extensions/shared/gsd-browser-cli.ts +119 -5
  509. package/src/resources/shared/package.json +3 -0
  510. package/src/resources/skills/create-skill/references/executable-code.md +1 -1
  511. package/src/resources/skills/create-skill/workflows/add-reference.md +8 -3
  512. package/src/resources/skills/create-skill/workflows/add-script.md +4 -2
  513. package/src/resources/skills/create-skill/workflows/add-template.md +3 -1
  514. package/src/resources/skills/create-skill/workflows/add-workflow.md +8 -3
  515. package/src/resources/skills/create-skill/workflows/upgrade-to-router.md +10 -5
  516. package/src/resources/skills/create-skill/workflows/verify-skill.md +9 -4
  517. package/src/resources/skills/gsd-browser/SKILL.md +1 -1
  518. package/src/resources/skills/spike-wrap-up/SKILL.md +9 -9
  519. /package/dist/web/standalone/.next/static/{3PtrU9qGPEXwNLWkIyiqk → mU4QIDlpVHDdjDpeEKh5W}/_buildManifest.js +0 -0
  520. /package/dist/web/standalone/.next/static/{3PtrU9qGPEXwNLWkIyiqk → mU4QIDlpVHDdjDpeEKh5W}/_ssgManifest.js +0 -0
@@ -3,6 +3,7 @@ import { Client } from "@modelcontextprotocol/sdk/client/index.js";
3
3
  import { StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio.js";
4
4
  import { Type, type TSchema } from "@sinclair/typebox";
5
5
 
6
+ import { BROWSER_CONTRACT_TOOL_NAMES, type BrowserContractToolName } from "../../shared/browser-contract.js";
6
7
  import { resolveGsdBrowserMcpLaunchConfig, type GsdBrowserMcpLaunchConfig } from "../../shared/gsd-browser-cli.js";
7
8
  import { buildMcpChildEnv } from "../../mcp-client/manager.js";
8
9
 
@@ -13,6 +14,8 @@ interface ManagedBrowserToolDetails {
13
14
  server: string;
14
15
  tool: string;
15
16
  mcpTool: string;
17
+ /** All MCP tools invoked, in order, when a translation made multiple calls. */
18
+ mcpTools?: string[];
16
19
  sessionName?: string;
17
20
  projectRoot?: string;
18
21
  truncated?: boolean;
@@ -37,9 +40,28 @@ interface McpContentItem {
37
40
  [key: string]: unknown;
38
41
  }
39
42
 
43
+ interface ManagedTranslatedCall {
44
+ mcpTool: string;
45
+ args: Record<string, unknown>;
46
+ /** Best-effort call: a failure adds no evidence but does not fail the tool. */
47
+ optional?: boolean;
48
+ }
49
+
50
+ interface ManagedToolTranslation {
51
+ /** Every MCP tool build() can emit; all must be served for contract coverage. */
52
+ requires: readonly string[];
53
+ /** Expand the Pi contract args into one or more sequential gsd-browser MCP calls. */
54
+ build(args: Record<string, unknown>): ManagedTranslatedCall[];
55
+ }
56
+
40
57
  interface ManagedBrowserToolSpec {
41
- name: string;
58
+ /** gsd-browser MCP tool candidates, tried in order. Defaults to the contract name itself. */
42
59
  mcpTools?: string[];
60
+ /**
61
+ * Param-shape translation for contract tools gsd-browser does not serve
62
+ * under any name. Takes precedence over mcpTools/name-based dispatch.
63
+ */
64
+ translate?: ManagedToolTranslation;
43
65
  label: string;
44
66
  description: string;
45
67
  parameters: TSchema;
@@ -51,6 +73,7 @@ const connections = new Map<string, ManagedConnection>();
51
73
  const pendingConnections = new Map<string, Promise<ManagedConnection>>();
52
74
  const DEFAULT_MAX_LINES = 2_000;
53
75
  const DEFAULT_MAX_BYTES = 50 * 1024;
76
+ const MCP_CALL_TIMEOUT_MS = 60_000;
54
77
 
55
78
  const AssertionCheck = Type.Object({
56
79
  kind: Type.String({ description: "Assertion kind, e.g. url_contains, text_visible, selector_visible, no_console_errors, no_failed_requests." }),
@@ -77,30 +100,16 @@ const BatchStep = Type.Object({
77
100
  checks: Type.Optional(Type.Array(AssertionCheck)),
78
101
  }, { additionalProperties: true });
79
102
 
80
- export const MANAGED_GSD_BROWSER_TOOL_NAMES = [
81
- "browser_navigate",
82
- "browser_click",
83
- "browser_type",
84
- "browser_fill_form",
85
- "browser_click_ref",
86
- "browser_fill_ref",
87
- "browser_wait_for",
88
- "browser_assert",
89
- "browser_verify",
90
- "browser_screenshot",
91
- "browser_snapshot_refs",
92
- "browser_find",
93
- "browser_get_console_logs",
94
- "browser_get_network_logs",
95
- "browser_evaluate",
96
- "browser_reload",
97
- "browser_batch",
98
- "browser_act",
99
- ] as const;
100
-
101
- const MANAGED_BROWSER_TOOLS: ManagedBrowserToolSpec[] = [
102
- {
103
- name: "browser_navigate",
103
+ /**
104
+ * The managed adapter serves exactly the Browser Automation Contract
105
+ * vocabulary. The spec table below is keyed by contract name, so adding a
106
+ * contract capability fails typecheck here until the adapter declares how the
107
+ * gsd-browser server satisfies it.
108
+ */
109
+ export const MANAGED_GSD_BROWSER_TOOL_NAMES = BROWSER_CONTRACT_TOOL_NAMES;
110
+
111
+ export const MANAGED_BROWSER_TOOL_SPECS: Record<BrowserContractToolName, ManagedBrowserToolSpec> = {
112
+ browser_navigate: {
104
113
  label: "Browser Navigate",
105
114
  description: "Navigate the managed gsd-browser session to a URL and return page state. Use for local web app verification and UAT evidence.",
106
115
  parameters: Type.Object({
@@ -108,8 +117,14 @@ const MANAGED_BROWSER_TOOLS: ManagedBrowserToolSpec[] = [
108
117
  screenshot: Type.Optional(Type.Boolean({ description: "Capture screenshot evidence when supported." })),
109
118
  }, { additionalProperties: true }),
110
119
  },
111
- {
112
- name: "browser_click",
120
+ browser_click: {
121
+ translate: {
122
+ requires: ["browser_batch"],
123
+ build: (args) => [{
124
+ mcpTool: "browser_batch",
125
+ args: { steps: [{ action: "click", ...args }] },
126
+ }],
127
+ },
113
128
  label: "Browser Click",
114
129
  description: "Click an element in the managed gsd-browser session by selector or coordinates.",
115
130
  parameters: Type.Object({
@@ -118,8 +133,14 @@ const MANAGED_BROWSER_TOOLS: ManagedBrowserToolSpec[] = [
118
133
  y: Type.Optional(Type.Number({ description: "Y coordinate to click." })),
119
134
  }, { additionalProperties: true }),
120
135
  },
121
- {
122
- name: "browser_type",
136
+ browser_type: {
137
+ translate: {
138
+ requires: ["browser_batch"],
139
+ build: (args) => [{
140
+ mcpTool: "browser_batch",
141
+ args: { steps: [{ action: "type", ...args }] },
142
+ }],
143
+ },
123
144
  label: "Browser Type",
124
145
  description: "Type or fill text into an input in the managed gsd-browser session.",
125
146
  parameters: Type.Object({
@@ -130,8 +151,7 @@ const MANAGED_BROWSER_TOOLS: ManagedBrowserToolSpec[] = [
130
151
  slowly: Type.Optional(Type.Boolean({ description: "Type character by character." })),
131
152
  }, { additionalProperties: true }),
132
153
  },
133
- {
134
- name: "browser_fill_form",
154
+ browser_fill_form: {
135
155
  label: "Browser Fill Form",
136
156
  description: "Fill a form in the managed gsd-browser session using field labels, names, placeholders, or aria labels.",
137
157
  parameters: Type.Object({
@@ -140,16 +160,14 @@ const MANAGED_BROWSER_TOOLS: ManagedBrowserToolSpec[] = [
140
160
  submit: Type.Optional(Type.Boolean({ description: "Submit the form after filling." })),
141
161
  }, { additionalProperties: true }),
142
162
  },
143
- {
144
- name: "browser_click_ref",
163
+ browser_click_ref: {
145
164
  label: "Browser Click Ref",
146
165
  description: "Click a versioned ref from the latest gsd-browser snapshot.",
147
166
  parameters: Type.Object({
148
167
  ref: Type.String({ description: "Versioned ref, e.g. @v3:e2." }),
149
168
  }, { additionalProperties: true }),
150
169
  },
151
- {
152
- name: "browser_fill_ref",
170
+ browser_fill_ref: {
153
171
  label: "Browser Fill Ref",
154
172
  description: "Fill text into an input-like versioned ref from the latest gsd-browser snapshot.",
155
173
  parameters: Type.Object({
@@ -160,8 +178,7 @@ const MANAGED_BROWSER_TOOLS: ManagedBrowserToolSpec[] = [
160
178
  slowly: Type.Optional(Type.Boolean({ description: "Type character by character." })),
161
179
  }, { additionalProperties: true }),
162
180
  },
163
- {
164
- name: "browser_wait_for",
181
+ browser_wait_for: {
165
182
  label: "Browser Wait For",
166
183
  description: "Wait for a browser condition such as network idle, selector visibility, text visibility, or URL change.",
167
184
  parameters: Type.Object({
@@ -171,8 +188,7 @@ const MANAGED_BROWSER_TOOLS: ManagedBrowserToolSpec[] = [
171
188
  timeout: Type.Optional(Type.Number({ description: "Maximum milliseconds to wait." })),
172
189
  }, { additionalProperties: true }),
173
190
  },
174
- {
175
- name: "browser_assert",
191
+ browser_assert: {
176
192
  label: "Browser Assert",
177
193
  description: "Run explicit browser assertions and return structured PASS/FAIL evidence.",
178
194
  promptGuidelines: [
@@ -183,8 +199,39 @@ const MANAGED_BROWSER_TOOLS: ManagedBrowserToolSpec[] = [
183
199
  checks: Type.Array(AssertionCheck),
184
200
  }, { additionalProperties: true }),
185
201
  },
186
- {
187
- name: "browser_verify",
202
+ browser_verify: {
203
+ translate: {
204
+ requires: ["browser_navigate", "browser_assert", "browser_screenshot"],
205
+ build: (args) => {
206
+ const calls: ManagedTranslatedCall[] = [
207
+ {
208
+ mcpTool: "browser_navigate",
209
+ args: { url: args.url, ...(args.timeout === undefined ? {} : { timeout: args.timeout }) },
210
+ },
211
+ ];
212
+ const verifyChecks = Array.isArray(args.checks) ? args.checks as Array<Record<string, unknown>> : [];
213
+ const assertChecks: Array<Record<string, unknown>> = [];
214
+ for (const check of verifyChecks) {
215
+ if (typeof check.expectedText === "string") {
216
+ assertChecks.push({ kind: "text_visible", text: check.expectedText });
217
+ }
218
+ if (typeof check.selector === "string") {
219
+ if (check.expectedVisible === false) {
220
+ assertChecks.push({ kind: "selector_hidden", selector: check.selector });
221
+ } else if (check.expectedVisible === true || check.expectedText === undefined) {
222
+ assertChecks.push({ kind: "selector_visible", selector: check.selector });
223
+ }
224
+ }
225
+ }
226
+ if (assertChecks.length > 0) {
227
+ calls.push({ mcpTool: "browser_assert", args: { checks: assertChecks } });
228
+ }
229
+ if (verifyChecks.some((check) => check.screenshot === true)) {
230
+ calls.push({ mcpTool: "browser_screenshot", args: {}, optional: true });
231
+ }
232
+ return calls;
233
+ },
234
+ },
188
235
  label: "Browser Verify",
189
236
  description: "Run a structured browser verification flow and return evidence from the managed gsd-browser session.",
190
237
  parameters: Type.Object({
@@ -199,8 +246,7 @@ const MANAGED_BROWSER_TOOLS: ManagedBrowserToolSpec[] = [
199
246
  timeout: Type.Optional(Type.Number({ description: "Navigation timeout in milliseconds." })),
200
247
  }, { additionalProperties: true }),
201
248
  },
202
- {
203
- name: "browser_screenshot",
249
+ browser_screenshot: {
204
250
  label: "Browser Screenshot",
205
251
  description: "Capture browser screenshot evidence from the managed gsd-browser session.",
206
252
  compatibility: { producesImages: true },
@@ -210,8 +256,7 @@ const MANAGED_BROWSER_TOOLS: ManagedBrowserToolSpec[] = [
210
256
  quality: Type.Optional(Type.Number({ description: "JPEG quality when supported." })),
211
257
  }, { additionalProperties: true }),
212
258
  },
213
- {
214
- name: "browser_snapshot_refs",
259
+ browser_snapshot_refs: {
215
260
  mcpTools: ["browser_snapshot", "browser_snapshot_refs"],
216
261
  label: "Browser Snapshot Refs",
217
262
  description: "Capture a compact gsd-browser snapshot with versioned refs for reliable interaction.",
@@ -222,8 +267,7 @@ const MANAGED_BROWSER_TOOLS: ManagedBrowserToolSpec[] = [
222
267
  mode: Type.Optional(Type.String({ description: "Snapshot mode: interactive, form, dialog, navigation, errors, headings, visible_only." })),
223
268
  }, { additionalProperties: true }),
224
269
  },
225
- {
226
- name: "browser_find",
270
+ browser_find: {
227
271
  mcpTools: ["browser_find_element", "browser_find"],
228
272
  label: "Browser Find",
229
273
  description: "Find elements by text, role, or selector in the managed gsd-browser session.",
@@ -234,8 +278,7 @@ const MANAGED_BROWSER_TOOLS: ManagedBrowserToolSpec[] = [
234
278
  limit: Type.Optional(Type.Number({ description: "Maximum results to return." })),
235
279
  }, { additionalProperties: true }),
236
280
  },
237
- {
238
- name: "browser_get_console_logs",
281
+ browser_get_console_logs: {
239
282
  mcpTools: ["browser_console", "browser_get_console_logs"],
240
283
  label: "Browser Console Logs",
241
284
  description: "Return buffered console logs and JavaScript errors from the managed gsd-browser session.",
@@ -243,8 +286,7 @@ const MANAGED_BROWSER_TOOLS: ManagedBrowserToolSpec[] = [
243
286
  clear: Type.Optional(Type.Boolean({ description: "Clear the buffer after reading logs." })),
244
287
  }, { additionalProperties: true }),
245
288
  },
246
- {
247
- name: "browser_get_network_logs",
289
+ browser_get_network_logs: {
248
290
  mcpTools: ["browser_network", "browser_get_network_logs"],
249
291
  label: "Browser Network Logs",
250
292
  description: "Return buffered network requests and responses from the managed gsd-browser session.",
@@ -253,8 +295,7 @@ const MANAGED_BROWSER_TOOLS: ManagedBrowserToolSpec[] = [
253
295
  filter: Type.Optional(Type.String({ description: "Filter, e.g. all, errors, fetch-xhr." })),
254
296
  }, { additionalProperties: true }),
255
297
  },
256
- {
257
- name: "browser_evaluate",
298
+ browser_evaluate: {
258
299
  mcpTools: ["browser_eval", "browser_evaluate"],
259
300
  label: "Browser Evaluate",
260
301
  description: "Evaluate a JavaScript expression in the managed gsd-browser page context.",
@@ -262,14 +303,22 @@ const MANAGED_BROWSER_TOOLS: ManagedBrowserToolSpec[] = [
262
303
  expression: Type.String({ description: "JavaScript expression to evaluate." }),
263
304
  }, { additionalProperties: true }),
264
305
  },
265
- {
266
- name: "browser_reload",
306
+ browser_reload: {
307
+ // gsd-browser's daemon has a reload command but does not expose it over
308
+ // MCP, so reload rides browser_evaluate. The network-idle settle is
309
+ // best-effort: pages with persistent connections never go idle.
310
+ translate: {
311
+ requires: ["browser_evaluate", "browser_wait_for"],
312
+ build: () => [
313
+ { mcpTool: "browser_evaluate", args: { expression: "location.reload()" } },
314
+ { mcpTool: "browser_wait_for", args: { condition: "network_idle", timeout: 3_000 }, optional: true },
315
+ ],
316
+ },
267
317
  label: "Browser Reload",
268
318
  description: "Reload the current page in the managed gsd-browser session.",
269
319
  parameters: Type.Object({}, { additionalProperties: true }),
270
320
  },
271
- {
272
- name: "browser_batch",
321
+ browser_batch: {
273
322
  label: "Browser Batch",
274
323
  description: "Execute multiple explicit browser steps through the managed gsd-browser session in one call.",
275
324
  promptGuidelines: [
@@ -282,8 +331,7 @@ const MANAGED_BROWSER_TOOLS: ManagedBrowserToolSpec[] = [
282
331
  finalSummaryOnly: Type.Optional(Type.Boolean({ description: "Return only the compact final summary." })),
283
332
  }, { additionalProperties: true }),
284
333
  },
285
- {
286
- name: "browser_act",
334
+ browser_act: {
287
335
  label: "Browser Act",
288
336
  description: "Execute a semantic browser action through gsd-browser, such as primary_cta, submit_form, or close_dialog.",
289
337
  parameters: Type.Object({
@@ -291,7 +339,7 @@ const MANAGED_BROWSER_TOOLS: ManagedBrowserToolSpec[] = [
291
339
  scope: Type.Optional(Type.String({ description: "CSS selector to narrow the search area." })),
292
340
  }, { additionalProperties: true }),
293
341
  },
294
- ];
342
+ };
295
343
 
296
344
  function resolveProjectRoot(ctx?: ExtensionContext): string {
297
345
  return ctx?.cwd || process.cwd();
@@ -381,11 +429,27 @@ function isUnknownMcpToolError(error: unknown): boolean {
381
429
  return /unknown tool|tool .*not found|tool not found|not registered|does not exist/i.test(message);
382
430
  }
383
431
 
384
- function normalizeManagedArgs(piToolName: string, args: Record<string, unknown>): Record<string, unknown> {
432
+ function normalizeBatchStep(step: unknown): unknown {
433
+ if (!step || typeof step !== "object") return step;
434
+ const { clearFirst, ...rest } = step as Record<string, unknown>;
435
+ return clearFirst === undefined ? step : { ...rest, clear_first: clearFirst };
436
+ }
437
+
438
+ export function normalizeManagedArgs(piToolName: string, args: Record<string, unknown>): Record<string, unknown> {
385
439
  if (piToolName === "browser_snapshot_refs") {
386
440
  const { interactiveOnly: _interactiveOnly, ...snapshotArgs } = args;
387
441
  return snapshotArgs;
388
442
  }
443
+ if (piToolName === "browser_batch") {
444
+ // gsd-browser's MCP batch tool reads snake_case option and step keys.
445
+ const { stopOnFailure, finalSummaryOnly, steps, ...rest } = args;
446
+ return {
447
+ ...rest,
448
+ ...(Array.isArray(steps) ? { steps: steps.map(normalizeBatchStep) } : {}),
449
+ ...(stopOnFailure === undefined ? {} : { stop_on_failure: stopOnFailure }),
450
+ ...(finalSummaryOnly === undefined ? {} : { summary_only: finalSummaryOnly }),
451
+ };
452
+ }
389
453
  return args;
390
454
  }
391
455
 
@@ -463,43 +527,104 @@ function truncateHeadText(
463
527
  };
464
528
  }
465
529
 
530
+ type McpToolCallResult = {
531
+ content?: unknown;
532
+ structuredContent?: unknown;
533
+ isError?: boolean;
534
+ };
535
+
536
+ function callGsdBrowserMcp(
537
+ connection: ManagedConnection,
538
+ mcpTool: string,
539
+ args: Record<string, unknown>,
540
+ signal?: AbortSignal,
541
+ ): Promise<McpToolCallResult> {
542
+ return connection.client.callTool(
543
+ { name: mcpTool, arguments: args },
544
+ undefined,
545
+ { signal, timeout: MCP_CALL_TIMEOUT_MS },
546
+ ) as Promise<McpToolCallResult>;
547
+ }
548
+
549
+ function buildManagedToolResult(
550
+ connection: ManagedConnection,
551
+ piToolName: string,
552
+ mcpToolsUsed: string[],
553
+ contentItems: McpContentItem[],
554
+ lastResult: McpToolCallResult,
555
+ ): ManagedBrowserToolResult {
556
+ const serialized = serializeMcpContent(contentItems);
557
+ return {
558
+ content: serialized.content,
559
+ details: {
560
+ engine: "gsd-browser",
561
+ server: connection.launch.serverName,
562
+ tool: piToolName,
563
+ mcpTool: mcpToolsUsed[mcpToolsUsed.length - 1] ?? piToolName,
564
+ ...(mcpToolsUsed.length > 1 ? { mcpTools: mcpToolsUsed } : {}),
565
+ sessionName: connection.launch.sessionName,
566
+ projectRoot: connection.launch.projectRoot,
567
+ truncated: serialized.truncated,
568
+ outputLines: serialized.outputLines,
569
+ outputBytes: serialized.outputBytes,
570
+ structuredContent: lastResult.structuredContent,
571
+ mcpIsError: Boolean(lastResult.isError),
572
+ },
573
+ isError: Boolean(lastResult.isError),
574
+ };
575
+ }
576
+
577
+ async function callTranslatedGsdBrowserTool(
578
+ connection: ManagedConnection,
579
+ piToolName: string,
580
+ translation: ManagedToolTranslation,
581
+ args: Record<string, unknown>,
582
+ options: { signal?: AbortSignal },
583
+ ): Promise<ManagedBrowserToolResult> {
584
+ const calls = translation.build(args);
585
+ const contentItems: McpContentItem[] = [];
586
+ const toolsUsed: string[] = [];
587
+ let lastResult: McpToolCallResult = {};
588
+
589
+ for (const call of calls) {
590
+ let result: McpToolCallResult;
591
+ try {
592
+ result = await callGsdBrowserMcp(connection, call.mcpTool, normalizeManagedArgs(call.mcpTool, call.args), options.signal);
593
+ } catch (error) {
594
+ if (call.optional) continue;
595
+ throw error;
596
+ }
597
+ if (call.optional && result.isError) continue;
598
+ toolsUsed.push(call.mcpTool);
599
+ if (Array.isArray(result.content)) contentItems.push(...result.content as McpContentItem[]);
600
+ lastResult = result;
601
+ // Later calls assume the earlier ones took effect (e.g. assert after a
602
+ // failed navigation would report misleading evidence), so stop here.
603
+ if (lastResult.isError) break;
604
+ }
605
+
606
+ return buildManagedToolResult(connection, piToolName, toolsUsed, contentItems, lastResult);
607
+ }
608
+
466
609
  async function callManagedGsdBrowserTool(
467
610
  piToolName: string,
468
- mcpTools: string[],
611
+ spec: ManagedBrowserToolSpec,
469
612
  args: Record<string, unknown>,
470
613
  options: { signal?: AbortSignal; ctx?: ExtensionContext },
471
614
  ): Promise<ManagedBrowserToolResult> {
472
615
  const connection = await getOrConnectManagedGsdBrowser(options.ctx, options.signal);
473
616
  const normalizedArgs = normalizeManagedArgs(piToolName, args);
474
- let lastError: unknown;
475
617
 
476
- for (const mcpTool of mcpTools) {
618
+ if (spec.translate) {
619
+ return callTranslatedGsdBrowserTool(connection, piToolName, spec.translate, normalizedArgs, options);
620
+ }
621
+
622
+ let lastError: unknown;
623
+ for (const mcpTool of spec.mcpTools ?? [piToolName]) {
477
624
  try {
478
- const result = await connection.client.callTool(
479
- { name: mcpTool, arguments: normalizedArgs },
480
- undefined,
481
- { signal: options.signal, timeout: 60000 },
482
- );
625
+ const result = await callGsdBrowserMcp(connection, mcpTool, normalizedArgs, options.signal);
483
626
  const contentItems = Array.isArray(result.content) ? result.content as McpContentItem[] : [];
484
- const serialized = serializeMcpContent(contentItems);
485
-
486
- return {
487
- content: serialized.content,
488
- details: {
489
- engine: "gsd-browser",
490
- server: connection.launch.serverName,
491
- tool: piToolName,
492
- mcpTool,
493
- sessionName: connection.launch.sessionName,
494
- projectRoot: connection.launch.projectRoot,
495
- truncated: serialized.truncated,
496
- outputLines: serialized.outputLines,
497
- outputBytes: serialized.outputBytes,
498
- structuredContent: (result as { structuredContent?: unknown }).structuredContent,
499
- mcpIsError: Boolean((result as { isError?: boolean }).isError),
500
- },
501
- isError: Boolean((result as { isError?: boolean }).isError),
502
- };
627
+ return buildManagedToolResult(connection, piToolName, [mcpTool], contentItems, result);
503
628
  } catch (error) {
504
629
  lastError = error;
505
630
  if (!isUnknownMcpToolError(error)) break;
@@ -520,6 +645,46 @@ function formatManagedBrowserError(toolName: string, error: unknown): string {
520
645
  ].join("\n");
521
646
  }
522
647
 
648
+ /**
649
+ * Contract tools the server's advertised tool list cannot satisfy through any
650
+ * of their declared MCP candidates or translations.
651
+ */
652
+ export function findMissingContractCoverage(servedToolNames: Iterable<string>): BrowserContractToolName[] {
653
+ const served = new Set(servedToolNames);
654
+ return BROWSER_CONTRACT_TOOL_NAMES.filter((name) => {
655
+ const spec = MANAGED_BROWSER_TOOL_SPECS[name];
656
+ if (spec.translate) {
657
+ return !spec.translate.requires.every((required) => served.has(required));
658
+ }
659
+ const candidates = spec.mcpTools ?? [name];
660
+ return !candidates.some((candidate) => served.has(candidate));
661
+ });
662
+ }
663
+
664
+ /**
665
+ * Compare the server's advertised tool list against the Browser Automation
666
+ * Contract so a server that stops serving a contract tool surfaces at warm-up
667
+ * instead of as a first-use error. Best-effort: a failed or empty listing
668
+ * returns no warning (call-time alias fallback still applies).
669
+ */
670
+ async function verifyContractCoverage(
671
+ connection: ManagedConnection,
672
+ signal?: AbortSignal,
673
+ ): Promise<string | undefined> {
674
+ let served: string[];
675
+ try {
676
+ const result = await connection.client.listTools(undefined, { signal, timeout: 10000 });
677
+ served = (result.tools ?? []).map((tool) => tool.name);
678
+ } catch {
679
+ return undefined;
680
+ }
681
+ if (served.length === 0) return undefined;
682
+
683
+ const missing = findMissingContractCoverage(served);
684
+ if (missing.length === 0) return undefined;
685
+ return `gsd-browser does not serve ${missing.length} Browser Automation Contract tool(s): ${missing.join(", ")}. These will error on first use; update gsd-browser or check GSD_BROWSER_* overrides.`;
686
+ }
687
+
523
688
  /**
524
689
  * Eagerly establish the managed gsd-browser connection so browser tools are
525
690
  * ready before first use. Best-effort: returns the error instead of throwing so
@@ -530,19 +695,21 @@ function formatManagedBrowserError(toolName: string, error: unknown): string {
530
695
  export async function warmUpManagedGsdBrowser(
531
696
  ctx?: ExtensionContext,
532
697
  signal?: AbortSignal,
533
- ): Promise<{ ok: true } | { ok: false; error: string }> {
698
+ ): Promise<{ ok: true; coverageWarning?: string } | { ok: false; error: string }> {
534
699
  try {
535
- await getOrConnectManagedGsdBrowser(ctx, signal);
536
- return { ok: true };
700
+ const connection = await getOrConnectManagedGsdBrowser(ctx, signal);
701
+ const coverageWarning = await verifyContractCoverage(connection, signal);
702
+ return coverageWarning ? { ok: true, coverageWarning } : { ok: true };
537
703
  } catch (error) {
538
704
  return { ok: false, error: error instanceof Error ? error.message : String(error) };
539
705
  }
540
706
  }
541
707
 
542
708
  export function registerManagedGsdBrowserTools(pi: ExtensionAPI): void {
543
- for (const tool of MANAGED_BROWSER_TOOLS) {
709
+ for (const name of BROWSER_CONTRACT_TOOL_NAMES) {
710
+ const tool = MANAGED_BROWSER_TOOL_SPECS[name];
544
711
  pi.registerTool({
545
- name: tool.name,
712
+ name,
546
713
  label: tool.label,
547
714
  description: tool.description,
548
715
  ...(tool.promptGuidelines ? { promptGuidelines: tool.promptGuidelines } : {}),
@@ -551,20 +718,20 @@ export function registerManagedGsdBrowserTools(pi: ExtensionAPI): void {
551
718
  async execute(_toolCallId, params, signal, _onUpdate, ctx) {
552
719
  try {
553
720
  return await callManagedGsdBrowserTool(
554
- tool.name,
555
- tool.mcpTools ?? [tool.name],
721
+ name,
722
+ tool,
556
723
  params as Record<string, unknown>,
557
724
  { signal, ctx },
558
725
  );
559
726
  } catch (error) {
560
- const message = formatManagedBrowserError(tool.name, error);
727
+ const message = formatManagedBrowserError(name, error);
561
728
  return {
562
729
  content: [{ type: "text", text: message }],
563
730
  details: {
564
731
  engine: "gsd-browser",
565
732
  server: "gsd-browser",
566
- tool: tool.name,
567
- mcpTool: tool.mcpTools?.[0] ?? tool.name,
733
+ tool: name,
734
+ mcpTool: tool.translate?.requires[0] ?? tool.mcpTools?.[0] ?? name,
568
735
  error: error instanceof Error ? error.message : String(error),
569
736
  },
570
737
  isError: true,
@@ -1,11 +1,38 @@
1
+ /**
2
+ * Browser Automation Engine resolution (ADR-037).
3
+ *
4
+ * The engine choice behind the canonical `browser_*` tools is a runtime
5
+ * decision with a recorded reason, not a static default:
6
+ * - An explicit `GSD_BROWSER_ENGINE` override is honored verbatim.
7
+ * - Otherwise, browser-facing projects prefer the managed gsd-browser engine
8
+ * when the availability probe can prove a CLI exists, and fall back to
9
+ * legacy Playwright with the failure reason recorded.
10
+ * - Non-browser-facing projects keep legacy Playwright (browser tools are
11
+ * incidental there; the managed daemon is not worth its startup risk).
12
+ *
13
+ * This module owns the committed resolution, not just the prediction: when
14
+ * registration verifies a probe-resolved managed engine (daemon connect) and
15
+ * falls back, the outcome is committed here so every ambient reader — UAT
16
+ * guidance, re-warm-up, later sessions in the same process — sees the engine
17
+ * the session actually registered.
18
+ */
19
+ import path from "node:path";
20
+
21
+ import { resolveGsdBrowserCliAvailability } from "../../shared/gsd-browser-cli.js";
22
+ import { detectWebApp } from "../web-app-detect.js";
23
+
1
24
  export type BrowserEngineMode = "gsd-browser" | "legacy" | "off";
2
25
 
3
- const DEFAULT_BROWSER_ENGINE: BrowserEngineMode = "legacy";
26
+ export interface BrowserEngineResolution {
27
+ engine: BrowserEngineMode;
28
+ /** "env" = explicit GSD_BROWSER_ENGINE override; "probe" = default path decided by availability. */
29
+ source: "env" | "probe";
30
+ reason: string;
31
+ }
4
32
 
5
- export function resolveBrowserEngineMode(env: NodeJS.ProcessEnv = process.env): BrowserEngineMode {
6
- const raw = env.GSD_BROWSER_ENGINE?.trim();
7
- if (!raw) return DEFAULT_BROWSER_ENGINE;
33
+ const committedResolutionByProjectRoot = new Map<string, BrowserEngineResolution>();
8
34
 
35
+ function parseExplicitEngineMode(raw: string): BrowserEngineMode {
9
36
  const normalized = raw.toLowerCase();
10
37
  if (normalized === "gsd-browser" || normalized === "gsd_browser" || normalized === "gsdbrowser") {
11
38
  return "gsd-browser";
@@ -17,3 +44,62 @@ export function resolveBrowserEngineMode(env: NodeJS.ProcessEnv = process.env):
17
44
 
18
45
  throw new Error(`Invalid GSD_BROWSER_ENGINE="${raw}". Expected "gsd-browser", "legacy", or "off".`);
19
46
  }
47
+
48
+ /** Pure resolution from explicit inputs. Never cached; probes on every call. */
49
+ export function resolveBrowserEngineResolution(
50
+ env: NodeJS.ProcessEnv,
51
+ projectRoot?: string,
52
+ ): BrowserEngineResolution {
53
+ const raw = env.GSD_BROWSER_ENGINE?.trim();
54
+ if (raw) {
55
+ return { engine: parseExplicitEngineMode(raw), source: "env", reason: `GSD_BROWSER_ENGINE=${raw}` };
56
+ }
57
+
58
+ if (!projectRoot) {
59
+ return { engine: "legacy", source: "probe", reason: "no project root to probe; using legacy Playwright" };
60
+ }
61
+
62
+ if (!detectWebApp(projectRoot)) {
63
+ return {
64
+ engine: "legacy",
65
+ source: "probe",
66
+ reason: "project is not browser-facing; using legacy Playwright",
67
+ };
68
+ }
69
+
70
+ const availability = resolveGsdBrowserCliAvailability(env);
71
+ return availability.available
72
+ ? {
73
+ engine: "gsd-browser",
74
+ source: "probe",
75
+ reason: `web app detected and managed gsd-browser engine available (${availability.detail})`,
76
+ }
77
+ : {
78
+ engine: "legacy",
79
+ source: "probe",
80
+ reason: `web app detected but gsd-browser unavailable (${availability.detail}); falling back to legacy Playwright`,
81
+ };
82
+ }
83
+
84
+ /**
85
+ * Session-facing resolution: the committed record for this project root, or
86
+ * the ambient probe result, cached as the initial commitment (the probe
87
+ * touches the filesystem and at worst one short subprocess).
88
+ */
89
+ export function resolveAmbientBrowserEngineResolution(projectRoot: string): BrowserEngineResolution {
90
+ const key = path.resolve(projectRoot);
91
+ const committed = committedResolutionByProjectRoot.get(key);
92
+ if (committed) return committed;
93
+
94
+ const resolution = resolveBrowserEngineResolution(process.env, projectRoot);
95
+ committedResolutionByProjectRoot.set(key, resolution);
96
+ return resolution;
97
+ }
98
+
99
+ /**
100
+ * Record a verified outcome for this project root — e.g. the probe predicted
101
+ * gsd-browser but the daemon-connect gate fell back to legacy Playwright.
102
+ */
103
+ export function commitBrowserEngineResolution(projectRoot: string, resolution: BrowserEngineResolution): void {
104
+ committedResolutionByProjectRoot.set(path.resolve(projectRoot), resolution);
105
+ }