@moretea-labs/forge 1.6.0 → 1.7.0

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 (396) hide show
  1. package/AGENTS.md +2 -0
  2. package/CHANGELOG.md +26 -0
  3. package/CLAUDE.md +2 -0
  4. package/README.md +2 -2
  5. package/README.zh-CN.md +1 -1
  6. package/SKILL.md +2 -2
  7. package/THIRD_PARTY_NOTICES.md +1 -1
  8. package/agents/openai.yaml +1 -1
  9. package/assets/hooks/hook-input.sh +11 -8
  10. package/assets/hooks/lib/session-state.sh +10 -7
  11. package/assets/hooks/lib/workflow-state.sh +13 -177
  12. package/assets/hooks/post-tool-observer.sh +8 -2
  13. package/assets/hooks/prompt-guard.sh +5 -81
  14. package/assets/hooks/session-start-context.sh +56 -1
  15. package/assets/partials/05-workflow.partial.md +1 -1
  16. package/assets/partials-agents/03-orchestration.partial.md +1 -1
  17. package/assets/plugin-registry.v1.json +1 -1
  18. package/assets/reference-configs/document-generation.md +1 -1
  19. package/assets/reference-configs/harness-overview.md +1 -1
  20. package/assets/reference-configs/sprint-contracts.md +3 -3
  21. package/assets/skill-version.json +2 -2
  22. package/assets/templates/contract.template.md +2 -7
  23. package/assets/templates/helpers/capture-plan.sh +2 -2
  24. package/assets/templates/helpers/check-task-workflow.sh +4 -4
  25. package/assets/templates/helpers/contract-worktree.sh +1 -21
  26. package/assets/templates/helpers/ensure-task-workflow.sh +11 -36
  27. package/assets/templates/helpers/migrate-project-template.sh +22 -45
  28. package/assets/templates/helpers/new-plan.sh +1 -1
  29. package/assets/templates/helpers/plan-to-todo.sh +12 -37
  30. package/assets/templates/helpers/ship-worktrees.sh +2 -29
  31. package/assets/templates/helpers/verify-contract.sh +1 -111
  32. package/assets/templates/helpers/verify-sprint.sh +3 -180
  33. package/assets/templates/plan.template.md +1 -1
  34. package/assets/templates/review.template.md +9 -34
  35. package/assets/workflow-contract.v1.json +10 -19
  36. package/docs/README.md +10 -10
  37. package/docs/architecture/CURRENT.md +170 -0
  38. package/docs/architecture/EVOLUTION.md +42 -0
  39. package/docs/architecture/current/README.md +4 -156
  40. package/docs/architecture/decisions/20260803-release-identity-binding-and-exit-policy.md +2 -2
  41. package/docs/architecture/decisions/20260823-immediate-controller-relay.md +53 -0
  42. package/docs/architecture/decisions/20260826-browser-runtime-v2.md +73 -0
  43. package/docs/architecture/history/README.md +7 -0
  44. package/docs/architecture/{chatgpt-handoff-facade.md → history/chatgpt-handoff-facade.md} +4 -0
  45. package/docs/architecture/{global-hook-runtime.md → history/global-hook-runtime.md} +7 -3
  46. package/docs/architecture/{ios-semantic-automation-provider-v2.md → history/ios-semantic-automation-provider-v2.md} +6 -2
  47. package/docs/architecture/history.md +3 -34
  48. package/docs/architecture/index.md +15 -98
  49. package/docs/architecture/modules/controller-runtime/transport-lifecycle.md +1 -1
  50. package/docs/architecture/reviews/2026-08-22-semantic-harness-convergence-acceptance.md +39 -0
  51. package/docs/architecture/versions/1.6.md +38 -0
  52. package/docs/architecture/versions/1.7.md +41 -0
  53. package/docs/forge-chatgpt-browser-engine.md +2 -2
  54. package/docs/forge-chatgpt-mcp-setup.md +4 -28
  55. package/docs/forge-chatgpt-supervised-automation.md +3 -3
  56. package/docs/forge-github-issue-launcher.md +1 -1
  57. package/docs/forge-runtime-self-healing-loop.md +1 -1
  58. package/docs/operations/controller-browser-plugin.md +26 -6
  59. package/docs/operations/controller-performance-and-502.md +124 -0
  60. package/docs/operations/controller-reliability-runbook.md +1 -1
  61. package/docs/operations/features.md +2 -2
  62. package/docs/operations/github-repository.md +1 -1
  63. package/docs/operations/homebrew.md +2 -2
  64. package/docs/operations/mcp-tool-exposure.md +5 -3
  65. package/docs/wiki/Architecture.md +6 -6
  66. package/docs/wiki/Implementation.md +2 -2
  67. package/docs/wiki/Integrations.md +2 -2
  68. package/docs/wiki/Work-Lifecycle.md +1 -1
  69. package/package.json +29 -10
  70. package/scripts/activate-source-baseline.ts +17 -13
  71. package/scripts/benchmark-background-check-overlap.ts +228 -0
  72. package/scripts/benchmark-mcp-host.sh +117 -0
  73. package/scripts/benchmark-mcp-transport.ts +170 -0
  74. package/scripts/benchmark-quality-harness.ts +146 -0
  75. package/scripts/benchmark-route-session-concurrency.ts +207 -6
  76. package/scripts/benchmark-thin-harness-mcp-e2e.ts +7 -1
  77. package/scripts/benchmark-typescript-navigation.ts +186 -0
  78. package/scripts/benchmark-work-efficiency.ts +334 -0
  79. package/scripts/capture-plan.sh +3 -3
  80. package/scripts/check-agent-tooling.sh +8 -35
  81. package/scripts/check-architecture-sync.sh +17 -86
  82. package/scripts/check-mcp-compatibility.ts +14 -0
  83. package/scripts/check-runtime-architecture.mjs +107 -64
  84. package/scripts/check-stable-baseline.ts +92 -0
  85. package/scripts/check-task-workflow.sh +4 -4
  86. package/scripts/contract-worktree.sh +1 -21
  87. package/scripts/ensure-task-workflow.sh +22 -55
  88. package/scripts/host-temporary-cloud-mcp-e2e.sh +265 -0
  89. package/scripts/install-standalone-recovery.ts +24 -0
  90. package/scripts/lib/project-init-lib.sh +15 -44
  91. package/scripts/migrate-project-template.sh +23 -1179
  92. package/scripts/new-plan.sh +1 -1
  93. package/scripts/plan-to-todo.sh +11 -36
  94. package/scripts/run-governed-gate.ts +2 -1
  95. package/scripts/ship-worktrees.sh +2 -29
  96. package/scripts/smoke-ios-physical-device.ts +4 -2
  97. package/scripts/smoke-runtime-recovery.ts +1 -35
  98. package/scripts/smoke-schedule-engine.ts +1 -20
  99. package/scripts/verify-contract.sh +1 -111
  100. package/scripts/verify-forge-runtime.sh +0 -1
  101. package/scripts/verify-sprint.sh +3 -180
  102. package/scripts/workflow-contract.ts +1 -5
  103. package/src/cli/commands/init-hook.ts +3 -3
  104. package/src/cli/commands/mcp.ts +9 -5
  105. package/src/cli/commands/plugin.ts +1 -1
  106. package/src/cli/commands/recovery.ts +25 -3
  107. package/src/cli/commands/runtime.ts +55 -3
  108. package/src/cli/commands/security.ts +12 -1
  109. package/src/cli/commands/setup-profile.ts +31 -21
  110. package/src/cli/controller/check-runner.ts +106 -3
  111. package/src/cli/controller/composite-result.ts +1 -1
  112. package/src/cli/controller/context/focus.ts +51 -0
  113. package/src/cli/controller/context/instruction-context.ts +114 -0
  114. package/src/cli/controller/context/known-paths.ts +76 -0
  115. package/src/cli/controller/context/query-planning.ts +110 -0
  116. package/src/cli/controller/context/rule-resolution.ts +532 -0
  117. package/src/cli/controller/context/source-materializer.ts +278 -0
  118. package/src/cli/controller/context/structural.ts +16 -0
  119. package/src/cli/controller/context/types.ts +286 -0
  120. package/src/cli/controller/context-pack.ts +785 -469
  121. package/src/cli/controller/launch-agents.ts +77 -2
  122. package/src/cli/controller/operational-plan.ts +2 -2
  123. package/src/cli/controller/work-mode.ts +6 -4
  124. package/src/cli/editing/edit-session.ts +60 -7
  125. package/src/cli/github/github.ts +133 -0
  126. package/src/cli/installer/managed-entries.ts +15 -1
  127. package/src/cli/local-bridge/console-automations.ts +54 -78
  128. package/src/cli/local-bridge/console-view-models.ts +1 -35
  129. package/src/cli/local-bridge/facade-api.ts +0 -217
  130. package/src/cli/local-bridge/frontend/src/App.tsx +3 -3
  131. package/src/cli/local-bridge/frontend/src/features/automations/AutomationsView.tsx +23 -13
  132. package/src/cli/local-bridge/frontend/src/features/capabilities/CapabilitiesView.tsx +37 -4
  133. package/src/cli/local-bridge/frontend/src/features/overview/OverviewView.tsx +6 -4
  134. package/src/cli/local-bridge/frontend/src/lib/api.ts +1 -6
  135. package/src/cli/local-bridge/frontend/src/lib/routes.ts +1 -1
  136. package/src/cli/local-bridge/frontend/src/shell/Sidebar.tsx +2 -2
  137. package/src/cli/local-bridge/frontend/src/styles.css +1 -1
  138. package/src/cli/local-bridge/frontend/src/types.ts +5 -8
  139. package/src/cli/local-bridge/job-store.ts +1 -490
  140. package/src/cli/local-bridge/server.ts +0 -513
  141. package/src/cli/local-bridge/ui-dist/app.css +1 -1
  142. package/src/cli/local-bridge/ui-dist/app.js +3703 -3757
  143. package/src/cli/mcp/auth.ts +5 -5
  144. package/src/cli/mcp/instructions.ts +3 -2
  145. package/src/cli/mcp/legacy-tool-service.ts +0 -189
  146. package/src/cli/mcp/multi-repository.ts +16 -5
  147. package/src/cli/mcp/oauth.ts +175 -26
  148. package/src/cli/mcp/repository-tools.ts +247 -107
  149. package/src/cli/mcp/server.ts +537 -111
  150. package/src/cli/mcp/tool-capability-cache.ts +1 -1
  151. package/src/cli/mcp/toolset-selection.ts +1 -1
  152. package/src/cli/mcp/toolset.ts +42 -5
  153. package/src/cli/mcp/transports/http.ts +101 -14
  154. package/src/cli/mcp/transports/session-registry.ts +43 -5
  155. package/src/cli/mcp/types.ts +3 -3
  156. package/src/cli/repositories/command-classifier.ts +101 -19
  157. package/src/cli/repositories/command-executor.ts +55 -521
  158. package/src/cli/repositories/command-process.ts +108 -0
  159. package/src/cli/repositories/command-scope.ts +99 -41
  160. package/src/cli/repositories/controller-home.ts +7 -8
  161. package/src/cli/repositories/git-command-executor.ts +2 -0
  162. package/src/cli/repositories/locks.ts +53 -16
  163. package/src/cli/repositories/repository-snapshot.ts +121 -0
  164. package/src/cli/repositories/selected-path-actions.ts +17 -9
  165. package/src/cli/repositories/structured-git.ts +61 -3
  166. package/src/cli/repository/inspector.ts +553 -63
  167. package/src/cli/repository/session-cache.ts +58 -17
  168. package/src/cli/v81-entry.ts +1 -4
  169. package/src/effects/fs-transaction.ts +85 -17
  170. package/src/runtime/context/codegraph-read-provider.ts +233 -2
  171. package/src/runtime/context/codegraph-sidecar.cjs +74 -40
  172. package/src/runtime/context/generic-lsp-provider.ts +355 -0
  173. package/src/runtime/context/lsp-client.ts +283 -0
  174. package/src/runtime/context/semantic-navigation.ts +275 -0
  175. package/src/runtime/context/swift-navigation.ts +565 -0
  176. package/src/runtime/context/typescript-navigation.ts +226 -0
  177. package/src/runtime/control-plane/dispatch-priority.ts +28 -0
  178. package/src/runtime/control-plane/execution/direct-edit-work-completion.ts +47 -8
  179. package/src/runtime/control-plane/execution/edit-validation-coordinator.ts +86 -24
  180. package/src/runtime/control-plane/execution/session-store.ts +18 -0
  181. package/src/runtime/control-plane/execution/verification-evidence.ts +58 -3
  182. package/src/runtime/control-plane/execution/work-handle-store.ts +27 -2
  183. package/src/runtime/control-plane/execution/work-lifecycle-audit.ts +258 -0
  184. package/src/runtime/control-plane/execution/work-remote-delivery.ts +215 -0
  185. package/src/runtime/control-plane/execution/work-task-receipt.ts +54 -11
  186. package/src/runtime/control-plane/execution/work-terminal-cleanup.ts +143 -8
  187. package/src/runtime/control-plane/execution/work-validation-reconciler.ts +22 -14
  188. package/src/runtime/control-plane/execution/work-verification-snapshot.ts +85 -8
  189. package/src/runtime/control-plane/facade/capability-registry.ts +129 -25
  190. package/src/runtime/control-plane/facade/controller-round-relay.ts +991 -0
  191. package/src/runtime/control-plane/facade/controller-session-store.ts +132 -1
  192. package/src/runtime/control-plane/facade/goal-workloop-access.ts +2 -0
  193. package/src/runtime/control-plane/facade/goal-workloop.ts +686 -129
  194. package/src/runtime/control-plane/facade/index.ts +1 -0
  195. package/src/runtime/control-plane/facade/plan-contract-store.ts +185 -20
  196. package/src/runtime/control-plane/facade/semantic-admission.ts +205 -0
  197. package/src/runtime/control-plane/facade/suggested-actions.ts +5 -1
  198. package/src/runtime/control-plane/facade/types.ts +22 -5
  199. package/src/runtime/control-plane/facade/work-contract-store.ts +175 -73
  200. package/src/runtime/control-plane/generated-cache-retention.ts +271 -0
  201. package/src/runtime/control-plane/global-scheduler/config.ts +44 -0
  202. package/src/runtime/control-plane/global-scheduler/dispatch-capacity.ts +80 -0
  203. package/src/runtime/control-plane/global-scheduler/durable-admission.ts +46 -0
  204. package/src/runtime/control-plane/global-scheduler/maintenance.ts +145 -0
  205. package/src/runtime/control-plane/global-scheduler/projection-refresh.ts +84 -0
  206. package/src/runtime/control-plane/global-scheduler/reconciliation.ts +3 -3
  207. package/src/runtime/control-plane/global-scheduler/scheduler.ts +273 -542
  208. package/src/runtime/control-plane/global-scheduler/source-scan.ts +59 -0
  209. package/src/runtime/control-plane/global-scheduler/state.ts +88 -0
  210. package/src/runtime/control-plane/global-scheduler/worker-attachment.ts +57 -0
  211. package/src/runtime/control-plane/global-scheduler/worker-exit-decision.ts +38 -0
  212. package/src/runtime/control-plane/global-scheduler/worker-exit-reconciler.ts +175 -0
  213. package/src/runtime/control-plane/global-scheduler/worker-launch.ts +111 -0
  214. package/src/runtime/control-plane/global-scheduler/worker-lifecycle-store.ts +64 -0
  215. package/src/runtime/control-plane/global-scheduler/worker-lifecycle.ts +150 -0
  216. package/src/runtime/control-plane/global-scheduler/worker-process.ts +119 -0
  217. package/src/runtime/control-plane/global-scheduler/worker-stderr.ts +60 -0
  218. package/src/runtime/control-plane/launcher/chatgpt-work-binding-store.ts +50 -0
  219. package/src/runtime/control-plane/launcher/chatgpt-work-continuation.ts +355 -116
  220. package/src/runtime/control-plane/launcher/launch-reservation-store.ts +40 -0
  221. package/src/runtime/control-plane/launcher/thin-launcher.ts +194 -10
  222. package/src/runtime/control-plane/persistence/controller-home-migration.ts +487 -0
  223. package/src/runtime/control-plane/persistence/sqlite-store.ts +33 -2
  224. package/src/runtime/control-plane/release-retention.ts +62 -2
  225. package/src/runtime/control-plane/routing/route-policy.ts +7 -16
  226. package/src/runtime/control-plane/runtime-status-client.ts +0 -2
  227. package/src/runtime/diagnostics/mcp-timing.ts +13 -0
  228. package/src/runtime/diagnostics/mcp-transport-benchmark.ts +129 -0
  229. package/src/runtime/diagnostics/performance.ts +24 -1
  230. package/src/runtime/evidence/event-ledger.ts +1 -1
  231. package/src/runtime/execution/jobs/store.ts +58 -4
  232. package/src/runtime/execution/jobs/types.ts +1 -1
  233. package/src/runtime/execution/managed-workspace.ts +203 -1
  234. package/src/runtime/execution/process-runtime/check-facade.ts +51 -4
  235. package/src/runtime/execution/process-runtime/check-result.ts +53 -0
  236. package/src/runtime/execution/process-runtime/check-scheduling.ts +114 -0
  237. package/src/runtime/execution/process-runtime/command-facade.ts +345 -40
  238. package/src/runtime/execution/process-runtime/gc.ts +38 -6
  239. package/src/runtime/execution/process-runtime/lightweight-managed.ts +1184 -0
  240. package/src/runtime/execution/process-runtime/persisted-check.ts +47 -4
  241. package/src/runtime/execution/process-runtime/resource-claims.ts +10 -6
  242. package/src/runtime/execution/process-runtime/runtime.ts +43 -3
  243. package/src/runtime/execution/process-runtime/store.ts +1 -0
  244. package/src/runtime/execution/process-runtime/types.ts +2 -0
  245. package/src/runtime/execution/thin-harness/async-process.ts +12 -2
  246. package/src/runtime/execution/thin-harness/search-worker.ts +54 -5
  247. package/src/runtime/execution/workers/executor.ts +0 -48
  248. package/src/runtime/gateway/mcp/execution-tools.ts +1192 -114
  249. package/src/runtime/gateway/mcp/process-tools.ts +83 -37
  250. package/src/runtime/gateway/mcp/router.ts +184 -82
  251. package/src/runtime/gateway/mcp/runtime-tool-definitions.ts +546 -0
  252. package/src/runtime/gateway/mcp/runtime-tools.ts +2224 -1589
  253. package/src/runtime/plugins/app-store-connect-adapter.ts +123 -19
  254. package/src/runtime/plugins/browser-adapter.ts +2901 -241
  255. package/src/runtime/plugins/browser-automation-service.ts +10 -0
  256. package/src/runtime/plugins/browser-handoff.ts +92 -2
  257. package/src/runtime/plugins/browser-macos-bridge.ts +582 -49
  258. package/src/runtime/plugins/browser-node-bridge.ts +6 -34
  259. package/src/runtime/plugins/browser-provider-registry.ts +109 -0
  260. package/src/runtime/plugins/browser-runtime-contract.ts +152 -0
  261. package/src/runtime/plugins/browser-runtime.ts +183 -0
  262. package/src/runtime/plugins/browser-session-authority.ts +332 -0
  263. package/src/runtime/plugins/capability-authorization-grants.ts +354 -0
  264. package/src/runtime/plugins/desktop-operator-registration.ts +8 -2
  265. package/src/runtime/plugins/external-adapter.ts +324 -3
  266. package/src/runtime/plugins/external-unix-socket.ts +7 -1
  267. package/src/runtime/plugins/first-party-registry.ts +2 -0
  268. package/src/runtime/plugins/github-adapter.ts +125 -0
  269. package/src/runtime/plugins/ios/agent-device-provider.ts +1 -1
  270. package/src/runtime/plugins/ios/agent-device-typed-provider.ts +52 -9
  271. package/src/runtime/plugins/ios/remote-xpc-hid.ts +1171 -0
  272. package/src/runtime/plugins/ios-adapter.ts +106 -16
  273. package/src/runtime/plugins/ios-agent-device.ts +234 -64
  274. package/src/runtime/plugins/ios-physical-device.ts +1143 -392
  275. package/src/runtime/plugins/lightweight-action.ts +153 -0
  276. package/src/runtime/plugins/local-system-adapter.ts +123 -6
  277. package/src/runtime/plugins/macos-capability-broker.ts +55 -9
  278. package/src/runtime/plugins/plugin-action-sidecar.ts +59 -0
  279. package/src/runtime/plugins/plugin-management-adapter.ts +49 -8
  280. package/src/runtime/plugins/resend-adapter.ts +1 -1
  281. package/src/runtime/plugins/store.ts +269 -29
  282. package/src/runtime/plugins/types.ts +35 -2
  283. package/src/runtime/plugins/xiaohongshu-publish.ts +515 -0
  284. package/src/runtime/projections/git-status-sampler.ts +16 -16
  285. package/src/runtime/projections/materialized-view.ts +28 -10
  286. package/src/runtime/recovery/maintenance-executor.ts +393 -28
  287. package/src/runtime/root/mcp-transport.ts +180 -10
  288. package/src/runtime/root/package-connector-service.ts +186 -8
  289. package/src/runtime/root/package-runtime-release.ts +143 -17
  290. package/src/runtime/root/package-runtime-service.ts +430 -22
  291. package/src/runtime/root/release-manifest.ts +7 -2
  292. package/src/runtime/root/release-materialize.ts +19 -0
  293. package/src/runtime/root/release-store.ts +48 -11
  294. package/src/runtime/root/runtime.ts +23 -5
  295. package/src/runtime/root/service.ts +100 -29
  296. package/src/runtime/root/types.ts +2 -0
  297. package/src/runtime/safe-tooling/ios-development.ts +321 -63
  298. package/src/runtime/shared/trusted-executable.ts +62 -0
  299. package/src/runtime/shared/trusted-node-executable.ts +48 -0
  300. package/src/runtime/standalone-recovery/core.ts +700 -92
  301. package/src/runtime/standalone-recovery/entry.ts +99 -23
  302. package/src/runtime/standalone-recovery/installer.ts +19 -3
  303. package/src/runtime/standalone-recovery/service-labels.ts +2 -0
  304. package/src/runtime/standalone-recovery/watchdog-heartbeat.ts +160 -0
  305. package/src/runtime/workflow/schedules/browser-probe.ts +81 -3
  306. package/src/runtime/workflow/schedules/engine.ts +287 -151
  307. package/src/runtime/workflow/schedules/github-issue-watch.ts +158 -0
  308. package/src/runtime/workflow/schedules/settlement.ts +48 -4
  309. package/src/runtime/workflow/schedules/store.ts +131 -10
  310. package/src/runtime/workflow/schedules/types.ts +2 -4
  311. package/src/runtime/workflow/schedules/work-continuation.ts +26 -13
  312. package/src/testing/test-governance.ts +8 -40
  313. package/assets/reference-configs/heartbeat-triage.md +0 -57
  314. package/assets/templates/helpers/harness-trace-grade.sh +0 -150
  315. package/assets/templates/helpers/heartbeat-triage.sh +0 -361
  316. package/assets/templates/helpers/maintenance-triage.sh +0 -167
  317. package/docs/architecture/current/approved-target-architecture.zh-CN.md +0 -1501
  318. package/docs/architecture/current/architecture-invariants.md +0 -331
  319. package/docs/architecture/current/automation-and-schedule-engine.md +0 -459
  320. package/docs/architecture/current/codegraph-context-provider.md +0 -238
  321. package/docs/architecture/current/control-plane-authority-inventory.md +0 -94
  322. package/docs/architecture/current/controller-repository-decoupling.md +0 -148
  323. package/docs/architecture/current/dispatch-and-agent-strategy.md +0 -373
  324. package/docs/architecture/current/entity-model.md +0 -612
  325. package/docs/architecture/current/external-plugin-governance.md +0 -396
  326. package/docs/architecture/current/failure-recovery.md +0 -447
  327. package/docs/architecture/current/governance.md +0 -213
  328. package/docs/architecture/current/human-interaction-plane.md +0 -87
  329. package/docs/architecture/current/implementation-status.md +0 -128
  330. package/docs/architecture/current/job-and-run-lifecycle.md +0 -413
  331. package/docs/architecture/current/legacy-governance.md +0 -58
  332. package/docs/architecture/current/local-workspace-target-grants.md +0 -70
  333. package/docs/architecture/current/migration-roadmap.md +0 -105
  334. package/docs/architecture/current/multi-repository-execution.md +0 -371
  335. package/docs/architecture/current/operations-runbook.md +0 -45
  336. package/docs/architecture/current/peer-supercontroller-runtime.md +0 -32
  337. package/docs/architecture/current/personal-assistant-plugin-baseline.md +0 -206
  338. package/docs/architecture/current/repository-access-modes.md +0 -102
  339. package/docs/architecture/current/route-policy.md +0 -15
  340. package/docs/architecture/current/route-session-concurrency.md +0 -85
  341. package/docs/architecture/current/runtime-architecture-simplification.md +0 -214
  342. package/docs/architecture/current/runtime-directory-map.md +0 -49
  343. package/docs/architecture/current/runtime-health-and-resource-lifecycle.md +0 -85
  344. package/docs/architecture/current/scheduler-and-resource-claims.md +0 -422
  345. package/docs/architecture/current/session-aware-execution-and-authorization.md +0 -77
  346. package/docs/architecture/current/system-overview.md +0 -169
  347. package/docs/architecture/current/target-requirements-traceability.md +0 -202
  348. package/docs/architecture/current/thin-harness-governance-policy.md +0 -32
  349. package/docs/architecture/current/thin-harness-v1.md +0 -321
  350. package/docs/architecture/current/verification-and-release-gates.md +0 -391
  351. package/docs/forge-autonomous-goal-loop.md +0 -9
  352. package/docs/forge-provider-configuration.md +0 -7
  353. package/docs/operations/chatgpt-personal-assistant-runtime.md +0 -93
  354. package/docs/operations/gmail-assistant-routines.md +0 -186
  355. package/docs/operations/personal-assistant-operator-guide.md +0 -61
  356. package/docs/operations/provider-configuration.md +0 -31
  357. package/scripts/harness-trace-grade.sh +0 -150
  358. package/scripts/heartbeat-triage.sh +0 -361
  359. package/scripts/maintenance-triage.sh +0 -167
  360. package/src/cli/local-bridge/frontend/src/features/settings/SettingsView.tsx +0 -2
  361. package/src/cli/repositories/goal-registry.ts +0 -239
  362. package/src/runtime/assistant/action-proposals.ts +0 -279
  363. package/src/runtime/assistant/intent.ts +0 -395
  364. package/src/runtime/assistant/model-provider.ts +0 -460
  365. package/src/runtime/assistant/openapi.ts +0 -223
  366. package/src/runtime/assistant/policy.ts +0 -89
  367. package/src/runtime/assistant/readiness.ts +0 -258
  368. package/src/runtime/assistant/routine-runtime.ts +0 -477
  369. package/src/runtime/assistant/schedule-binding.ts +0 -171
  370. package/src/runtime/assistant/standing-grants.ts +0 -375
  371. package/src/runtime/assistant/store.ts +0 -243
  372. package/src/runtime/assistant/types.ts +0 -135
  373. package/src/runtime/control-plane/goal-loop/config-facade.ts +0 -700
  374. package/src/runtime/control-plane/goal-loop/config-store.ts +0 -570
  375. package/src/runtime/control-plane/goal-loop/config-types.ts +0 -213
  376. package/src/runtime/control-plane/goal-loop/executor-router.ts +0 -109
  377. package/src/runtime/control-plane/goal-loop/failure-taxonomy.ts +0 -149
  378. package/src/runtime/control-plane/goal-loop/goal-contract-store.ts +0 -304
  379. package/src/runtime/control-plane/goal-loop/goal-loop-engine.ts +0 -1001
  380. package/src/runtime/control-plane/goal-loop/handoff-packet.ts +0 -160
  381. package/src/runtime/control-plane/goal-loop/index.ts +0 -13
  382. package/src/runtime/control-plane/goal-loop/local-tools.ts +0 -290
  383. package/src/runtime/control-plane/goal-loop/policy-gates.ts +0 -203
  384. package/src/runtime/control-plane/goal-loop/provider-dispatch.ts +0 -93
  385. package/src/runtime/control-plane/goal-loop/provider-registry.ts +0 -545
  386. package/src/runtime/control-plane/goal-loop/types.ts +0 -378
  387. package/src/runtime/control-plane/startup-recovery.ts +0 -198
  388. package/src/runtime/gateway/mcp/resource-policy.ts +0 -186
  389. package/src/runtime/personal-assistant/gmail-triage-manager.ts +0 -231
  390. package/src/runtime/personal-assistant/reporting-runtime.ts +0 -344
  391. package/src/runtime/personal-assistant/triage-runtime.ts +0 -748
  392. package/src/runtime/workflow/findings/store.ts +0 -204
  393. package/src/runtime/workflow/findings/types.ts +0 -58
  394. package/src/runtime/workflow/portfolio/engine.ts +0 -20
  395. package/src/runtime/workflow/portfolio/store.ts +0 -185
  396. package/src/runtime/workflow/portfolio/types.ts +0 -29
