@moretea-labs/forge 1.5.1 → 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 (434) hide show
  1. package/AGENTS.md +2 -0
  2. package/CHANGELOG.md +46 -0
  3. package/CLAUDE.md +2 -0
  4. package/DESIGN.md +7 -2
  5. package/README.md +4 -4
  6. package/README.zh-CN.md +2 -2
  7. package/SKILL.md +2 -2
  8. package/THIRD_PARTY_NOTICES.md +1 -1
  9. package/agents/openai.yaml +1 -1
  10. package/assets/hooks/hook-input.sh +11 -8
  11. package/assets/hooks/lib/session-state.sh +10 -7
  12. package/assets/hooks/lib/workflow-state.sh +13 -177
  13. package/assets/hooks/post-tool-observer.sh +8 -2
  14. package/assets/hooks/pre-edit-guard.sh +8 -39
  15. package/assets/hooks/prompt-guard.sh +7 -83
  16. package/assets/hooks/session-start-context.sh +56 -1
  17. package/assets/partials/05-workflow.partial.md +1 -1
  18. package/assets/partials-agents/03-orchestration.partial.md +1 -1
  19. package/assets/plugin-registry.v1.json +54 -3
  20. package/assets/reference-configs/document-generation.md +1 -1
  21. package/assets/reference-configs/harness-overview.md +1 -1
  22. package/assets/reference-configs/hook-operations.md +1 -1
  23. package/assets/reference-configs/sprint-contracts.md +3 -3
  24. package/assets/skill-version.json +2 -2
  25. package/assets/templates/contract.template.md +2 -7
  26. package/assets/templates/helpers/capture-plan.sh +2 -2
  27. package/assets/templates/helpers/check-task-workflow.sh +4 -4
  28. package/assets/templates/helpers/contract-worktree.sh +1 -21
  29. package/assets/templates/helpers/ensure-task-workflow.sh +13 -38
  30. package/assets/templates/helpers/migrate-project-template.sh +22 -45
  31. package/assets/templates/helpers/new-plan.sh +1 -1
  32. package/assets/templates/helpers/plan-to-todo.sh +12 -37
  33. package/assets/templates/helpers/ship-worktrees.sh +2 -29
  34. package/assets/templates/helpers/sprint-backlog.sh +6 -6
  35. package/assets/templates/helpers/verify-contract.sh +1 -111
  36. package/assets/templates/helpers/verify-sprint.sh +3 -180
  37. package/assets/templates/plan.template.md +1 -1
  38. package/assets/templates/review.template.md +9 -34
  39. package/assets/workflow-contract.v1.json +10 -19
  40. package/docs/README.md +10 -10
  41. package/docs/architecture/CURRENT.md +170 -0
  42. package/docs/architecture/EVOLUTION.md +42 -0
  43. package/docs/architecture/current/README.md +4 -156
  44. package/docs/architecture/decisions/20260803-release-identity-binding-and-exit-policy.md +2 -2
  45. package/docs/architecture/decisions/20260823-immediate-controller-relay.md +53 -0
  46. package/docs/architecture/decisions/20260826-browser-runtime-v2.md +73 -0
  47. package/docs/architecture/history/README.md +7 -0
  48. package/docs/architecture/{chatgpt-handoff-facade.md → history/chatgpt-handoff-facade.md} +4 -0
  49. package/docs/architecture/{global-hook-runtime.md → history/global-hook-runtime.md} +7 -3
  50. package/docs/architecture/{ios-semantic-automation-provider-v2.md → history/ios-semantic-automation-provider-v2.md} +6 -2
  51. package/docs/architecture/history.md +3 -34
  52. package/docs/architecture/index.md +15 -98
  53. package/docs/architecture/modules/controller-runtime/transport-lifecycle.md +1 -1
  54. package/docs/architecture/reviews/2026-08-22-semantic-harness-convergence-acceptance.md +39 -0
  55. package/docs/architecture/versions/1.6.md +38 -0
  56. package/docs/architecture/versions/1.7.md +41 -0
  57. package/docs/forge-chatgpt-browser-engine.md +2 -2
  58. package/docs/forge-chatgpt-mcp-setup.md +4 -28
  59. package/docs/forge-chatgpt-supervised-automation.md +3 -3
  60. package/docs/forge-github-issue-launcher.md +1 -1
  61. package/docs/forge-runtime-self-healing-loop.md +1 -1
  62. package/docs/operations/controller-browser-plugin.md +38 -22
  63. package/docs/operations/controller-performance-and-502.md +124 -0
  64. package/docs/operations/controller-reliability-runbook.md +1 -1
  65. package/docs/operations/features.md +3 -3
  66. package/docs/operations/github-repository.md +1 -1
  67. package/docs/operations/homebrew.md +2 -2
  68. package/docs/operations/mcp-tool-exposure.md +5 -3
  69. package/docs/tutorials/01-install-and-start.md +1 -1
  70. package/docs/tutorials/01-install-and-start.zh-CN.md +1 -1
  71. package/docs/wiki/Architecture.md +6 -6
  72. package/docs/wiki/Implementation.md +2 -2
  73. package/docs/wiki/Installation.md +1 -1
  74. package/docs/wiki/Integrations.md +2 -2
  75. package/docs/wiki/Quick-Start.md +1 -1
  76. package/docs/wiki/Work-Lifecycle.md +1 -1
  77. package/package.json +29 -10
  78. package/scripts/activate-source-baseline.ts +17 -13
  79. package/scripts/benchmark-background-check-overlap.ts +228 -0
  80. package/scripts/benchmark-mcp-host.sh +117 -0
  81. package/scripts/benchmark-mcp-transport.ts +170 -0
  82. package/scripts/benchmark-quality-harness.ts +146 -0
  83. package/scripts/benchmark-route-session-concurrency.ts +207 -6
  84. package/scripts/benchmark-thin-harness-mcp-e2e.ts +7 -1
  85. package/scripts/benchmark-typescript-navigation.ts +186 -0
  86. package/scripts/benchmark-work-efficiency.ts +334 -0
  87. package/scripts/capture-plan.sh +3 -3
  88. package/scripts/check-agent-tooling.sh +8 -35
  89. package/scripts/check-architecture-sync.sh +17 -86
  90. package/scripts/check-mcp-compatibility.ts +14 -0
  91. package/scripts/check-public-docs.sh +14 -1
  92. package/scripts/check-runtime-architecture.mjs +107 -64
  93. package/scripts/check-stable-baseline.ts +92 -0
  94. package/scripts/check-task-workflow.sh +4 -4
  95. package/scripts/contract-worktree.sh +1 -21
  96. package/scripts/ensure-task-workflow.sh +22 -55
  97. package/scripts/host-temporary-cloud-mcp-e2e.sh +265 -0
  98. package/scripts/install-standalone-recovery.ts +24 -0
  99. package/scripts/lib/project-init-lib.sh +15 -44
  100. package/scripts/migrate-chatgpt-automation-schedules.ts +64 -0
  101. package/scripts/migrate-project-template.sh +23 -1179
  102. package/scripts/new-plan.sh +1 -1
  103. package/scripts/plan-to-todo.sh +11 -36
  104. package/scripts/run-governed-gate.ts +2 -1
  105. package/scripts/ship-worktrees.sh +2 -29
  106. package/scripts/smoke-ios-physical-device.ts +4 -2
  107. package/scripts/smoke-runtime-recovery.ts +1 -35
  108. package/scripts/smoke-schedule-engine.ts +1 -20
  109. package/scripts/sprint-backlog.sh +1 -1
  110. package/scripts/verify-contract.sh +1 -111
  111. package/scripts/verify-forge-runtime.sh +0 -1
  112. package/scripts/verify-sprint.sh +3 -180
  113. package/scripts/workflow-contract.ts +1 -5
  114. package/src/cli/commands/chatgpt.ts +31 -2
  115. package/src/cli/commands/init-hook.ts +3 -3
  116. package/src/cli/commands/mcp.ts +9 -5
  117. package/src/cli/commands/plugin.ts +37 -10
  118. package/src/cli/commands/recovery.ts +25 -3
  119. package/src/cli/commands/runtime.ts +55 -3
  120. package/src/cli/commands/security.ts +12 -1
  121. package/src/cli/commands/setup-profile.ts +31 -21
  122. package/src/cli/controller/check-runner.ts +106 -3
  123. package/src/cli/controller/composite-result.ts +1 -1
  124. package/src/cli/controller/context/focus.ts +51 -0
  125. package/src/cli/controller/context/instruction-context.ts +114 -0
  126. package/src/cli/controller/context/known-paths.ts +76 -0
  127. package/src/cli/controller/context/query-planning.ts +110 -0
  128. package/src/cli/controller/context/rule-resolution.ts +532 -0
  129. package/src/cli/controller/context/source-materializer.ts +278 -0
  130. package/src/cli/controller/context/structural.ts +16 -0
  131. package/src/cli/controller/context/types.ts +286 -0
  132. package/src/cli/controller/context-pack.ts +898 -430
  133. package/src/cli/controller/launch-agents.ts +77 -2
  134. package/src/cli/controller/operational-plan.ts +2 -2
  135. package/src/cli/controller/work-mode.ts +6 -4
  136. package/src/cli/editing/edit-session.ts +60 -7
  137. package/src/cli/github/github.ts +133 -0
  138. package/src/cli/hook/prompt-guard-decision.ts +17 -18
  139. package/src/cli/hook/prompt-intents.ts +1 -1
  140. package/src/cli/installer/managed-entries.ts +15 -1
  141. package/src/cli/local-bridge/console-automations.ts +225 -67
  142. package/src/cli/local-bridge/console-view-models.ts +3 -35
  143. package/src/cli/local-bridge/facade-api.ts +2 -217
  144. package/src/cli/local-bridge/frontend/src/App.tsx +3 -3
  145. package/src/cli/local-bridge/frontend/src/features/automations/AutomationsView.tsx +153 -3
  146. package/src/cli/local-bridge/frontend/src/features/capabilities/CapabilitiesView.tsx +37 -4
  147. package/src/cli/local-bridge/frontend/src/features/overview/OverviewView.tsx +183 -3
  148. package/src/cli/local-bridge/frontend/src/features/repositories/RepositoriesView.tsx +1 -1
  149. package/src/cli/local-bridge/frontend/src/features/work/WorkView.tsx +4 -3
  150. package/src/cli/local-bridge/frontend/src/lib/api.ts +18 -11
  151. package/src/cli/local-bridge/frontend/src/lib/routes.ts +1 -1
  152. package/src/cli/local-bridge/frontend/src/shell/CommandBar.tsx +1 -1
  153. package/src/cli/local-bridge/frontend/src/shell/Sidebar.tsx +4 -3
  154. package/src/cli/local-bridge/frontend/src/styles.css +27 -11
  155. package/src/cli/local-bridge/frontend/src/types.ts +8 -7
  156. package/src/cli/local-bridge/job-store.ts +1 -490
  157. package/src/cli/local-bridge/server.ts +29 -532
  158. package/src/cli/local-bridge/ui-dist/app.css +1 -1
  159. package/src/cli/local-bridge/ui-dist/app.js +5101 -4967
  160. package/src/cli/mcp/auth.ts +5 -5
  161. package/src/cli/mcp/instructions.ts +3 -2
  162. package/src/cli/mcp/legacy-tool-service.ts +0 -189
  163. package/src/cli/mcp/multi-repository.ts +16 -5
  164. package/src/cli/mcp/oauth.ts +175 -26
  165. package/src/cli/mcp/paths.ts +8 -2
  166. package/src/cli/mcp/repository-tools.ts +356 -101
  167. package/src/cli/mcp/server.ts +625 -54
  168. package/src/cli/mcp/tool-capability-cache.ts +1 -1
  169. package/src/cli/mcp/toolset-selection.ts +1 -1
  170. package/src/cli/mcp/toolset.ts +42 -5
  171. package/src/cli/mcp/transports/http.ts +125 -15
  172. package/src/cli/mcp/transports/session-registry.ts +67 -5
  173. package/src/cli/mcp/types.ts +3 -3
  174. package/src/cli/repositories/command-classifier.ts +209 -14
  175. package/src/cli/repositories/command-executor.ts +55 -521
  176. package/src/cli/repositories/command-process.ts +108 -0
  177. package/src/cli/repositories/command-scope.ts +99 -41
  178. package/src/cli/repositories/controller-home.ts +7 -8
  179. package/src/cli/repositories/git-command-executor.ts +2 -0
  180. package/src/cli/repositories/locks.ts +53 -16
  181. package/src/cli/repositories/repository-snapshot.ts +121 -0
  182. package/src/cli/repositories/safe-patch.ts +6 -4
  183. package/src/cli/repositories/selected-path-actions.ts +17 -9
  184. package/src/cli/repositories/structured-git.ts +110 -10
  185. package/src/cli/repository/inspector.ts +565 -62
  186. package/src/cli/repository/session-cache.ts +58 -17
  187. package/src/cli/v81-entry.ts +1 -4
  188. package/src/effects/fs-transaction.ts +85 -17
  189. package/src/runtime/context/codegraph-read-provider.ts +233 -2
  190. package/src/runtime/context/codegraph-sidecar.cjs +74 -40
  191. package/src/runtime/context/generic-lsp-provider.ts +355 -0
  192. package/src/runtime/context/lsp-client.ts +283 -0
  193. package/src/runtime/context/semantic-navigation.ts +275 -0
  194. package/src/runtime/context/swift-navigation.ts +565 -0
  195. package/src/runtime/context/typescript-navigation.ts +226 -0
  196. package/src/runtime/control-plane/dispatch-priority.ts +28 -0
  197. package/src/runtime/control-plane/execution/direct-edit-work-completion.ts +196 -2
  198. package/src/runtime/control-plane/execution/edit-validation-coordinator.ts +86 -24
  199. package/src/runtime/control-plane/execution/execution-identity.ts +65 -14
  200. package/src/runtime/control-plane/execution/session-store.ts +18 -0
  201. package/src/runtime/control-plane/execution/validation.ts +15 -2
  202. package/src/runtime/control-plane/execution/verification-evidence.ts +58 -3
  203. package/src/runtime/control-plane/execution/work-handle-store.ts +27 -2
  204. package/src/runtime/control-plane/execution/work-lifecycle-audit.ts +258 -0
  205. package/src/runtime/control-plane/execution/work-remote-delivery.ts +215 -0
  206. package/src/runtime/control-plane/execution/work-task-receipt.ts +54 -11
  207. package/src/runtime/control-plane/execution/work-terminal-cleanup.ts +175 -8
  208. package/src/runtime/control-plane/execution/work-validation-reconciler.ts +28 -21
  209. package/src/runtime/control-plane/execution/work-verification-snapshot.ts +87 -9
  210. package/src/runtime/control-plane/facade/capability-registry.ts +129 -25
  211. package/src/runtime/control-plane/facade/controller-round-relay.ts +991 -0
  212. package/src/runtime/control-plane/facade/controller-session-store.ts +144 -14
  213. package/src/runtime/control-plane/facade/goal-workloop-access.ts +9 -2
  214. package/src/runtime/control-plane/facade/goal-workloop.ts +885 -105
  215. package/src/runtime/control-plane/facade/index.ts +1 -0
  216. package/src/runtime/control-plane/facade/plan-contract-store.ts +211 -26
  217. package/src/runtime/control-plane/facade/requirement-board.ts +24 -8
  218. package/src/runtime/control-plane/facade/semantic-admission.ts +205 -0
  219. package/src/runtime/control-plane/facade/suggested-actions.ts +5 -1
  220. package/src/runtime/control-plane/facade/types.ts +55 -11
  221. package/src/runtime/control-plane/facade/work-contract-store.ts +204 -73
  222. package/src/runtime/control-plane/generated-cache-retention.ts +271 -0
  223. package/src/runtime/control-plane/global-scheduler/config.ts +44 -0
  224. package/src/runtime/control-plane/global-scheduler/dispatch-capacity.ts +80 -0
  225. package/src/runtime/control-plane/global-scheduler/durable-admission.ts +46 -0
  226. package/src/runtime/control-plane/global-scheduler/maintenance.ts +145 -0
  227. package/src/runtime/control-plane/global-scheduler/projection-refresh.ts +84 -0
  228. package/src/runtime/control-plane/global-scheduler/reconciliation.ts +3 -3
  229. package/src/runtime/control-plane/global-scheduler/scheduler.ts +273 -542
  230. package/src/runtime/control-plane/global-scheduler/source-scan.ts +59 -0
  231. package/src/runtime/control-plane/global-scheduler/state.ts +88 -0
  232. package/src/runtime/control-plane/global-scheduler/worker-attachment.ts +57 -0
  233. package/src/runtime/control-plane/global-scheduler/worker-exit-decision.ts +38 -0
  234. package/src/runtime/control-plane/global-scheduler/worker-exit-reconciler.ts +175 -0
  235. package/src/runtime/control-plane/global-scheduler/worker-launch.ts +111 -0
  236. package/src/runtime/control-plane/global-scheduler/worker-lifecycle-store.ts +64 -0
  237. package/src/runtime/control-plane/global-scheduler/worker-lifecycle.ts +150 -0
  238. package/src/runtime/control-plane/global-scheduler/worker-process.ts +119 -0
  239. package/src/runtime/control-plane/global-scheduler/worker-stderr.ts +60 -0
  240. package/src/runtime/control-plane/launcher/chatgpt-work-binding-store.ts +50 -0
  241. package/src/runtime/control-plane/launcher/chatgpt-work-continuation.ts +642 -51
  242. package/src/runtime/control-plane/launcher/launch-reservation-store.ts +40 -0
  243. package/src/runtime/control-plane/launcher/thin-launcher.ts +194 -10
  244. package/src/runtime/control-plane/persistence/controller-home-migration.ts +487 -0
  245. package/src/runtime/control-plane/persistence/requirement-store.ts +15 -11
  246. package/src/runtime/control-plane/persistence/sqlite-store.ts +33 -2
  247. package/src/runtime/control-plane/release-retention.ts +62 -2
  248. package/src/runtime/control-plane/routing/route-policy.ts +7 -16
  249. package/src/runtime/control-plane/runtime-status-client.ts +0 -2
  250. package/src/runtime/diagnostics/mcp-timing.ts +19 -0
  251. package/src/runtime/diagnostics/mcp-transport-benchmark.ts +129 -0
  252. package/src/runtime/diagnostics/performance.ts +24 -1
  253. package/src/runtime/evidence/event-ledger.ts +1 -1
  254. package/src/runtime/execution/jobs/store.ts +58 -4
  255. package/src/runtime/execution/jobs/types.ts +1 -1
  256. package/src/runtime/execution/managed-workspace.ts +203 -1
  257. package/src/runtime/execution/process-runtime/check-facade.ts +52 -14
  258. package/src/runtime/execution/process-runtime/check-result.ts +63 -2
  259. package/src/runtime/execution/process-runtime/check-scheduling.ts +114 -0
  260. package/src/runtime/execution/process-runtime/command-facade.ts +346 -40
  261. package/src/runtime/execution/process-runtime/gc.ts +98 -12
  262. package/src/runtime/execution/process-runtime/lightweight-managed.ts +1184 -0
  263. package/src/runtime/execution/process-runtime/persisted-check.ts +57 -6
  264. package/src/runtime/execution/process-runtime/resource-claims.ts +97 -8
  265. package/src/runtime/execution/process-runtime/runtime.ts +59 -4
  266. package/src/runtime/execution/process-runtime/store.ts +7 -0
  267. package/src/runtime/execution/process-runtime/types.ts +2 -0
  268. package/src/runtime/execution/thin-harness/async-process.ts +12 -2
  269. package/src/runtime/execution/thin-harness/search-worker.ts +54 -5
  270. package/src/runtime/execution/workers/executor.ts +0 -48
  271. package/src/runtime/gateway/mcp/execution-tools.ts +1219 -126
  272. package/src/runtime/gateway/mcp/process-tools.ts +83 -37
  273. package/src/runtime/gateway/mcp/router.ts +185 -83
  274. package/src/runtime/gateway/mcp/runtime-tool-definitions.ts +546 -0
  275. package/src/runtime/gateway/mcp/runtime-tools.ts +2555 -1616
  276. package/src/runtime/model-clients/deepseek-adapter.ts +0 -32
  277. package/src/runtime/plugins/app-store-connect-adapter.ts +123 -19
  278. package/src/runtime/plugins/browser-adapter.ts +2925 -318
  279. package/src/runtime/plugins/browser-automation-service.ts +10 -0
  280. package/src/runtime/plugins/browser-handoff-host.ts +6 -31
  281. package/src/runtime/plugins/browser-handoff.ts +92 -5
  282. package/src/runtime/plugins/browser-macos-bridge.ts +586 -45
  283. package/src/runtime/plugins/browser-node-bridge.ts +6 -34
  284. package/src/runtime/plugins/browser-provider-registry.ts +109 -0
  285. package/src/runtime/plugins/browser-runtime-contract.ts +152 -0
  286. package/src/runtime/plugins/browser-runtime.ts +183 -0
  287. package/src/runtime/plugins/browser-session-authority.ts +332 -0
  288. package/src/runtime/plugins/capability-authorization-grants.ts +354 -0
  289. package/src/runtime/plugins/desktop-operator-registration.ts +15 -12
  290. package/src/runtime/plugins/external-adapter.ts +324 -3
  291. package/src/runtime/plugins/external-registration.ts +84 -5
  292. package/src/runtime/plugins/external-unix-socket.ts +7 -1
  293. package/src/runtime/plugins/first-party-registry.ts +4 -2
  294. package/src/runtime/plugins/github-adapter.ts +125 -0
  295. package/src/runtime/plugins/gmail-adapter.ts +28 -2
  296. package/src/runtime/plugins/ios/agent-device-provider.ts +1 -1
  297. package/src/runtime/plugins/ios/agent-device-typed-provider.ts +52 -9
  298. package/src/runtime/plugins/ios/remote-xpc-hid.ts +1171 -0
  299. package/src/runtime/plugins/ios-adapter.ts +106 -16
  300. package/src/runtime/plugins/ios-agent-device.ts +234 -64
  301. package/src/runtime/plugins/ios-physical-device.ts +1143 -392
  302. package/src/runtime/plugins/lightweight-action.ts +153 -0
  303. package/src/runtime/plugins/local-system-adapter.ts +125 -8
  304. package/src/runtime/plugins/macos-capability-broker.ts +55 -9
  305. package/src/runtime/plugins/plugin-action-sidecar.ts +59 -0
  306. package/src/runtime/plugins/plugin-management-adapter.ts +181 -0
  307. package/src/runtime/plugins/resend-adapter.ts +1 -1
  308. package/src/runtime/plugins/store.ts +366 -24
  309. package/src/runtime/plugins/types.ts +39 -2
  310. package/src/runtime/plugins/xiaohongshu-publish.ts +515 -0
  311. package/src/runtime/projections/git-status-sampler.ts +16 -16
  312. package/src/runtime/projections/materialized-view.ts +28 -10
  313. package/src/runtime/recovery/actions.ts +0 -10
  314. package/src/runtime/recovery/classifier.ts +0 -9
  315. package/src/runtime/recovery/maintenance-executor.ts +415 -18
  316. package/src/runtime/recovery/probe.ts +0 -1
  317. package/src/runtime/recovery/types.ts +0 -1
  318. package/src/runtime/root/mcp-transport.ts +180 -10
  319. package/src/runtime/root/package-connector-service.ts +186 -8
  320. package/src/runtime/root/package-runtime-release.ts +143 -17
  321. package/src/runtime/root/package-runtime-service.ts +430 -22
  322. package/src/runtime/root/release-manifest.ts +7 -2
  323. package/src/runtime/root/release-materialize.ts +162 -19
  324. package/src/runtime/root/release-store.ts +48 -11
  325. package/src/runtime/root/runtime.ts +23 -5
  326. package/src/runtime/root/service.ts +100 -27
  327. package/src/runtime/root/types.ts +2 -0
  328. package/src/runtime/safe-tooling/index.ts +0 -1
  329. package/src/runtime/safe-tooling/ios-development.ts +321 -63
  330. package/src/runtime/safe-tooling/types.ts +0 -30
  331. package/src/runtime/shared/trusted-executable.ts +62 -0
  332. package/src/runtime/shared/trusted-node-executable.ts +48 -0
  333. package/src/runtime/standalone-recovery/core.ts +702 -94
  334. package/src/runtime/standalone-recovery/entry.ts +99 -23
  335. package/src/runtime/standalone-recovery/installer.ts +19 -3
  336. package/src/runtime/standalone-recovery/service-labels.ts +2 -0
  337. package/src/runtime/standalone-recovery/watchdog-heartbeat.ts +160 -0
  338. package/src/runtime/workflow/schedules/browser-probe.ts +258 -0
  339. package/src/runtime/workflow/schedules/chatgpt-automation-migration.ts +40 -0
  340. package/src/runtime/workflow/schedules/engine.ts +509 -80
  341. package/src/runtime/workflow/schedules/github-issue-watch.ts +158 -0
  342. package/src/runtime/workflow/schedules/settlement.ts +48 -4
  343. package/src/runtime/workflow/schedules/store.ts +131 -10
  344. package/src/runtime/workflow/schedules/types.ts +6 -3
  345. package/src/runtime/workflow/schedules/work-continuation.ts +120 -34
  346. package/src/testing/test-governance.ts +8 -40
  347. package/assets/reference-configs/heartbeat-triage.md +0 -57
  348. package/assets/templates/helpers/harness-trace-grade.sh +0 -150
  349. package/assets/templates/helpers/heartbeat-triage.sh +0 -361
  350. package/assets/templates/helpers/maintenance-triage.sh +0 -167
  351. package/bin/forge-desktop-helper.mjs +0 -204
  352. package/docs/architecture/current/approved-target-architecture.zh-CN.md +0 -1501
  353. package/docs/architecture/current/architecture-invariants.md +0 -331
  354. package/docs/architecture/current/automation-and-schedule-engine.md +0 -453
  355. package/docs/architecture/current/codegraph-context-provider.md +0 -226
  356. package/docs/architecture/current/control-plane-authority-inventory.md +0 -94
  357. package/docs/architecture/current/controller-repository-decoupling.md +0 -148
  358. package/docs/architecture/current/dispatch-and-agent-strategy.md +0 -354
  359. package/docs/architecture/current/entity-model.md +0 -592
  360. package/docs/architecture/current/external-plugin-governance.md +0 -396
  361. package/docs/architecture/current/failure-recovery.md +0 -447
  362. package/docs/architecture/current/governance.md +0 -213
  363. package/docs/architecture/current/human-interaction-plane.md +0 -87
  364. package/docs/architecture/current/implementation-status.md +0 -128
  365. package/docs/architecture/current/job-and-run-lifecycle.md +0 -413
  366. package/docs/architecture/current/legacy-governance.md +0 -58
  367. package/docs/architecture/current/local-workspace-target-grants.md +0 -70
  368. package/docs/architecture/current/migration-roadmap.md +0 -105
  369. package/docs/architecture/current/multi-repository-execution.md +0 -371
  370. package/docs/architecture/current/operations-runbook.md +0 -45
  371. package/docs/architecture/current/peer-supercontroller-runtime.md +0 -32
  372. package/docs/architecture/current/personal-assistant-plugin-baseline.md +0 -206
  373. package/docs/architecture/current/repository-access-modes.md +0 -102
  374. package/docs/architecture/current/route-policy.md +0 -15
  375. package/docs/architecture/current/route-session-concurrency.md +0 -85
  376. package/docs/architecture/current/runtime-architecture-simplification.md +0 -214
  377. package/docs/architecture/current/runtime-directory-map.md +0 -49
  378. package/docs/architecture/current/runtime-health-and-resource-lifecycle.md +0 -85
  379. package/docs/architecture/current/scheduler-and-resource-claims.md +0 -422
  380. package/docs/architecture/current/session-aware-execution-and-authorization.md +0 -77
  381. package/docs/architecture/current/system-overview.md +0 -144
  382. package/docs/architecture/current/target-requirements-traceability.md +0 -202
  383. package/docs/architecture/current/thin-harness-governance-policy.md +0 -32
  384. package/docs/architecture/current/thin-harness-v1.md +0 -311
  385. package/docs/architecture/current/verification-and-release-gates.md +0 -391
  386. package/docs/forge-autonomous-goal-loop.md +0 -9
  387. package/docs/forge-provider-configuration.md +0 -7
  388. package/docs/operations/chatgpt-personal-assistant-runtime.md +0 -83
  389. package/docs/operations/controller-desktop-plugin.md +0 -112
  390. package/docs/operations/gmail-assistant-routines.md +0 -186
  391. package/docs/operations/personal-assistant-operator-guide.md +0 -61
  392. package/docs/operations/provider-configuration.md +0 -31
  393. package/scripts/harness-trace-grade.sh +0 -150
  394. package/scripts/heartbeat-triage.sh +0 -361
  395. package/scripts/maintenance-triage.sh +0 -167
  396. package/src/cli/local-bridge/frontend/src/features/settings/SettingsView.tsx +0 -2
  397. package/src/cli/repositories/goal-registry.ts +0 -239
  398. package/src/runtime/assistant/action-proposals.ts +0 -279
  399. package/src/runtime/assistant/intent.ts +0 -395
  400. package/src/runtime/assistant/model-provider.ts +0 -460
  401. package/src/runtime/assistant/openapi.ts +0 -223
  402. package/src/runtime/assistant/policy.ts +0 -89
  403. package/src/runtime/assistant/readiness.ts +0 -258
  404. package/src/runtime/assistant/routine-runtime.ts +0 -477
  405. package/src/runtime/assistant/schedule-binding.ts +0 -171
  406. package/src/runtime/assistant/standing-grants.ts +0 -375
  407. package/src/runtime/assistant/store.ts +0 -243
  408. package/src/runtime/assistant/types.ts +0 -135
  409. package/src/runtime/control-plane/goal-loop/config-facade.ts +0 -700
  410. package/src/runtime/control-plane/goal-loop/config-store.ts +0 -570
  411. package/src/runtime/control-plane/goal-loop/config-types.ts +0 -213
  412. package/src/runtime/control-plane/goal-loop/executor-router.ts +0 -109
  413. package/src/runtime/control-plane/goal-loop/failure-taxonomy.ts +0 -149
  414. package/src/runtime/control-plane/goal-loop/goal-contract-store.ts +0 -304
  415. package/src/runtime/control-plane/goal-loop/goal-loop-engine.ts +0 -1001
  416. package/src/runtime/control-plane/goal-loop/handoff-packet.ts +0 -160
  417. package/src/runtime/control-plane/goal-loop/index.ts +0 -13
  418. package/src/runtime/control-plane/goal-loop/local-tools.ts +0 -290
  419. package/src/runtime/control-plane/goal-loop/policy-gates.ts +0 -203
  420. package/src/runtime/control-plane/goal-loop/provider-dispatch.ts +0 -93
  421. package/src/runtime/control-plane/goal-loop/provider-registry.ts +0 -545
  422. package/src/runtime/control-plane/goal-loop/types.ts +0 -378
  423. package/src/runtime/control-plane/startup-recovery.ts +0 -198
  424. package/src/runtime/gateway/mcp/resource-policy.ts +0 -186
  425. package/src/runtime/personal-assistant/gmail-triage-manager.ts +0 -231
  426. package/src/runtime/personal-assistant/reporting-runtime.ts +0 -344
  427. package/src/runtime/personal-assistant/triage-runtime.ts +0 -748
  428. package/src/runtime/plugins/desktop-adapter.ts +0 -374
  429. package/src/runtime/safe-tooling/browser-safe.ts +0 -133
  430. package/src/runtime/workflow/findings/store.ts +0 -204
  431. package/src/runtime/workflow/findings/types.ts +0 -58
  432. package/src/runtime/workflow/portfolio/engine.ts +0 -20
  433. package/src/runtime/workflow/portfolio/store.ts +0 -185
  434. 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
+ }