@@ -1,9 +1,10 @@
1
1
  import { spawn } from 'child_process';
2
- import { accessSync, constants, existsSync } from 'fs';
3
- import { delimiter, dirname, isAbsolute, join, resolve } from 'path';
2
+ import { existsSync } from 'fs';
3
+ import { dirname, join } from 'path';
4
4
  import { fileURLToPath } from 'url';
5
5
  import type { AssistantPluginActionExecutionInput } from './types';
6
6
  import { AssistantPluginError } from './errors';
7
+ import { resolveTrustedNodeExecutable } from '../shared/trusted-node-executable';
7
8
 
8
9
  const BRIDGE_SCHEMA_VERSION = 1;
9
10
  const MAX_REQUEST_BYTES = 1_048_576;
@@ -43,43 +44,14 @@ interface BridgeFailure {
43
44
 
44
45
  type BridgeResponse = BridgeSuccess | BridgeFailure;
45
46
 
46
- function isExecutable(path: string): boolean {
47
- try {
48
- accessSync(path, constants.X_OK);
49
- return existsSync(path);
50
- } catch {
51
- return false;
52
- }
53
- }
54
-
55
- function pathCandidates(env: NodeJS.ProcessEnv): string[] {
56
- const candidates = [
57
- env.FORGE_NODE_EXECUTABLE,
58
- env.VOLTA_HOME ? join(env.VOLTA_HOME, 'bin', 'node') : undefined,
59
- '/opt/homebrew/bin/node',
60
- '/usr/local/bin/node',
61
- '/usr/bin/node',
62
- ];
63
- for (const entry of (env.PATH ?? '').split(delimiter)) {
64
- if (entry.trim()) candidates.push(join(entry, process.platform === 'win32' ? 'node.exe' : 'node'));
65
- }
66
- return candidates.filter((value): value is string => Boolean(value));
67
- }
68
-
69
47
  export function resolveBrowserBridgeNodeExecutable(env: NodeJS.ProcessEnv = process.env): string {
70
- if (env.FORGE_NODE_EXECUTABLE) {
71
- const configured = isAbsolute(env.FORGE_NODE_EXECUTABLE)
72
- ? env.FORGE_NODE_EXECUTABLE
73
- : resolve(env.FORGE_NODE_EXECUTABLE);
74
- if (isExecutable(configured)) return configured;
48
+ const resolution = resolveTrustedNodeExecutable(env);
49
+ if (resolution.executable) return resolution.executable;
50
+ if (resolution.configuredInvalid) {
75
51
  throw new AssistantPluginError('PLUGIN_BROWSER_NODE_UNAVAILABLE', 'The configured Browser bridge Node executable is not executable.', {
76
52
  retryable: false,
77
53
  });
78
54
  }
79
- for (const candidate of pathCandidates(env)) {
80
- const absolute = isAbsolute(candidate) ? candidate : resolve(candidate);
81
- if (isExecutable(absolute)) return absolute;
82
- }
83
55
  throw new AssistantPluginError('PLUGIN_BROWSER_NODE_UNAVAILABLE', 'Browser attach operations require a trusted Node executable, but none was found.', {
84
56
  retryable: false,
85
57
  });
@@ -0,0 +1,109 @@
1
+ import { AssistantPluginError } from './errors';
2
+ import {
3
+ providerSupports,
4
+ type BrowserForegroundRequirement,
5
+ type BrowserProviderCapabilities,
6
+ type BrowserProviderCapability,
7
+ } from './browser-runtime-contract';
8
+
9
+ export interface BrowserRuntimeProvider<TInput, TResult> extends BrowserProviderCapabilities {
10
+ /** Lower values are preferred when multiple providers satisfy the same capability contract. */
11
+ priority: number;
12
+ /** Availability is decided before execution; ordinary provider failures are never fallback signals. */
13
+ supportsInput(input: TInput): boolean;
14
+ execute(input: TInput): Promise<TResult>;
15
+ /** Runs only after an explicit stale/restart/configuration boundary. */
16
+ revalidate?: () => Promise<void> | void;
17
+ }
18
+
19
+ interface BrowserProviderState<TInput, TResult> {
20
+ provider: BrowserRuntimeProvider<TInput, TResult>;
21
+ generation: number;
22
+ invalidatedReason?: string;
23
+ }
24
+
25
+ export interface BrowserProviderSelection<TInput, TResult> {
26
+ provider: BrowserRuntimeProvider<TInput, TResult>;
27
+ generation: number;
28
+ }
29
+
30
+ /**
31
+ * A typed pre-action rejection. Runtime may select another provider because this proves the action
32
+ * was not attempted. Arbitrary provider errors are intentionally not mapped to this signal.
33
+ */
34
+ export class BrowserProviderUnavailableBeforeActionError extends Error {
35
+ readonly providerId: string;
36
+ readonly reason: string;
37
+
38
+ constructor(providerId: string, reason: string) {
39
+ super(`${providerId} unavailable before action: ${reason}`);
40
+ this.name = 'BrowserProviderUnavailableBeforeActionError';
41
+ this.providerId = providerId;
42
+ this.reason = reason;
43
+ }
44
+ }
45
+
46
+ function foregroundCompatible(
47
+ provider: BrowserProviderCapabilities,
48
+ requested: BrowserForegroundRequirement,
49
+ ): boolean {
50
+ // Background-safe providers may execute explicit foreground transactions; foreground-only
51
+ // providers may not satisfy a background-safe transaction.
52
+ return requested === 'explicit_required' || provider.foreground === 'none';
53
+ }
54
+
55
+ export class BrowserProviderRegistry<TInput, TResult> {
56
+ private readonly providers = new Map<string, BrowserProviderState<TInput, TResult>>();
57
+
58
+ register(provider: BrowserRuntimeProvider<TInput, TResult>): void {
59
+ const current = this.providers.get(provider.providerId);
60
+ if (current) {
61
+ // Refresh call-local closures without discarding the warm provider generation.
62
+ current.provider = provider;
63
+ return;
64
+ }
65
+ this.providers.set(provider.providerId, { provider, generation: 1 });
66
+ }
67
+
68
+ invalidate(providerId: string, reason: string): void {
69
+ const state = this.providers.get(providerId);
70
+ if (state) state.invalidatedReason = reason;
71
+ }
72
+
73
+ invalidateAll(reason: string): void {
74
+ for (const state of this.providers.values()) state.invalidatedReason = reason;
75
+ }
76
+
77
+ private async prepare(state: BrowserProviderState<TInput, TResult>): Promise<void> {
78
+ if (!state.invalidatedReason) return;
79
+ await state.provider.revalidate?.();
80
+ state.invalidatedReason = undefined;
81
+ state.generation += 1;
82
+ }
83
+
84
+ async select(options: {
85
+ input: TInput;
86
+ requiredCapabilities: readonly BrowserProviderCapability[];
87
+ foreground: BrowserForegroundRequirement;
88
+ excludedProviderIds?: ReadonlySet<string>;
89
+ }): Promise<BrowserProviderSelection<TInput, TResult>> {
90
+ const candidates = [...this.providers.values()]
91
+ .filter(({ provider }) => !options.excludedProviderIds?.has(provider.providerId))
92
+ .filter(({ provider }) => provider.supportsInput(options.input))
93
+ .filter(({ provider }) => providerSupports(provider, options.requiredCapabilities))
94
+ .filter(({ provider }) => foregroundCompatible(provider, options.foreground))
95
+ .sort((left, right) => left.provider.priority - right.provider.priority
96
+ || left.provider.providerId.localeCompare(right.provider.providerId));
97
+
98
+ const selected = candidates[0];
99
+ if (!selected) {
100
+ throw new AssistantPluginError(
101
+ 'PLUGIN_BROWSER_PROVIDER_UNAVAILABLE',
102
+ `No Browser provider satisfies required capabilities: ${options.requiredCapabilities.join(', ') || 'browser.transaction'}.`,
103
+ { retryable: true },
104
+ );
105
+ }
106
+ await this.prepare(selected);
107
+ return { provider: selected.provider, generation: selected.generation };
108
+ }
109
+ }
@@ -0,0 +1,152 @@
1
+ export type BrowserProviderCapability =
2
+ | 'dom.read'
3
+ | 'dom.interact'
4
+ | 'browser.internal_resources'
5
+ | 'browser.screenshot'
6
+ | 'browser.trusted_input'
7
+ | 'browser.foreground'
8
+ | 'browser.transaction'
9
+ | 'browser.persistent_handle';
10
+
11
+ export type BrowserTargetOwnership = 'plugin_owned' | 'user_owned' | 'provider_owned';
12
+ export type BrowserTargetKind = 'page' | 'tab' | 'browser_internal_resource';
13
+ export type BrowserForegroundRequirement = 'none' | 'explicit_required';
14
+ export type BrowserActionReplaySafety = 'read_only' | 'idempotent' | 'non_idempotent';
15
+
16
+ /** Stable resource identity. URL/title are deliberately excluded because they are mutable observations. */
17
+ export interface BrowserTargetIdentity {
18
+ providerId: string;
19
+ resourceKind: BrowserTargetKind;
20
+ resourceId: string;
21
+ browserProduct?: string;
22
+ ownership: BrowserTargetOwnership;
23
+ }
24
+
25
+ export interface BrowserObservedState {
26
+ url: string;
27
+ title?: string;
28
+ observedAt: string;
29
+ providerRevision?: string;
30
+ }
31
+
32
+ export interface BrowserProviderCapabilities {
33
+ providerId: string;
34
+ capabilities: readonly BrowserProviderCapability[];
35
+ foreground: BrowserForegroundRequirement;
36
+ /** True only when the provider can verify postconditions in the same provider call that performs the action. */
37
+ verifiesPostconditions: boolean;
38
+ /** True only when an already-bound provider handle can be reused across bounded consecutive actions. */
39
+ persistentHandle: boolean;
40
+ }
41
+
42
+ export type BrowserCondition =
43
+ | { kind: 'target_identity'; target: BrowserTargetIdentity }
44
+ | { kind: 'url_equals'; url: string }
45
+ | { kind: 'url_matches'; pattern: string }
46
+ | { kind: 'selector_exists'; selector: string }
47
+ | { kind: 'selector_visible'; selector: string }
48
+ | { kind: 'text_contains'; text: string; selector?: string }
49
+ | { kind: 'attribute_equals'; selector: string; attribute: string; value: string }
50
+ | { kind: 'provider_assertion'; assertion: string; expected: string | number | boolean };
51
+
52
+ export type BrowserTransactionAction =
53
+ | { kind: 'read'; operation: string; arguments?: Record<string, unknown> }
54
+ | { kind: 'dom'; operation: string; arguments?: Record<string, unknown> }
55
+ | { kind: 'internal_resource'; operation: string; arguments?: Record<string, unknown> }
56
+ | { kind: 'trusted_input'; operation: string; arguments?: Record<string, unknown> };
57
+
58
+ export interface BrowserTransaction {
59
+ transactionId: string;
60
+ target: BrowserTargetIdentity;
61
+ requiredCapabilities: readonly BrowserProviderCapability[];
62
+ foreground: BrowserForegroundRequirement;
63
+ replaySafety: BrowserActionReplaySafety;
64
+ preconditions?: readonly BrowserCondition[];
65
+ action: BrowserTransactionAction;
66
+ /** Writes/interactions require at least one postcondition unless the action itself returns a typed read result. */
67
+ postconditions?: readonly BrowserCondition[];
68
+ timeoutMs: number;
69
+ }
70
+
71
+ export interface BrowserConditionEvidence {
72
+ condition: BrowserCondition;
73
+ satisfied: boolean;
74
+ observed?: unknown;
75
+ reason?: string;
76
+ }
77
+
78
+ export interface BrowserTransactionTiming {
79
+ providerCalls: number;
80
+ providerDurationMs: number;
81
+ totalDurationMs: number;
82
+ }
83
+
84
+ export interface BrowserTransactionResult<T = unknown> {
85
+ transactionId: string;
86
+ target: BrowserTargetIdentity;
87
+ transportSucceeded: boolean;
88
+ actionPerformed: boolean;
89
+ /** Authoritative success bit. AX/transport success alone must never set this true. */
90
+ verified: boolean;
91
+ result?: T;
92
+ observedState?: BrowserObservedState;
93
+ preconditionEvidence: readonly BrowserConditionEvidence[];
94
+ postconditionEvidence: readonly BrowserConditionEvidence[];
95
+ timing: BrowserTransactionTiming;
96
+ }
97
+
98
+ export interface BrowserRuntimeBudget {
99
+ p95Ms: number;
100
+ maxProviderCallsWarm: number;
101
+ maxProviderCallsCold: number;
102
+ foregroundAllowed: boolean;
103
+ }
104
+
105
+ /**
106
+ * Architecture targets, not per-host promises. Live V2 gates report p50/p95 and fail when a
107
+ * regression materially exceeds these budgets without attributable provider evidence.
108
+ */
109
+ export const BROWSER_RUNTIME_V2_BUDGETS = {
110
+ read: { p95Ms: 350, maxProviderCallsWarm: 1, maxProviderCallsCold: 2, foregroundAllowed: false },
111
+ domInteraction: { p95Ms: 600, maxProviderCallsWarm: 1, maxProviderCallsCold: 2, foregroundAllowed: false },
112
+ internalResource: { p95Ms: 700, maxProviderCallsWarm: 1, maxProviderCallsCold: 2, foregroundAllowed: false },
113
+ physicalInput: { p95Ms: 1_500, maxProviderCallsWarm: 1, maxProviderCallsCold: 2, foregroundAllowed: true },
114
+ } as const satisfies Record<string, BrowserRuntimeBudget>;
115
+
116
+ export function browserTargetKey(target: BrowserTargetIdentity): string {
117
+ return [target.providerId, target.browserProduct ?? '', target.resourceKind, target.resourceId, target.ownership].join(':');
118
+ }
119
+
120
+ export function providerSupports(
121
+ provider: BrowserProviderCapabilities,
122
+ required: readonly BrowserProviderCapability[],
123
+ ): boolean {
124
+ const available = new Set(provider.capabilities);
125
+ return required.every((capability) => available.has(capability));
126
+ }
127
+
128
+ export function browserTransactionVerified(result: BrowserTransactionResult): boolean {
129
+ return result.transportSucceeded
130
+ && result.actionPerformed
131
+ && result.verified
132
+ && result.preconditionEvidence.every((entry) => entry.satisfied)
133
+ && result.postconditionEvidence.every((entry) => entry.satisfied);
134
+ }
135
+
136
+ export function browserTransactionRequiresPostcondition(transaction: BrowserTransaction): boolean {
137
+ return transaction.replaySafety !== 'read_only';
138
+ }
139
+
140
+ export function validateBrowserTransaction(transaction: BrowserTransaction): string[] {
141
+ const errors: string[] = [];
142
+ if (!transaction.transactionId.trim()) errors.push('transactionId is required');
143
+ if (!transaction.target.providerId.trim() || !transaction.target.resourceId.trim()) errors.push('stable target identity is incomplete');
144
+ if (!Number.isFinite(transaction.timeoutMs) || transaction.timeoutMs <= 0) errors.push('timeoutMs must be positive');
145
+ if (transaction.foreground === 'none' && transaction.requiredCapabilities.includes('browser.foreground')) {
146
+ errors.push('foreground capability cannot be required by a foreground-free transaction');
147
+ }
148
+ if (browserTransactionRequiresPostcondition(transaction) && (transaction.postconditions?.length ?? 0) === 0) {
149
+ errors.push('interactive transactions require at least one postcondition');
150
+ }
151
+ return errors;
152
+ }
@@ -0,0 +1,183 @@
1
+ import { AssistantPluginError } from './errors';
2
+ import type { AssistantPluginActionExecutionInput } from './types';
3
+ import {
4
+ validateBrowserTransaction,
5
+ type BrowserActionReplaySafety,
6
+ type BrowserForegroundRequirement,
7
+ type BrowserProviderCapability,
8
+ type BrowserTargetIdentity,
9
+ type BrowserTransaction,
10
+ } from './browser-runtime-contract';
11
+ import {
12
+ BrowserProviderRegistry,
13
+ BrowserProviderUnavailableBeforeActionError,
14
+ type BrowserRuntimeProvider,
15
+ } from './browser-provider-registry';
16
+
17
+ export const ALL_BROWSER_PROVIDER_CAPABILITIES = [
18
+ 'dom.read',
19
+ 'dom.interact',
20
+ 'browser.internal_resources',
21
+ 'browser.screenshot',
22
+ 'browser.trusted_input',
23
+ 'browser.foreground',
24
+ 'browser.transaction',
25
+ 'browser.persistent_handle',
26
+ ] as const satisfies readonly BrowserProviderCapability[];
27
+
28
+ const READ_ACTIONS = new Set([
29
+ 'list_sessions', 'reconcile_sessions', 'get_handoff_status',
30
+ 'get_text', 'get_html', 'query_selector', 'query_all', 'get_attribute', 'list_frames', 'verify_state',
31
+ 'extract_links', 'extract_tables', 'extract_forms', 'snapshot_interactive', 'get_console_errors', 'get_failed_requests',
32
+ 'wait_for_load_state', 'wait_for_selector', 'await_file_transfer',
33
+ ]);
34
+ const SCREENSHOT_ACTIONS = new Set(['screenshot']);
35
+ const TRUSTED_INPUT_ACTIONS = new Set(['trusted_input', 'activate_page']);
36
+ const DOM_INTERACTION_ACTIONS = new Set([
37
+ 'create_session', 'open_page', 'navigate', 'reload', 'go_back',
38
+ 'click', 'click_text', 'double_click', 'hover', 'focus', 'type', 'fill', 'select_option', 'check', 'uncheck',
39
+ 'press', 'keyboard_shortcut', 'dispatch_event', 'attach_local_file', 'close_page',
40
+ ]);
41
+ const IDEMPOTENT_ACTIONS = new Set(['configure', 'close_session', 'clear_session', 'request_human_handoff', 'resolve_handoff']);
42
+
43
+ interface BrowserRuntimeActionPolicy {
44
+ requiredCapabilities: readonly BrowserProviderCapability[];
45
+ foreground: BrowserForegroundRequirement;
46
+ replaySafety: BrowserActionReplaySafety;
47
+ }
48
+
49
+ const registries = new Map<string, BrowserProviderRegistry<AssistantPluginActionExecutionInput, Record<string, unknown>>>();
50
+
51
+ function registryFor(runtimeKey: string): BrowserProviderRegistry<AssistantPluginActionExecutionInput, Record<string, unknown>> {
52
+ let registry = registries.get(runtimeKey);
53
+ if (!registry) {
54
+ registry = new BrowserProviderRegistry();
55
+ registries.set(runtimeKey, registry);
56
+ }
57
+ return registry;
58
+ }
59
+
60
+ export function invalidateBrowserRuntime(runtimeKey: string, reason: string): void {
61
+ registries.get(runtimeKey)?.invalidateAll(reason);
62
+ }
63
+
64
+ export function browserRuntimeActionPolicy(actionId: string): BrowserRuntimeActionPolicy {
65
+ if (SCREENSHOT_ACTIONS.has(actionId)) {
66
+ return { requiredCapabilities: ['browser.screenshot', 'browser.transaction'], foreground: 'none', replaySafety: 'read_only' };
67
+ }
68
+ if (TRUSTED_INPUT_ACTIONS.has(actionId)) {
69
+ return {
70
+ requiredCapabilities: ['browser.trusted_input', 'browser.foreground', 'browser.transaction'],
71
+ foreground: 'explicit_required',
72
+ replaySafety: 'non_idempotent',
73
+ };
74
+ }
75
+ if (READ_ACTIONS.has(actionId)) {
76
+ return { requiredCapabilities: ['dom.read', 'browser.transaction'], foreground: 'none', replaySafety: 'read_only' };
77
+ }
78
+ if (DOM_INTERACTION_ACTIONS.has(actionId)) {
79
+ return { requiredCapabilities: ['dom.interact', 'browser.transaction'], foreground: 'none', replaySafety: 'non_idempotent' };
80
+ }
81
+ return {
82
+ requiredCapabilities: ['browser.transaction'],
83
+ foreground: 'none',
84
+ replaySafety: IDEMPOTENT_ACTIONS.has(actionId) ? 'idempotent' : 'non_idempotent',
85
+ };
86
+ }
87
+
88
+ function stringArgument(args: Record<string, unknown>, key: string): string | undefined {
89
+ const value = args[key];
90
+ return typeof value === 'string' && value.trim() ? value.trim() : undefined;
91
+ }
92
+
93
+ function stableTargetFor(input: AssistantPluginActionExecutionInput, providerId: string): BrowserTargetIdentity {
94
+ const sessionId = stringArgument(input.args, 'session_id');
95
+ const nativeProduct = stringArgument(input.args, 'native_browser_product');
96
+ const nativeWindowId = stringArgument(input.args, 'native_window_id');
97
+ const nativeTabId = stringArgument(input.args, 'native_tab_id');
98
+ if (nativeWindowId && nativeTabId) {
99
+ return {
100
+ providerId,
101
+ resourceKind: 'tab',
102
+ resourceId: `window:${nativeWindowId}/tab:${nativeTabId}`,
103
+ ...(nativeProduct ? { browserProduct: nativeProduct } : {}),
104
+ ownership: 'user_owned',
105
+ };
106
+ }
107
+ if (sessionId) {
108
+ return {
109
+ providerId,
110
+ resourceKind: 'page',
111
+ resourceId: `session:${sessionId}`,
112
+ ownership: 'provider_owned',
113
+ };
114
+ }
115
+ return {
116
+ providerId,
117
+ resourceKind: 'page',
118
+ resourceId: `request:${input.requestId}:${input.actionId}`,
119
+ ownership: 'plugin_owned',
120
+ };
121
+ }
122
+
123
+ function transactionFor(
124
+ input: AssistantPluginActionExecutionInput,
125
+ providerId: string,
126
+ policy: BrowserRuntimeActionPolicy,
127
+ ): BrowserTransaction {
128
+ return {
129
+ transactionId: input.requestId,
130
+ target: stableTargetFor(input, providerId),
131
+ requiredCapabilities: policy.requiredCapabilities,
132
+ foreground: policy.foreground,
133
+ replaySafety: policy.replaySafety,
134
+ action: {
135
+ kind: policy.replaySafety === 'read_only' ? 'read' : policy.foreground === 'explicit_required' ? 'trusted_input' : 'dom',
136
+ operation: input.actionId,
137
+ arguments: input.args,
138
+ },
139
+ ...(policy.replaySafety === 'read_only'
140
+ ? {}
141
+ : { postconditions: [{ kind: 'provider_assertion', assertion: 'semantic_action_result', expected: true }] as const }),
142
+ timeoutMs: typeof input.args.timeout_ms === 'number' && Number.isFinite(input.args.timeout_ms)
143
+ ? Math.max(1, Math.trunc(input.args.timeout_ms))
144
+ : 60_000,
145
+ };
146
+ }
147
+
148
+ export async function executeBrowserRuntimeAction(options: {
149
+ runtimeKey: string;
150
+ input: AssistantPluginActionExecutionInput;
151
+ providers: readonly BrowserRuntimeProvider<AssistantPluginActionExecutionInput, Record<string, unknown>>[];
152
+ }): Promise<Record<string, unknown>> {
153
+ const registry = registryFor(options.runtimeKey);
154
+ for (const provider of options.providers) registry.register(provider);
155
+
156
+ const policy = browserRuntimeActionPolicy(options.input.actionId);
157
+ const excluded = new Set<string>();
158
+ while (true) {
159
+ const selection = await registry.select({
160
+ input: options.input,
161
+ requiredCapabilities: policy.requiredCapabilities,
162
+ foreground: policy.foreground,
163
+ excludedProviderIds: excluded,
164
+ });
165
+ const transaction = transactionFor(options.input, selection.provider.providerId, policy);
166
+ const validationErrors = validateBrowserTransaction(transaction);
167
+ if (validationErrors.length > 0) {
168
+ throw new AssistantPluginError('PLUGIN_BROWSER_TRANSACTION_INVALID', validationErrors[0]!, {
169
+ retryable: false,
170
+ details: { transactionId: transaction.transactionId, errors: validationErrors },
171
+ });
172
+ }
173
+
174
+ try {
175
+ return await selection.provider.execute(options.input);
176
+ } catch (error) {
177
+ if (!(error instanceof BrowserProviderUnavailableBeforeActionError)) throw error;
178
+ excluded.add(selection.provider.providerId);
179
+ // This is provider reselection, not action replay: the typed error proves the rejected provider
180
+ // never attempted the action. Unknown outcomes from non-idempotent actions always propagate.
181
+ }
182
+ }
183
+ }