@moretea-labs/forge 1.8.0 → 1.8.1

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 (528) hide show
  1. package/AGENTS.md +70 -7
  2. package/CHANGELOG.md +14 -0
  3. package/CLAUDE.md +17 -2
  4. package/CONTRIBUTING.md +3 -2
  5. package/THIRD_PARTY_NOTICES.md +1 -1
  6. package/adapters/chatgpt/browser-delivery-host.ts +7 -1
  7. package/adapters/chatgpt/browser-delivery-runtime.ts +529 -56
  8. package/adapters/chatgpt/controller-binding-store.ts +101 -22
  9. package/adapters/chatgpt/controller-round-host.ts +15 -25
  10. package/adapters/chatgpt/controller-round-settlement-store.ts +58 -4
  11. package/adapters/chatgpt/provider-delivery.ts +228 -1
  12. package/adapters/chatgpt/work-conversation-binding-store.ts +79 -53
  13. package/adapters/computer/chatgpt-extension-target.ts +463 -0
  14. package/adapters/computer/chatgpt-target-router.ts +103 -0
  15. package/adapters/computer/chrome-extension/background.js +385 -0
  16. package/adapters/computer/chrome-extension/content.js +378 -0
  17. package/adapters/computer/chrome-extension/core.js +24 -0
  18. package/adapters/computer/chrome-extension/manifest.json +30 -0
  19. package/adapters/computer/desktop-operator-discovery.ts +11 -31
  20. package/adapters/computer/interaction-target-authority.ts +142 -18
  21. package/adapters/mcp/auth.ts +0 -1
  22. package/adapters/mcp/instructions.ts +5 -4
  23. package/adapters/mcp/multi-repository.ts +3 -19
  24. package/adapters/mcp/oauth.ts +73 -0
  25. package/adapters/mcp/paths.ts +4 -1
  26. package/adapters/mcp/runtime-gateway/automation-receipt-adapter.ts +87 -0
  27. package/adapters/mcp/runtime-gateway/bounded-result-runtime.ts +62 -0
  28. package/adapters/mcp/runtime-gateway/cognition-settlement.ts +201 -0
  29. package/adapters/mcp/runtime-gateway/context-adapter.ts +411 -73
  30. package/adapters/mcp/runtime-gateway/context-pack-sidecar.ts +91 -0
  31. package/adapters/mcp/runtime-gateway/controller-authority-adapter.ts +20 -5
  32. package/adapters/mcp/runtime-gateway/core-capability-adapter.ts +258 -0
  33. package/adapters/mcp/runtime-gateway/engineering-preconditions.ts +10 -27
  34. package/adapters/mcp/runtime-gateway/engineering-tool-contract.ts +15 -0
  35. package/adapters/mcp/runtime-gateway/execution-tools.ts +8 -42
  36. package/adapters/mcp/runtime-gateway/gateway-execution-adapter.ts +2 -1
  37. package/adapters/mcp/runtime-gateway/plugin-adapter.ts +117 -45
  38. package/adapters/mcp/runtime-gateway/process-tools.ts +190 -22
  39. package/adapters/mcp/runtime-gateway/protected-computer-adapter.ts +16 -4
  40. package/adapters/mcp/runtime-gateway/recovery-adapter.ts +69 -52
  41. package/adapters/mcp/runtime-gateway/repository-compat-adapter.ts +4 -35
  42. package/adapters/mcp/runtime-gateway/result-adapter.ts +10 -4
  43. package/adapters/mcp/runtime-gateway/router.ts +18 -504
  44. package/adapters/mcp/runtime-gateway/routing-policy.ts +499 -0
  45. package/adapters/mcp/runtime-gateway/runtime-observation-adapter.ts +14 -65
  46. package/adapters/mcp/runtime-gateway/runtime-readiness-observation.ts +218 -0
  47. package/adapters/mcp/runtime-gateway/runtime-tool-definitions.ts +113 -173
  48. package/adapters/mcp/runtime-gateway/runtime-tools.ts +15 -5
  49. package/adapters/mcp/runtime-gateway/scheduler-adapter.ts +1 -0
  50. package/adapters/mcp/runtime-gateway/shared-adapter.ts +20 -0
  51. package/adapters/mcp/runtime-gateway/status-inbox-adapter.ts +358 -266
  52. package/adapters/mcp/runtime-gateway/typescript-navigation-sidecar.ts +136 -0
  53. package/adapters/mcp/runtime-gateway/work-adapter.ts +261 -3122
  54. package/adapters/mcp/runtime-gateway/work-controller-operations.ts +257 -0
  55. package/adapters/mcp/runtime-gateway/work-detail-projection.ts +60 -0
  56. package/adapters/mcp/runtime-gateway/work-input-wire-migration.ts +246 -0
  57. package/adapters/mcp/runtime-gateway/work-learning-operations.ts +145 -0
  58. package/adapters/mcp/runtime-gateway/work-list-projection.ts +38 -0
  59. package/adapters/mcp/runtime-gateway/work-plan-operations.ts +382 -0
  60. package/adapters/mcp/runtime-gateway/work-repair-adapter.ts +308 -0
  61. package/adapters/mcp/runtime-gateway/work-requirement-operations.ts +148 -0
  62. package/adapters/mcp/runtime-gateway/work-semantic-operations.ts +263 -0
  63. package/adapters/mcp/runtime-gateway/work-workflow-operations.ts +113 -0
  64. package/adapters/mcp/runtime-gateway/workflow-supervisor-adapter.ts +156 -0
  65. package/adapters/mcp/server.ts +67 -23
  66. package/adapters/mcp/setup.ts +1 -3
  67. package/adapters/mcp/tool-mapping/legacy-tool-service.ts +44 -170
  68. package/adapters/mcp/tool-mapping/post-finalize-work-attribution.ts +4 -9
  69. package/adapters/mcp/tool-mapping/repository-tools.ts +133 -142
  70. package/adapters/mcp/toolset-names.ts +5 -0
  71. package/adapters/mcp/toolset.ts +6 -5
  72. package/adapters/mcp/transports/http-observation.ts +365 -0
  73. package/adapters/mcp/transports/http.ts +154 -677
  74. package/adapters/mcp/transports/oauth-http.ts +322 -0
  75. package/adapters/mcp/transports/session-registry.ts +6 -0
  76. package/adapters/mcp/tunnels/openai-secure-tunnel.ts +89 -5
  77. package/assets/plugin-registry.v1.json +6 -4
  78. package/assets/reference-configs/agentic-development-flow.md +25 -0
  79. package/assets/reference-configs/global-working-rules.md +19 -0
  80. package/assets/skill-version.json +2 -2
  81. package/docs/architecture/CURRENT.md +111 -41
  82. package/docs/architecture/decisions/20260803-release-identity-binding-and-exit-policy.md +14 -5
  83. package/docs/architecture/decisions/20260823-immediate-controller-relay.md +6 -3
  84. package/docs/architecture/decisions/20260907-assistant-learning-loop.md +2 -0
  85. package/docs/architecture/decisions/20260907-controller-round-transition-policy.md +19 -4
  86. package/docs/architecture/decisions/20260916-workflow-supervisor-authority.md +249 -0
  87. package/docs/architecture/decisions/20260917-cognitive-memory-foundation.md +82 -0
  88. package/docs/architecture/decisions/20260918-stable-candidate-release-lifecycle.md +221 -0
  89. package/docs/architecture/decisions/20260919-autonomous-work-liveness.md +62 -0
  90. package/docs/architecture/decisions/20260924-thin-semantic-working-context.md +72 -0
  91. package/docs/architecture/decisions/20261001-supervisor-turn-authority.md +237 -0
  92. package/docs/architecture/decisions/20261005-forge-v3-desktop-client-boundary.md +77 -0
  93. package/docs/architecture/domains/verification.md +1 -0
  94. package/docs/architecture/domains/workflow-engine.md +6 -0
  95. package/docs/architecture/modules/controller-runtime/transport-lifecycle.md +1 -1
  96. package/docs/forge-plugin-management.md +2 -2
  97. package/docs/operations/controller-performance-and-502.md +17 -0
  98. package/docs/operations/controller-reliability-runbook.md +2 -2
  99. package/docs/operations/features.md +1 -1
  100. package/docs/operations/features.zh-CN.md +1 -1
  101. package/docs/operations/homebrew.md +2 -2
  102. package/docs/operations/mcp-tool-exposure.md +2 -0
  103. package/docs/operations/releasing.md +2 -0
  104. package/docs/operations/standalone-disaster-recovery.md +14 -6
  105. package/docs/wiki/Implementation.md +1 -1
  106. package/package.json +25 -14
  107. package/packages/kernel/cognition/api/index.ts +6 -0
  108. package/packages/kernel/cognition/application/activation-service.ts +451 -0
  109. package/packages/kernel/cognition/application/consolidation-service.ts +185 -0
  110. package/packages/kernel/cognition/application/legacy-experience-adapter.ts +38 -0
  111. package/packages/kernel/cognition/application/memory-service.ts +64 -0
  112. package/packages/kernel/cognition/domain/learning.ts +106 -0
  113. package/packages/kernel/cognition/domain/memory.ts +254 -0
  114. package/packages/kernel/controller/api/index.ts +1 -0
  115. package/packages/kernel/controller/application/continuation-service.ts +281 -0
  116. package/packages/kernel/controller/application/controller-round-service.ts +12 -0
  117. package/packages/kernel/controller/domain/controller-round-transition-policy.ts +242 -21
  118. package/packages/kernel/controller/domain/controller-round.ts +4 -1
  119. package/packages/kernel/controller/domain/execution-quality.ts +3 -1
  120. package/packages/kernel/controller/infrastructure/controller-round-store.ts +689 -103
  121. package/packages/kernel/controller/infrastructure/controller-session-store.ts +297 -71
  122. package/packages/kernel/controller/ports/controller-host.ts +2 -0
  123. package/packages/kernel/identity/api/index.ts +10 -0
  124. package/packages/kernel/identity/domain/activity-projection.ts +43 -0
  125. package/packages/kernel/identity/domain/capability-broker.ts +60 -0
  126. package/packages/kernel/identity/domain/grant.ts +72 -0
  127. package/packages/kernel/identity/domain/owned-resource.ts +116 -0
  128. package/packages/kernel/identity/domain/user-request.ts +93 -0
  129. package/packages/kernel/identity/infrastructure/activity-projection-store.ts +77 -0
  130. package/packages/kernel/identity/infrastructure/capability-broker.ts +81 -0
  131. package/packages/kernel/identity/infrastructure/grant-store.ts +284 -0
  132. package/packages/kernel/identity/infrastructure/owned-resource-store.ts +259 -0
  133. package/packages/kernel/identity/infrastructure/user-request-store.ts +182 -0
  134. package/packages/kernel/scheduler/api/index.ts +0 -2
  135. package/packages/kernel/scheduler/application/schedule-service.ts +3 -0
  136. package/packages/kernel/scheduler/application/settlement.ts +0 -15
  137. package/packages/kernel/scheduler/domain/schedule.ts +87 -0
  138. package/packages/kernel/scheduler/infrastructure/schedule-store.ts +153 -133
  139. package/packages/kernel/work/api/index.ts +3 -2
  140. package/packages/kernel/work/application/work-service.ts +17 -42
  141. package/packages/kernel/work/domain/current-task-lineage.ts +104 -0
  142. package/packages/kernel/work/domain/engineering-design.ts +10 -5
  143. package/packages/kernel/work/domain/engineering-profile.ts +8 -12
  144. package/packages/kernel/work/domain/evaluation-promotion-receipt.ts +186 -0
  145. package/packages/kernel/work/domain/execution-concurrency.ts +19 -26
  146. package/packages/kernel/work/domain/execution-snapshot.ts +0 -31
  147. package/packages/kernel/work/domain/implementation-review.ts +14 -331
  148. package/packages/kernel/work/domain/objective-graph.ts +119 -0
  149. package/packages/kernel/work/domain/project-engineering-contract.ts +23 -1
  150. package/packages/kernel/work/domain/repository-completion-receipt.ts +1 -1
  151. package/packages/kernel/work/domain/state-machine.ts +25 -63
  152. package/packages/kernel/work/domain/types.ts +57 -51
  153. package/packages/kernel/work/infrastructure/work-contract-store.ts +819 -728
  154. package/packages/kernel/work/ports/work-contract-store.ts +5 -2
  155. package/packages/plugin-runtime/browser/session-authority.ts +2 -1
  156. package/packages/plugin-runtime/computer/chatgpt-identity.ts +24 -0
  157. package/packages/plugin-runtime/computer/conversation-target.ts +143 -0
  158. package/packages/plugin-runtime/computer/index.ts +2 -0
  159. package/packages/plugin-runtime/computer/target-authority.ts +26 -1
  160. package/packages/plugin-runtime/external/unix-jsonl-transport.ts +142 -18
  161. package/packages/protocols/computer/contract.ts +27 -1
  162. package/scripts/activate-source-baseline.ts +7 -9
  163. package/scripts/canary-controller-semantic-wait.ts +12 -24
  164. package/scripts/check-mcp-compatibility.ts +48 -136
  165. package/scripts/check-runtime-architecture.mjs +622 -217
  166. package/scripts/forge-local-recovery-helper.mjs +93 -15
  167. package/scripts/lib/project-init-lib.sh +3 -0
  168. package/scripts/open-source-audit-allowlist.txt +1 -2
  169. package/scripts/run-bounded-command.mjs +5 -0
  170. package/scripts/run-governed-gate.ts +0 -1
  171. package/scripts/run-mobile-monitor-bridge.ts +0 -1
  172. package/scripts/smoke-control-plane-failure-domain.ts +94 -0
  173. package/scripts/smoke-mcp-http-runtime.ts +5 -0
  174. package/scripts/smoke-runtime-recovery.ts +12 -43
  175. package/scripts/smoke-schedule-engine.ts +23 -15
  176. package/scripts/smoke-unattended-transport-recovery.ts +223 -0
  177. package/scripts/smoke-user-request-continuation-restart.ts +232 -0
  178. package/scripts/smoke-workflow-supervisor-chrome-adapter.ts +92 -0
  179. package/scripts/smoke-workflow-supervisor-process-restart.ts +276 -0
  180. package/scripts/smoke-workflow-supervisor-restart-recovery.ts +150 -0
  181. package/scripts/smoke-workflow-supervisor.ts +103 -0
  182. package/scripts/verify-forge-runtime.sh +2 -1
  183. package/src/cli/agent-jobs/executor-health.ts +11 -34
  184. package/src/cli/agent-jobs/integration.ts +18 -49
  185. package/src/cli/agent-jobs/job-manager.ts +7 -3
  186. package/src/cli/commands/brain-assistant.ts +27 -13
  187. package/src/cli/commands/brain.ts +13 -15
  188. package/src/cli/commands/chatgpt.ts +1 -163
  189. package/src/cli/commands/recovery.ts +135 -121
  190. package/src/cli/commands/runtime.ts +3 -3
  191. package/src/cli/commands/setup-profile.ts +8 -0
  192. package/src/cli/controller/check-runner.ts +13 -2
  193. package/src/cli/controller/completion-backlog.ts +3 -3
  194. package/src/cli/controller/completion-orchestrator.ts +4 -43
  195. package/src/cli/controller/completion-target.ts +3 -72
  196. package/src/cli/controller/context/source-materializer.ts +81 -100
  197. package/src/cli/controller/context-pack.ts +10 -8
  198. package/src/cli/controller/execution-completion.ts +4 -7
  199. package/src/cli/controller/execution-policy.ts +36 -153
  200. package/src/cli/controller/governance.ts +2 -3
  201. package/src/cli/controller/issue-store.ts +4 -99
  202. package/src/cli/controller/launch-agents.ts +59 -18
  203. package/src/cli/controller/operational-plan.ts +24 -51
  204. package/src/cli/controller/runtime-config.ts +5 -1
  205. package/src/cli/controller/stuck-state-migration.ts +2 -3
  206. package/src/cli/controller/systemd-user.ts +39 -1
  207. package/src/cli/editing/edit-session.ts +1 -7
  208. package/src/cli/local-bridge/console-automations.ts +18 -13
  209. package/src/cli/local-bridge/console-view-models.ts +3 -12
  210. package/src/cli/local-bridge/facade-api.ts +64 -191
  211. package/src/cli/local-bridge/server.ts +24 -147
  212. package/src/cli/local-bridge/types.ts +0 -1
  213. package/src/cli/mcp/oauth-client-retirement.ts +74 -0
  214. package/src/cli/repositories/command-executor.ts +29 -23
  215. package/src/cli/repositories/command-scope.ts +35 -16
  216. package/src/cli/repositories/controller-home.ts +48 -0
  217. package/src/cli/repositories/ephemeral-workspace.ts +20 -30
  218. package/src/cli/repositories/git-command-executor.ts +2 -2
  219. package/src/cli/repositories/registry.ts +77 -11
  220. package/src/cli/repositories/structured-git.ts +62 -2
  221. package/src/cli/repository/session-cache.ts +92 -6
  222. package/src/runtime/context/assistant-context.ts +20 -7
  223. package/src/runtime/context/assistant-work-context.ts +89 -27
  224. package/src/runtime/context/automatic-learning.ts +565 -0
  225. package/src/runtime/context/cognitive-attention.ts +173 -0
  226. package/src/runtime/context/cognitive-skill-canary.ts +158 -0
  227. package/src/runtime/context/context-closure.ts +46 -9
  228. package/src/runtime/context/context-pack-process.ts +103 -0
  229. package/src/runtime/context/context-plane.ts +1 -9
  230. package/src/runtime/context/direct-controller-learning.ts +298 -0
  231. package/src/runtime/context/semantic-navigation-contract.ts +9 -0
  232. package/src/runtime/context/semantic-navigation.ts +6 -34
  233. package/src/runtime/context/typescript-navigation-process.ts +145 -0
  234. package/src/runtime/context/typescript-navigation.ts +89 -3
  235. package/src/runtime/control-plane/cleanup-artifact-retention.ts +212 -9
  236. package/src/runtime/control-plane/concurrency/work-execution-concurrency.ts +9 -47
  237. package/src/runtime/control-plane/execution/controller-authority-recovery.ts +34 -4
  238. package/src/runtime/control-plane/execution/edit-validation-coordinator.ts +29 -20
  239. package/src/runtime/control-plane/execution/execution-identity.ts +23 -3
  240. package/src/runtime/control-plane/execution/repository-work-attribution.ts +7 -30
  241. package/src/runtime/control-plane/execution/retained-work-resume.ts +206 -199
  242. package/src/runtime/control-plane/execution/session-store.ts +31 -1
  243. package/src/runtime/control-plane/execution/validation.ts +6 -8
  244. package/src/runtime/control-plane/execution/work-authority-reconciler.ts +13 -42
  245. package/src/runtime/control-plane/execution/work-check-evidence.ts +137 -0
  246. package/src/runtime/control-plane/execution/work-completion-authority.ts +30 -85
  247. package/src/runtime/control-plane/execution/work-delivery-service.ts +497 -0
  248. package/src/runtime/control-plane/execution/work-evidence-policy.ts +12 -50
  249. package/src/runtime/control-plane/execution/work-execution-support.ts +50 -149
  250. package/src/runtime/control-plane/execution/work-handle-authority.ts +188 -109
  251. package/src/runtime/control-plane/execution/work-handle-store.ts +19 -43
  252. package/src/runtime/control-plane/execution/work-head-settlement.ts +53 -20
  253. package/src/runtime/control-plane/execution/work-lifecycle-audit.ts +52 -29
  254. package/src/runtime/control-plane/execution/work-operation-service.ts +43 -27
  255. package/src/runtime/control-plane/execution/work-preparation-service.ts +126 -266
  256. package/src/runtime/control-plane/execution/work-remote-delivery.ts +2 -3
  257. package/src/runtime/control-plane/execution/work-revision-diff.ts +39 -0
  258. package/src/runtime/control-plane/execution/work-terminal-cleanup.ts +173 -186
  259. package/src/runtime/control-plane/execution/work-validation-reconciler.ts +28 -84
  260. package/src/runtime/control-plane/execution/work-verification-service.ts +406 -50
  261. package/src/runtime/control-plane/execution/work-verification-snapshot.ts +5 -1
  262. package/src/runtime/control-plane/facade/capability-registry.ts +362 -37
  263. package/src/runtime/control-plane/facade/check-normalization.ts +3 -9
  264. package/src/runtime/control-plane/facade/codex-delegation.ts +10 -11
  265. package/src/runtime/control-plane/facade/controller-connection.ts +135 -0
  266. package/src/runtime/control-plane/facade/goal-workloop-access.ts +1 -20
  267. package/src/runtime/control-plane/facade/goal-workloop.ts +281 -1753
  268. package/src/runtime/control-plane/facade/handoff-inbox-application.ts +12 -25
  269. package/src/runtime/control-plane/facade/handoff-inbox-store.ts +256 -52
  270. package/src/runtime/control-plane/facade/index.ts +0 -1
  271. package/src/runtime/control-plane/facade/operation-digest.ts +12 -15
  272. package/src/runtime/control-plane/facade/plan-contract-store.ts +451 -991
  273. package/src/runtime/control-plane/facade/policy-gate.ts +0 -23
  274. package/src/runtime/control-plane/facade/repository-work-admission.ts +12 -22
  275. package/src/runtime/control-plane/facade/requirement-authority.ts +102 -199
  276. package/src/runtime/control-plane/facade/requirement-board.ts +3 -3
  277. package/src/runtime/control-plane/facade/rh-work-operation-contract.ts +51 -14
  278. package/src/runtime/control-plane/facade/self-healing-loop.ts +18 -53
  279. package/src/runtime/control-plane/facade/suggested-actions.ts +15 -18
  280. package/src/runtime/control-plane/facade/types.ts +49 -108
  281. package/src/runtime/control-plane/facade/work-continuation.ts +8 -8
  282. package/src/runtime/control-plane/generated-cache-retention.ts +97 -1
  283. package/src/runtime/control-plane/global-scheduler/autonomous-continuation.ts +248 -0
  284. package/src/runtime/control-plane/global-scheduler/durable-admission.ts +1 -1
  285. package/src/runtime/control-plane/global-scheduler/maintenance.ts +239 -112
  286. package/src/runtime/control-plane/global-scheduler/reconciliation.ts +2 -1
  287. package/src/runtime/control-plane/global-scheduler/scheduler.ts +66 -40
  288. package/src/runtime/control-plane/global-scheduler/wake-signal.ts +42 -2
  289. package/src/runtime/control-plane/governance/access-policy.ts +19 -2
  290. package/src/runtime/control-plane/governance/authorization.ts +20 -3
  291. package/src/runtime/control-plane/launcher/chatgpt-round-continuation.ts +63 -300
  292. package/src/runtime/control-plane/launcher/chatgpt-work-continuation.ts +28 -300
  293. package/src/runtime/control-plane/launcher/local-conversation-controller.ts +238 -0
  294. package/src/runtime/control-plane/launcher/provider-mcp-bootstrap.ts +5 -2
  295. package/src/runtime/control-plane/launcher/thin-launcher.ts +96 -240
  296. package/src/runtime/control-plane/persistence/cognition-store.ts +820 -0
  297. package/src/runtime/control-plane/persistence/experience-store.ts +162 -29
  298. package/src/runtime/control-plane/persistence/requirement-store.ts +216 -74
  299. package/src/runtime/control-plane/persistence/sqlite-store.ts +113 -6
  300. package/src/runtime/control-plane/release-retention.ts +135 -47
  301. package/src/runtime/control-plane/repository-namespace-retention.ts +2 -2
  302. package/src/runtime/control-plane/runtime-cleanup.ts +290 -21
  303. package/src/runtime/control-plane/workspace/project-onboarding.ts +80 -0
  304. package/src/runtime/control-plane/workspace/semantic-sync-service.ts +19 -5
  305. package/src/runtime/control-plane/workspace/workspace-store.ts +169 -0
  306. package/src/runtime/diagnostics/incident-repair.ts +313 -146
  307. package/src/runtime/diagnostics/mcp-timing.ts +114 -0
  308. package/src/runtime/evidence/artifact-store.ts +158 -40
  309. package/src/runtime/evidence/evidence-store.ts +112 -8
  310. package/src/runtime/evidence/output-handle-index.ts +225 -0
  311. package/src/runtime/evidence/result-store.ts +158 -44
  312. package/src/runtime/execution/jobs/store.ts +3 -4
  313. package/src/runtime/execution/managed-workspace.ts +57 -0
  314. package/src/runtime/execution/process-runtime/check-facade.ts +1 -1
  315. package/src/runtime/execution/process-runtime/check-result-retention.ts +2 -2
  316. package/src/runtime/execution/process-runtime/check-result.ts +105 -1
  317. package/src/runtime/execution/process-runtime/check-runner-sidecar.ts +18 -8
  318. package/src/runtime/execution/process-runtime/command-facade.ts +79 -27
  319. package/src/runtime/execution/process-runtime/gc.ts +15 -2
  320. package/src/runtime/execution/process-runtime/handle-index.ts +176 -0
  321. package/src/runtime/execution/process-runtime/host-command-lane.ts +139 -0
  322. package/src/runtime/execution/process-runtime/index.ts +3 -0
  323. package/src/runtime/execution/process-runtime/lightweight-managed.ts +251 -72
  324. package/src/runtime/execution/process-runtime/persisted-check.ts +3 -3
  325. package/src/runtime/execution/process-runtime/process-runner-entry.ts +47 -5
  326. package/src/runtime/execution/process-runtime/process-scope.ts +160 -0
  327. package/src/runtime/execution/process-runtime/resource-claims.ts +65 -61
  328. package/src/runtime/execution/process-runtime/runtime.ts +35 -2
  329. package/src/runtime/execution/process-runtime/store.ts +30 -2
  330. package/src/runtime/execution/process-runtime/types.ts +6 -1
  331. package/src/runtime/execution/workers/executor.ts +2 -6
  332. package/src/runtime/platform/service-inventory.ts +130 -0
  333. package/src/runtime/platform/service-manager.ts +8 -0
  334. package/src/runtime/plugins/action-application.ts +85 -28
  335. package/src/runtime/plugins/app-store-connect-adapter.ts +38 -14
  336. package/src/runtime/plugins/browser-adapter.ts +757 -34
  337. package/src/runtime/plugins/browser-automation-service.ts +23 -3
  338. package/src/runtime/plugins/browser-macos-bridge.ts +321 -29
  339. package/src/runtime/plugins/browser-manifest-surface.ts +45 -11
  340. package/src/runtime/plugins/browser-native-session-service.ts +63 -13
  341. package/src/runtime/plugins/browser-registration.ts +16 -0
  342. package/src/runtime/plugins/browser-runtime.ts +14 -1
  343. package/src/runtime/plugins/browser-session-authority.ts +2 -2
  344. package/src/runtime/plugins/browser-session-store.ts +46 -76
  345. package/src/runtime/plugins/capability-authorization-grants.ts +258 -62
  346. package/src/runtime/plugins/computer-chatgpt-browser-adapter-installer.ts +219 -0
  347. package/src/runtime/plugins/computer-chatgpt-macos-target.ts +891 -0
  348. package/src/runtime/plugins/computer-registration.ts +222 -11
  349. package/src/runtime/plugins/desktop-operator-external-policy.ts +36 -4
  350. package/src/runtime/plugins/desktop-operator-registration.ts +12 -4
  351. package/src/runtime/plugins/external-adapter.ts +42 -6
  352. package/src/runtime/plugins/external-registration.ts +21 -1
  353. package/src/runtime/plugins/gmail-adapter.ts +23 -2
  354. package/src/runtime/plugins/google-calendar-adapter.ts +2 -2
  355. package/src/runtime/plugins/google-shared.ts +14 -7
  356. package/src/runtime/plugins/google-tasks-adapter.ts +2 -2
  357. package/src/runtime/plugins/ios-adapter.ts +1 -1
  358. package/src/runtime/plugins/lightweight-action.ts +208 -2
  359. package/src/runtime/plugins/local-system-adapter.ts +12 -2
  360. package/src/runtime/plugins/managed-process-adapter.ts +12 -5
  361. package/src/runtime/plugins/plugin-action-sidecar.ts +17 -13
  362. package/src/runtime/plugins/plugin-management-adapter.ts +1 -1
  363. package/src/runtime/plugins/store.ts +602 -428
  364. package/src/runtime/plugins/types.ts +20 -0
  365. package/src/runtime/plugins/xiaohongshu-publish.ts +16 -0
  366. package/src/runtime/projections/invalidation.ts +7 -3
  367. package/src/runtime/projections/materialized-view.ts +80 -36
  368. package/src/runtime/recovery/actions.ts +3 -3
  369. package/src/runtime/recovery/capability-action-application.ts +46 -45
  370. package/src/runtime/recovery/lifecycle-inventory.ts +29 -29
  371. package/src/runtime/recovery/maintenance-executor.ts +374 -123
  372. package/src/runtime/recovery/store.ts +29 -11
  373. package/src/runtime/release/release-coordinator.ts +296 -0
  374. package/src/runtime/release/release-session.ts +716 -0
  375. package/src/runtime/release/release-state-migration.ts +25 -0
  376. package/src/runtime/resources/leases/store.ts +56 -25
  377. package/src/runtime/root/computer-composition.ts +191 -6
  378. package/src/runtime/root/controller-progression-composition.ts +192 -0
  379. package/src/runtime/root/controller-round-composition.ts +20 -1
  380. package/src/runtime/root/deployment-topology.ts +106 -0
  381. package/src/runtime/root/entry.ts +4 -3
  382. package/src/runtime/root/known-good-recovery.ts +184 -0
  383. package/src/runtime/root/local-bridge.ts +0 -1
  384. package/src/runtime/root/mcp-transport.ts +111 -18
  385. package/src/runtime/root/ownership.ts +261 -9
  386. package/src/runtime/root/package-connector-service.ts +105 -19
  387. package/src/runtime/root/package-runtime-release.ts +117 -18
  388. package/src/runtime/root/package-runtime-service.ts +17 -11
  389. package/src/runtime/root/release-execution-canary.ts +44 -12
  390. package/src/runtime/root/release-loader.ts +90 -8
  391. package/src/runtime/root/release-manifest.ts +80 -6
  392. package/src/runtime/root/release-materialize.ts +372 -28
  393. package/src/runtime/root/release-store.ts +395 -36
  394. package/src/runtime/root/runtime-lane.ts +191 -0
  395. package/src/runtime/root/runtime.ts +159 -27
  396. package/src/runtime/root/scheduled-controller-composition.ts +28 -3
  397. package/src/runtime/root/service-runner.ts +2 -2
  398. package/src/runtime/root/service.ts +36 -33
  399. package/src/runtime/root/status.ts +48 -0
  400. package/src/runtime/root/types.ts +32 -3
  401. package/src/runtime/root/workflow-supervisor-composition.ts +493 -0
  402. package/src/runtime/root/workflow-supervisor-runtime.ts +209 -0
  403. package/src/runtime/root/write-fence.ts +50 -2
  404. package/src/runtime/safe-tooling/google-credential-store.ts +76 -21
  405. package/src/runtime/safe-tooling/google-oauth-broker.ts +25 -7
  406. package/src/runtime/safe-tooling/workspace-auth.ts +1 -1
  407. package/src/runtime/shared/bounded-child-supervisor.ts +9 -1
  408. package/src/runtime/shared/process-environment.ts +20 -9
  409. package/src/runtime/shared/response-budget.ts +1 -3
  410. package/src/runtime/standalone-recovery/controller-home-migration.ts +16 -24
  411. package/src/runtime/standalone-recovery/core.ts +3702 -342
  412. package/src/runtime/standalone-recovery/entry.ts +469 -39
  413. package/src/runtime/standalone-recovery/installer.ts +262 -148
  414. package/src/runtime/standalone-recovery/mcp-server.ts +29 -193
  415. package/src/runtime/standalone-recovery/operation-lock.ts +1 -1
  416. package/src/runtime/standalone-recovery/performance.ts +54 -16
  417. package/src/runtime/standalone-recovery/release.ts +53 -5
  418. package/src/runtime/standalone-recovery/service-labels.ts +5 -2
  419. package/src/runtime/standalone-recovery/watchdog-heartbeat.ts +5 -2
  420. package/src/runtime/workflow/schedules/browser-probe.ts +17 -6
  421. package/src/runtime/workflow/schedules/chatgpt-automation-migration.ts +10 -3
  422. package/src/runtime/workflow/schedules/engine.ts +138 -172
  423. package/src/runtime/workflow/schedules/work-continuation.ts +44 -5
  424. package/src/runtime/workflows/runtime.ts +15 -19
  425. package/src/testing/test-governance.ts +5 -1
  426. package/supervisor/chatgpt-conversation.ts +23 -0
  427. package/supervisor/client.ts +201 -0
  428. package/supervisor/control-plane.ts +868 -0
  429. package/supervisor/entry.ts +15 -0
  430. package/supervisor/forge-validators.ts +80 -0
  431. package/supervisor/index.ts +5 -0
  432. package/supervisor/native-browser-adapter.ts +786 -0
  433. package/supervisor/native-messaging/host.ts +39 -0
  434. package/supervisor/native-messaging/manifest.ts +26 -0
  435. package/supervisor/native-messaging/protocol.ts +27 -0
  436. package/supervisor/paths.ts +18 -0
  437. package/supervisor/protocol.ts +202 -0
  438. package/supervisor/server.ts +404 -0
  439. package/supervisor/store.ts +1451 -0
  440. package/supervisor/tsconfig.json +8 -0
  441. package/supervisor/types.ts +255 -0
  442. package/adapters/chatgpt/controller-host.ts +0 -119
  443. package/adapters/mcp/controller-round-compatibility.ts +0 -184
  444. package/adapters/mcp/frozen-client-semantic-compatibility.ts +0 -292
  445. package/adapters/mcp/runtime-gateway/work-compat-adapter.ts +0 -502
  446. package/packages/kernel/progression/api/index.ts +0 -2
  447. package/packages/kernel/progression/application/projector.ts +0 -211
  448. package/packages/kernel/progression/domain/types.ts +0 -116
  449. package/packages/kernel/progression/index.ts +0 -1
  450. package/packages/kernel/scheduler/application/continuation-service.ts +0 -212
  451. package/packages/kernel/scheduler/domain/continuation.ts +0 -38
  452. package/packages/kernel/scheduler/infrastructure/continuation-dispatch-store.ts +0 -38
  453. package/packages/kernel/work/domain/admission-policy.ts +0 -34
  454. package/scripts/benchmark-background-check-overlap.ts +0 -228
  455. package/scripts/benchmark-computer-hotpath.ts +0 -255
  456. package/scripts/benchmark-controller-hotpath.ts +0 -212
  457. package/scripts/benchmark-controller-round2.ts +0 -191
  458. package/scripts/benchmark-ios-agent-device.ts +0 -511
  459. package/scripts/benchmark-mcp-host.sh +0 -117
  460. package/scripts/benchmark-mcp-transport.ts +0 -169
  461. package/scripts/benchmark-operational-memory-activation.ts +0 -235
  462. package/scripts/benchmark-operational-shadow.ts +0 -28
  463. package/scripts/benchmark-quality-harness.ts +0 -146
  464. package/scripts/benchmark-route-session-concurrency.ts +0 -915
  465. package/scripts/benchmark-thin-harness-gateway-ab.ts +0 -632
  466. package/scripts/benchmark-thin-harness-mcp-e2e.ts +0 -498
  467. package/scripts/benchmark-thin-harness.ts +0 -251
  468. package/scripts/benchmark-typescript-navigation.ts +0 -186
  469. package/scripts/benchmark-work-efficiency.ts +0 -334
  470. package/scripts/build-controller-ui.ts +0 -28
  471. package/scripts/check-npm-release.sh +0 -32
  472. package/scripts/check-public-release-surface.sh +0 -19
  473. package/scripts/check-release-published.sh +0 -57
  474. package/scripts/check-release-readiness.sh +0 -37
  475. package/scripts/check-release-version.mjs +0 -74
  476. package/scripts/check-tarball-install-smoke.sh +0 -150
  477. package/scripts/package-source-archive.sh +0 -147
  478. package/scripts/public-release-files.txt +0 -39
  479. package/scripts/public-release.ts +0 -174
  480. package/scripts/publish-release-tarball.sh +0 -27
  481. package/scripts/route-nl-vs-ts-eval.ts +0 -679
  482. package/scripts/stage-runtime-release.ts +0 -44
  483. package/src/cli/controller/progress.ts +0 -656
  484. package/src/cli/controller/work-mode.ts +0 -181
  485. package/src/cli/local-bridge/console-assets.ts +0 -17
  486. package/src/cli/local-bridge/dashboard.ts +0 -17
  487. package/src/cli/local-bridge/frontend/src/App.tsx +0 -10
  488. package/src/cli/local-bridge/frontend/src/components/Button.tsx +0 -1
  489. package/src/cli/local-bridge/frontend/src/components/DetailPane.tsx +0 -3
  490. package/src/cli/local-bridge/frontend/src/components/SearchField.tsx +0 -1
  491. package/src/cli/local-bridge/frontend/src/components/SectionHeader.tsx +0 -1
  492. package/src/cli/local-bridge/frontend/src/components/Segmented.tsx +0 -1
  493. package/src/cli/local-bridge/frontend/src/components/StatusText.tsx +0 -3
  494. package/src/cli/local-bridge/frontend/src/design/icons.tsx +0 -11
  495. package/src/cli/local-bridge/frontend/src/design/tokens.css +0 -8
  496. package/src/cli/local-bridge/frontend/src/features/automations/AutomationsView.tsx +0 -153
  497. package/src/cli/local-bridge/frontend/src/features/capabilities/CapabilitiesView.tsx +0 -37
  498. package/src/cli/local-bridge/frontend/src/features/overview/OverviewView.tsx +0 -183
  499. package/src/cli/local-bridge/frontend/src/features/repositories/RepositoriesView.tsx +0 -2
  500. package/src/cli/local-bridge/frontend/src/features/system/SystemView.tsx +0 -2
  501. package/src/cli/local-bridge/frontend/src/features/work/WorkView.tsx +0 -4
  502. package/src/cli/local-bridge/frontend/src/lib/api.ts +0 -30
  503. package/src/cli/local-bridge/frontend/src/lib/format.ts +0 -4
  504. package/src/cli/local-bridge/frontend/src/lib/routes.ts +0 -7
  505. package/src/cli/local-bridge/frontend/src/main.tsx +0 -1
  506. package/src/cli/local-bridge/frontend/src/shell/AppShell.tsx +0 -1
  507. package/src/cli/local-bridge/frontend/src/shell/CommandBar.tsx +0 -2
  508. package/src/cli/local-bridge/frontend/src/shell/Sidebar.tsx +0 -4
  509. package/src/cli/local-bridge/frontend/src/styles.css +0 -28
  510. package/src/cli/local-bridge/frontend/src/types.ts +0 -15
  511. package/src/cli/local-bridge/frontend/src/vite-env.d.ts +0 -1
  512. package/src/cli/local-bridge/frontend/vite.config.ts +0 -27
  513. package/src/cli/local-bridge/ui-dist/app.css +0 -1
  514. package/src/cli/local-bridge/ui-dist/app.js +0 -11228
  515. package/src/runtime/control-plane/execution/content-equivalent-commit-authority.ts +0 -169
  516. package/src/runtime/control-plane/execution/direct-canonical-work-reconciliation.ts +0 -85
  517. package/src/runtime/control-plane/execution/direct-edit-work-completion.ts +0 -655
  518. package/src/runtime/control-plane/execution/work-finalization-service.ts +0 -2850
  519. package/src/runtime/control-plane/execution/work-path-scope.ts +0 -37
  520. package/src/runtime/control-plane/execution/work-task-receipt.ts +0 -468
  521. package/src/runtime/control-plane/facade/controller-round-relay.ts +0 -3
  522. package/src/runtime/control-plane/facade/work-admission-policy.ts +0 -142
  523. package/src/runtime/control-plane/facade/work-implementation-review.ts +0 -2
  524. package/src/runtime/control-plane/facade/work-state-machine.ts +0 -2
  525. package/src/runtime/control-plane/facade/work-task-projection.ts +0 -66
  526. package/src/runtime/control-plane/routing/index.ts +0 -1
  527. package/src/runtime/control-plane/routing/route-policy.ts +0 -401
  528. package/src/runtime/control-plane/routing/workspace-admission.ts +0 -70
@@ -5,20 +5,40 @@ import type {
5
5
  ComputerCaptureRegion,
6
6
  ComputerTrustedInput,
7
7
  } from '../../../packages/protocols/computer/index';
8
- import { executeRuntimeComputerBrowserAutomation } from '../root/computer-composition';
8
+ import { executeRuntimeComputerBrowserAutomation, executeRuntimeComputerBrowserTrustedInput } from '../root/computer-composition';
9
9
  import { AssistantPluginError } from './errors';
10
10
 
11
11
  export type BrowserAutomationProduct = ComputerBrowserProduct;
12
12
  export type BrowserAutomationTabRef = ComputerBrowserTabRef;
13
13
  export type BrowserAutomationRegion = ComputerCaptureRegion;
14
14
  export type BrowserAutomationTrustedInput = ComputerTrustedInput;
15
- export type BrowserAutomationBrokerAction = ComputerBrowserAutomationRequest;
15
+ export interface BrowserAutomationSemanticTargetProof {
16
+ domRole: string;
17
+ accessibleName: string;
18
+ editable: true;
19
+ focused: true;
20
+ multiline: boolean;
21
+ }
22
+ export type BrowserAutomationTrustedInputRequest = Extract<ComputerBrowserAutomationRequest, { action: 'trusted_input' }> & {
23
+ /** Ephemeral Browser-owned proof; never persisted or forwarded to compatibility providers. */
24
+ semanticTarget?: BrowserAutomationSemanticTargetProof;
25
+ };
26
+ export type BrowserAutomationBrokerAction =
27
+ | Exclude<ComputerBrowserAutomationRequest, { action: 'trusted_input' }>
28
+ | BrowserAutomationTrustedInputRequest;
16
29
 
17
30
  export async function callBrowserAutomationBroker(
18
31
  request: BrowserAutomationBrokerAction,
19
32
  timeoutMs: number,
20
33
  ): Promise<Record<string, unknown>> {
21
- return await executeRuntimeComputerBrowserAutomation(request, timeoutMs);
34
+ if (request.action === 'trusted_input'
35
+ && (request.input.kind === 'key' || (request.input.kind === 'text' && request.semanticTarget))) {
36
+ return await executeRuntimeComputerBrowserTrustedInput(request, timeoutMs);
37
+ }
38
+ // Generic trusted text remains on the explicit Browser compatibility contract.
39
+ // Only Browser-owned semantic proof authorizes the Unified Computer text path.
40
+ const { semanticTarget: _semanticTarget, ...compatibilityRequest } = request as BrowserAutomationTrustedInputRequest;
41
+ return await executeRuntimeComputerBrowserAutomation(compatibilityRequest as ComputerBrowserAutomationRequest, timeoutMs);
22
42
  }
23
43
 
24
44
  export async function captureBrowserAutomationRegion(region: BrowserAutomationRegion, timeoutMs: number): Promise<Buffer> {
@@ -6,7 +6,9 @@ import {
6
6
  callBrowserAutomationBroker,
7
7
  captureBrowserAutomationRegion,
8
8
  type BrowserAutomationBrokerAction,
9
+ type BrowserAutomationSemanticTargetProof,
9
10
  type BrowserAutomationTrustedInput,
11
+ type BrowserAutomationTrustedInputRequest,
10
12
  } from './browser-automation-service';
11
13
  import { AssistantPluginError } from './errors';
12
14
  import type { BrowserNativeAttachAttempt, BrowserNativeProduct } from '../../../packages/protocols/browser/index';
@@ -64,6 +66,8 @@ export interface MacOsBrowserTabInventoryEntry {
64
66
  url: string;
65
67
  title: string;
66
68
  active: boolean;
69
+ /** True when this tab is active in the frontmost browser window. */
70
+ frontmost?: boolean;
67
71
  }
68
72
 
69
73
  export interface MacOsBrowserTabInventory {
@@ -119,7 +123,7 @@ function execFileText(file: string, args: string[], timeoutMs: number): Promise<
119
123
  }, (error, stdout, stderr) => {
120
124
  if (error) {
121
125
  const diagnostic = String(stderr || error.message).trim().slice(-2_000);
122
- reject(new Error(diagnostic || error.message));
126
+ reject(new Error(diagnostic || error.message, { cause: error }));
123
127
  return;
124
128
  }
125
129
  resolve(String(stdout).trim());
@@ -134,8 +138,12 @@ const defaultRuntimeHooks: MacOsBrowserRuntimeHooks = {
134
138
  try {
135
139
  await execFileText('/usr/bin/pgrep', ['-x', processName], timeoutMs);
136
140
  return true;
137
- } catch {
138
- return false;
141
+ } catch (error) {
142
+ // pgrep's no-match exit is absence; timeout/permission/transport failure
143
+ // cannot prove that an application's tabs are absent.
144
+ const cause = error instanceof Error ? error.cause : undefined;
145
+ if (cause && typeof cause === 'object' && 'code' in cause && cause.code === 1) return false;
146
+ throw error;
139
147
  }
140
148
  },
141
149
  };
@@ -227,6 +235,12 @@ async function runBrowserAutomationText(
227
235
  testArgs: string[],
228
236
  timeoutMs: number,
229
237
  ): Promise<string> {
238
+ // AppleScript `tell application` starts an application that is not already
239
+ // running while it compiles the script. Every browser entry point therefore
240
+ // fails closed unless the exact browser process is already live, so routine
241
+ // inventory/reconcile work can never launch the user's browser or hand Forge
242
+ // an unauthenticated profile.
243
+ if ('product' in request) await assertMacOsBrowserApplicationRunning(request.product, timeoutMs);
230
244
  if (runtimeHooks.runAppleScript) return await runtimeHooks.runAppleScript(testScript, testArgs, timeoutMs);
231
245
  const result = await callBrowserAutomationBroker(request, timeoutMs);
232
246
  if (typeof result.value !== 'string') {
@@ -239,6 +253,76 @@ async function runBrowserAutomationText(
239
253
  return result.value;
240
254
  }
241
255
 
256
+ /**
257
+ * Non-launching precondition for every Apple Events browser operation.
258
+ * Path existence is checked without scripting the application, and process
259
+ * liveness comes from the process table, so neither probe can start a browser.
260
+ */
261
+ export async function assertMacOsBrowserApplicationRunning(
262
+ product: MacOsBrowserProduct,
263
+ timeoutMs = DEFAULT_NATIVE_TIMEOUT_MS,
264
+ ): Promise<void> {
265
+ const browser = browserDefinition(product);
266
+ const details = { browserProduct: product, bundleId: browser.bundleId, appName: browser.appName };
267
+ if (runtimeHooks.platform !== 'darwin') {
268
+ throw new AssistantPluginError(
269
+ 'PLUGIN_BROWSER_NATIVE_APP_UNSUPPORTED_PLATFORM',
270
+ `Native ${browser.appName} Apple Events are unavailable on ${runtimeHooks.platform}.`,
271
+ { retryable: false, details },
272
+ );
273
+ }
274
+ if (!browser.appPaths.some((path) => runtimeHooks.appExists(path))) {
275
+ throw new AssistantPluginError(
276
+ 'PLUGIN_BROWSER_NATIVE_APP_NOT_INSTALLED',
277
+ `${browser.appName} is not installed; Forge never installs or substitutes a browser application.`,
278
+ { retryable: false, details },
279
+ );
280
+ }
281
+ if (!(await runtimeHooks.processRunning(browser.processName, timeoutMs))) {
282
+ throw new AssistantPluginError(
283
+ 'PLUGIN_BROWSER_NATIVE_APP_NOT_RUNNING',
284
+ `${browser.appName} is not running; Forge never launches a browser application implicitly.`,
285
+ { retryable: true, details },
286
+ );
287
+ }
288
+ }
289
+
290
+ /**
291
+ * Start only the browser family already chosen by the Computer target. This
292
+ * is deliberately narrower than a generic browser launch: it never guesses a
293
+ * product, profile, or authentication identity. The caller must have a
294
+ * durable preferred product and must still verify the resulting ChatGPT page
295
+ * before any provider mutation.
296
+ */
297
+ export async function ensureMacOsBrowserApplicationRunning(
298
+ product: MacOsBrowserProduct,
299
+ timeoutMs = DEFAULT_NATIVE_TIMEOUT_MS,
300
+ ): Promise<void> {
301
+ const browser = browserDefinition(product);
302
+ if (runtimeHooks.platform !== 'darwin') throw new AssistantPluginError(
303
+ 'PLUGIN_BROWSER_NATIVE_APP_UNSUPPORTED_PLATFORM',
304
+ `Native ${browser.appName} Apple Events are unavailable on ${runtimeHooks.platform}.`,
305
+ { retryable: false, details: { browserProduct: product } },
306
+ );
307
+ if (!browser.appPaths.some((path) => runtimeHooks.appExists(path))) throw new AssistantPluginError(
308
+ 'PLUGIN_BROWSER_NATIVE_APP_NOT_INSTALLED',
309
+ `${browser.appName} is not installed.`,
310
+ { retryable: false, details: { browserProduct: product } },
311
+ );
312
+ if (await runtimeHooks.processRunning(browser.processName, timeoutMs)) return;
313
+ await execFileText('/usr/bin/open', ['-a', browser.appName], timeoutMs);
314
+ const deadline = Date.now() + Math.max(1_000, timeoutMs);
315
+ while (Date.now() < deadline) {
316
+ if (await runtimeHooks.processRunning(browser.processName, Math.min(1_000, timeoutMs))) return;
317
+ await new Promise((resolve) => setTimeout(resolve, 100));
318
+ }
319
+ throw new AssistantPluginError(
320
+ 'PLUGIN_BROWSER_NATIVE_APP_START_TIMEOUT',
321
+ `${browser.appName} did not become available after Forge started the remembered browser family.`,
322
+ { retryable: true, details: { browserProduct: product } },
323
+ );
324
+ }
325
+
242
326
  async function captureBrowserAutomation(
243
327
  region: { x: number; y: number; width: number; height: number },
244
328
  path: string,
@@ -251,7 +335,7 @@ async function captureBrowserAutomation(
251
335
  }
252
336
 
253
337
  async function sendBrowserTrustedInput(
254
- request: Extract<BrowserAutomationBrokerAction, { action: 'trusted_input' }>,
338
+ request: BrowserAutomationTrustedInputRequest,
255
339
  timeoutMs: number,
256
340
  ): Promise<void> {
257
341
  if (runtimeHooks.trustedInput) {
@@ -405,6 +489,8 @@ set maxTabs to 256
405
489
  set returnedCount to 0
406
490
  set truncatedInventory to false
407
491
  set outputText to "false"
492
+ set frontWindowId to ""
493
+ if (count of windows) is greater than 0 then set frontWindowId to ((id of front window) as text)
408
494
  repeat with candidateWindow in windows
409
495
  set activeTabId to ""
410
496
  try
@@ -417,10 +503,11 @@ repeat with candidateWindow in windows
417
503
  end if
418
504
  set candidateWindowId to ((id of candidateWindow) as text)
419
505
  set candidateTabId to ((id of candidateTab) as text)
506
+ set candidateFrontmost to (candidateWindowId is frontWindowId)
420
507
  set candidateURL to my cleanField((URL of candidateTab as text), recordSeparator, fieldSeparator)
421
508
  set candidateTitle to my cleanField((title of candidateTab as text), recordSeparator, fieldSeparator)
422
509
  set candidateActive to (candidateTabId is activeTabId)
423
- set outputText to outputText & recordSeparator & candidateWindowId & fieldSeparator & candidateTabId & fieldSeparator & (candidateActive as text) & fieldSeparator & candidateURL & fieldSeparator & candidateTitle
510
+ set outputText to outputText & recordSeparator & candidateWindowId & fieldSeparator & candidateTabId & fieldSeparator & (candidateActive as text) & fieldSeparator & (candidateFrontmost as text) & fieldSeparator & candidateURL & fieldSeparator & candidateTitle
424
511
  set returnedCount to returnedCount + 1
425
512
  end repeat
426
513
  if truncatedInventory then exit repeat
@@ -458,14 +545,23 @@ function parseTabInventory(product: MacOsBrowserProduct, raw: string): MacOsBrow
458
545
  const windowId = (fields[0] ?? '').trim();
459
546
  const tabId = (fields[1] ?? '').trim();
460
547
  const activeText = (fields[2] ?? '').trim().toLowerCase();
461
- if (!windowId || !tabId || (activeText !== 'true' && activeText !== 'false')) {
548
+ const hasFrontmostField = fields.length >= 6 && ['true', 'false'].includes((fields[3] ?? '').trim().toLowerCase());
549
+ const frontmostText = hasFrontmostField ? (fields[3] ?? '').trim().toLowerCase() : undefined;
550
+ if (!windowId || !tabId || (activeText !== 'true' && activeText !== 'false') || (fields.length >= 6 && !hasFrontmostField)) {
462
551
  throw new AssistantPluginError(
463
552
  'PLUGIN_MACOS_CAPABILITY_BROKER_PROTOCOL_ERROR',
464
553
  'Stable Forge macOS capability broker returned invalid browser tab inventory metadata.',
465
554
  { retryable: true },
466
555
  );
467
556
  }
468
- tabs.push({ windowId, tabId, active: activeText === 'true', url: fields[3] ?? '', title: fields.slice(4).join(fieldSeparator) });
557
+ tabs.push({
558
+ windowId,
559
+ tabId,
560
+ active: activeText === 'true',
561
+ ...(frontmostText ? { frontmost: frontmostText === 'true' } : {}),
562
+ url: fields[hasFrontmostField ? 4 : 3] ?? '',
563
+ title: fields.slice(hasFrontmostField ? 5 : 4).join(fieldSeparator),
564
+ });
469
565
  if (tabs.length > 256) {
470
566
  throw new AssistantPluginError(
471
567
  'PLUGIN_MACOS_CAPABILITY_BROKER_PROTOCOL_ERROR',
@@ -507,30 +603,76 @@ return (frontmost as text) & separator & (URL of targetTab as text) & separator
507
603
  function activateTargetTabScript(browser: MacOsBrowserDefinition, ref: MacOsBrowserTabRef): string {
508
604
  return browserTellScript(browser, `
509
605
  ${targetTabPreamble(ref)}
510
- set targetTabIndex to 1
511
- repeat with candidateTab in tabs of targetWindow
512
- if ((id of candidateTab) as text) is ((id of targetTab) as text) then exit repeat
513
- set targetTabIndex to targetTabIndex + 1
606
+ -- Activating by position is only safe inside the same enumeration that produced
607
+ -- the index. A tab created or closed by the provider between those two steps
608
+ -- makes the positional write fail with -1719 ("Can't get item N of every tab"),
609
+ -- so each attempt re-reads the tab list, bounds the index and verifies the exact
610
+ -- tab became active before it is reported as done.
611
+ set targetTabIdText to ((id of targetTab) as text)
612
+ set activationConfirmed to false
613
+ repeat 3 times
614
+ set targetTabIndex to 0
615
+ set candidateIndex to 0
616
+ repeat with candidateTab in tabs of targetWindow
617
+ set candidateIndex to candidateIndex + 1
618
+ if ((id of candidateTab) as text) is targetTabIdText then set targetTabIndex to candidateIndex
619
+ end repeat
620
+ if targetTabIndex is greater than 0 then
621
+ try
622
+ if targetTabIndex is less than or equal to (count of tabs of targetWindow) then
623
+ set active tab index of targetWindow to targetTabIndex
624
+ if ((id of active tab of targetWindow) as text) is targetTabIdText then set activationConfirmed to true
625
+ end if
626
+ end try
627
+ end if
628
+ if activationConfirmed then exit repeat
629
+ delay 0.05
514
630
  end repeat
515
- set active tab index of targetWindow to targetTabIndex
516
631
  set index of targetWindow to 1
517
632
  activate
518
633
  `);
519
634
  }
520
635
 
521
- function createOwnedTabScript(browser: MacOsBrowserDefinition): string {
636
+ function createOwnedTabScript(browser: MacOsBrowserDefinition, preferredWindowId?: string): string {
522
637
  return `on run argv
523
638
  set targetUrl to item 1 of argv
524
639
  ${browserTellScript(browser, `
525
- if (count of windows) is 0 then
640
+ set preferredWindowId to "${preferredWindowId ?? ''}"
641
+ set targetWindow to missing value
642
+ if preferredWindowId is not "" then
643
+ repeat with candidateWindow in windows
644
+ if ((id of candidateWindow) as text) is preferredWindowId then
645
+ set targetWindow to candidateWindow
646
+ exit repeat
647
+ end if
648
+ end repeat
649
+ end if
650
+ if targetWindow is missing value and (count of windows) is greater than 0 then set targetWindow to front window
651
+ if targetWindow is missing value then
526
652
  set targetWindow to make new window
527
653
  set targetTab to active tab of targetWindow
528
654
  set URL of targetTab to targetUrl
529
655
  else
530
656
  set targetWindow to front window
531
- set originalActiveIndex to active tab index of targetWindow
657
+ set originalActiveTabId to ((id of active tab of targetWindow) as text)
532
658
  set targetTab to make new tab at end of tabs of targetWindow with properties {URL:targetUrl}
533
- set active tab index of targetWindow to originalActiveIndex
659
+ -- Restore the previously active tab by identity, never by a stale position:
660
+ -- the new tab can shift Chrome's tab order and make a pre-create index invalid.
661
+ repeat 3 times
662
+ if ((id of active tab of targetWindow) as text) is originalActiveTabId then exit repeat
663
+ set restoreIndex to 0
664
+ set candidateIndex to 0
665
+ repeat with candidateTab in tabs of targetWindow
666
+ set candidateIndex to candidateIndex + 1
667
+ if ((id of candidateTab) as text) is originalActiveTabId then set restoreIndex to candidateIndex
668
+ end repeat
669
+ if restoreIndex is 0 then exit repeat
670
+ try
671
+ if restoreIndex is less than or equal to (count of tabs of targetWindow) then set active tab index of targetWindow to restoreIndex
672
+ end try
673
+ if ((id of active tab of targetWindow) as text) is originalActiveTabId then exit repeat
674
+ delay 0.05
675
+ end repeat
534
676
  end if
535
677
  set targetTabId to id of targetTab
536
678
  set separator to ASCII character 30
@@ -804,7 +946,11 @@ export class MacOsAppleEventsPage {
804
946
  return await runBrowserAutomationText(effectiveRequest, effectiveScript, args, timeoutMs);
805
947
  } catch (error) {
806
948
  const message = error instanceof Error ? error.message : String(error);
807
- throw new AssistantPluginError('PLUGIN_BROWSER_NATIVE_OPERATION_FAILED', `${this.browser.appName} Apple Events operation failed: ${message}`, {
949
+ // Keep the broker's bounded timeout/serialization identity visible to
950
+ // the sole Supervisor retry policy. Flattening both to the generic
951
+ // operation error makes a blocked tab hot-loop against the global lane.
952
+ const brokerFailure = /\b(BROWSER_AUTOMATION_TIMEOUT|BROWSER_AUTOMATION_SERIALIZATION_BUSY)\b/.exec(message)?.[1];
953
+ throw new AssistantPluginError(brokerFailure ?? 'PLUGIN_BROWSER_NATIVE_OPERATION_FAILED', `${this.browser.appName} Apple Events operation failed: ${message}`, {
808
954
  retryable: true,
809
955
  details: { browserProduct: this.browser.product, bundleId: this.browser.bundleId },
810
956
  });
@@ -1123,6 +1269,57 @@ export class MacOsAppleEventsPage {
1123
1269
  await this.refreshMetadata();
1124
1270
  }
1125
1271
 
1272
+ /**
1273
+ * Supervisor-only semantic text boundary. Browser owns exact tab + DOM focus;
1274
+ * Computer receives only a one-shot semantic target proof and remains the OS
1275
+ * mutation transport. Generic Browser trusted text keeps its compatibility
1276
+ * semantics and does not implicitly become ChatGPT-specific.
1277
+ */
1278
+ async trustedSemanticTextInput(text: string): Promise<void> {
1279
+ if (!this.targetRef) {
1280
+ throw new AssistantPluginError('PLUGIN_BROWSER_TRUSTED_INPUT_UNAVAILABLE', 'Semantic trusted text requires an exact saved browser tab.', { retryable: false });
1281
+ }
1282
+ this.targetRef = await resolveCurrentMacOsBrowserTabRef(this.browser.product, this.targetRef, this.timeoutMs);
1283
+ const metadata = await readResolvedMacOsBrowserOwnedTabMetadata(this.browser.product, this.targetRef, this.timeoutMs);
1284
+ if (!metadata.frontmost || metadata.active !== true) {
1285
+ throw new AssistantPluginError(
1286
+ 'PLUGIN_BROWSER_FOREGROUND_REQUIRED',
1287
+ 'Semantic trusted text requires the exact saved browser tab to be frontmost and active.',
1288
+ { retryable: true, details: { browserProduct: this.browser.product, windowId: this.targetRef.windowId, tabId: this.targetRef.tabId } },
1289
+ );
1290
+ }
1291
+ const semanticTarget = await this.evaluate<BrowserAutomationSemanticTargetProof & { valid?: boolean }>(`(() => {
1292
+ const element = document.activeElement;
1293
+ if (!(element instanceof HTMLElement)) return { valid: false };
1294
+ const tag = element.tagName.toLowerCase();
1295
+ const inputType = element instanceof HTMLInputElement ? String(element.type || 'text').toLowerCase() : '';
1296
+ const textInput = element instanceof HTMLTextAreaElement
1297
+ || element.isContentEditable
1298
+ || (element instanceof HTMLInputElement && !['button','checkbox','color','file','hidden','image','radio','range','reset','submit'].includes(inputType));
1299
+ const accessibleName = String(element.getAttribute('aria-label') || element.getAttribute('placeholder') || element.getAttribute('title') || element.getAttribute('name') || '').trim();
1300
+ const domRole = String(element.getAttribute('role') || (textInput ? 'textbox' : '')).trim();
1301
+ const multiline = element instanceof HTMLTextAreaElement || element.isContentEditable || element.getAttribute('aria-multiline') === 'true';
1302
+ return { valid: textInput && document.activeElement === element && Boolean(domRole) && Boolean(accessibleName), domRole, accessibleName, editable: true, focused: true, multiline };
1303
+ })()`);
1304
+ if (semanticTarget.valid !== true || semanticTarget.editable !== true || semanticTarget.focused !== true
1305
+ || !semanticTarget.domRole || !semanticTarget.accessibleName) {
1306
+ throw new AssistantPluginError(
1307
+ 'PLUGIN_BROWSER_TRUSTED_INPUT_SEMANTIC_TARGET_UNPROVEN',
1308
+ 'Browser could not prove one focused editable DOM target with an accessible identity before trusted text mutation.',
1309
+ { retryable: true, details: { browserProduct: this.browser.product, windowId: this.targetRef.windowId, tabId: this.targetRef.tabId } },
1310
+ );
1311
+ }
1312
+ const { valid: _valid, ...proof } = semanticTarget;
1313
+ await sendBrowserTrustedInput({
1314
+ action: 'trusted_input',
1315
+ product: this.browser.product,
1316
+ ref: this.targetRef,
1317
+ input: { kind: 'text', text },
1318
+ semanticTarget: proof,
1319
+ }, this.timeoutMs);
1320
+ await this.refreshMetadata();
1321
+ }
1322
+
1126
1323
  async screenshot(options: Record<string, unknown>): Promise<Buffer> {
1127
1324
  const path = typeof options.path === 'string' ? options.path : undefined;
1128
1325
  if (!path) throw new Error('Native browser screenshot requires an output path.');
@@ -1191,8 +1388,15 @@ export class MacOsAppleEventsPage {
1191
1388
  const prototype = element instanceof HTMLTextAreaElement ? HTMLTextAreaElement.prototype : HTMLInputElement.prototype;
1192
1389
  const setter = Object.getOwnPropertyDescriptor(prototype, 'value')?.set;
1193
1390
  if (setter) setter.call(element, ${JSON.stringify(value)}); else element.value = ${JSON.stringify(value)};
1194
- } else if (element.isContentEditable) element.textContent = ${JSON.stringify(value)};
1195
- else throw new Error('Element does not accept text input.');
1391
+ } else if (element.isContentEditable) {
1392
+ element.focus();
1393
+ const selection = window.getSelection();
1394
+ if (!selection) throw new Error('Contenteditable selection unavailable.');
1395
+ const range = document.createRange();
1396
+ range.selectNodeContents(element); selection.removeAllRanges(); selection.addRange(range);
1397
+ if (!document.execCommand('insertText', false, ${JSON.stringify(value)})) throw new Error('Contenteditable insertion rejected.');
1398
+ return true;
1399
+ } else throw new Error('Element does not accept text input.');
1196
1400
  element.dispatchEvent(new Event('input', { bubbles: true }));
1197
1401
  element.dispatchEvent(new Event('change', { bubbles: true }));
1198
1402
  return true;
@@ -1200,8 +1404,26 @@ export class MacOsAppleEventsPage {
1200
1404
  }
1201
1405
 
1202
1406
  async type(selector: string, text: string): Promise<void> {
1203
- const current = await this.evaluate<string>(selectorSource(selector, `return 'value' in element ? String(element.value || '') : String(element.textContent || '');`));
1204
- await this.fill(selector, `${current}${text}`);
1407
+ await this.evaluate(selectorSource(selector, `
1408
+ if ('value' in element) {
1409
+ element.focus();
1410
+ const value = String(element.value || '');
1411
+ const prototype = element instanceof HTMLTextAreaElement ? HTMLTextAreaElement.prototype : HTMLInputElement.prototype;
1412
+ const setter = Object.getOwnPropertyDescriptor(prototype, 'value')?.set;
1413
+ if (setter) setter.call(element, value + ${JSON.stringify(text)}); else element.value = value + ${JSON.stringify(text)};
1414
+ element.dispatchEvent(new Event('input', { bubbles: true }));
1415
+ return true;
1416
+ }
1417
+ if (!element.isContentEditable) throw new Error('Element does not accept text input.');
1418
+ element.focus();
1419
+ const selection = window.getSelection();
1420
+ if (!selection) throw new Error('Contenteditable selection unavailable.');
1421
+ const range = document.createRange();
1422
+ range.selectNodeContents(element); range.collapse(false);
1423
+ selection.removeAllRanges(); selection.addRange(range);
1424
+ if (!document.execCommand('insertText', false, ${JSON.stringify(text)})) throw new Error('Contenteditable insertion rejected.');
1425
+ return true;
1426
+ `));
1205
1427
  }
1206
1428
 
1207
1429
  async press(selector: string, key: string): Promise<void> {
@@ -1388,18 +1610,58 @@ async function resolveCurrentMacOsBrowserTabRef(
1388
1610
  return { windowId: match.windowId, tabId: match.tabId };
1389
1611
  }
1390
1612
 
1613
+ export interface MacOsBrowserTabInventoryOptions {
1614
+ /**
1615
+ * Correct stale active/frontmost bits through one extra foreground metadata
1616
+ * read. Exact-target callers that only need stable windowId/tabId/url identity
1617
+ * can disable this optional probe so a blocked foreground Apple Events read
1618
+ * cannot starve the inventory itself.
1619
+ */
1620
+ correctFrontmost?: boolean;
1621
+ }
1622
+
1391
1623
  export async function listMacOsBrowserTabs(
1392
1624
  product: MacOsBrowserProduct,
1393
1625
  timeoutMs = DEFAULT_NATIVE_TIMEOUT_MS,
1626
+ options: MacOsBrowserTabInventoryOptions = {},
1394
1627
  ): Promise<MacOsBrowserTabInventory> {
1395
1628
  const browser = browserDefinition(product);
1629
+ // Capture the frontmost tab before reading the stable inventory when callers
1630
+ // need corrected UI-current metadata. Exact-target identity does not depend on
1631
+ // this optional foreground probe.
1632
+ const inspected = options.correctFrontmost === false
1633
+ ? undefined
1634
+ : await inspectBrowser(product, timeoutMs);
1396
1635
  const raw = await runBrowserAutomationText(
1397
1636
  { action: 'list_tabs', product },
1398
1637
  listTabsScript(browser),
1399
1638
  [],
1400
1639
  timeoutMs,
1401
1640
  );
1402
- return parseTabInventory(product, raw);
1641
+ const inventory = parseTabInventory(product, raw);
1642
+ if (!inspected) return inventory;
1643
+ const metadata = inspected.metadata;
1644
+ const current = metadata?.frontmost === true && metadata.active !== false
1645
+ ? { windowId: metadata.windowId, tabId: metadata.tabId, url: metadata.url.trim() }
1646
+ : undefined;
1647
+ if (!current) return inventory;
1648
+ const hasIdentity = Boolean(current.windowId && current.tabId);
1649
+ const currentMatches = inventory.tabs.filter(tab => (
1650
+ hasIdentity
1651
+ ? tab.windowId === current.windowId && tab.tabId === current.tabId
1652
+ : Boolean(current.url) && tab.url.trim() === current.url
1653
+ ));
1654
+ const currentMatch = currentMatches.length === 1 ? currentMatches[0] : undefined;
1655
+ if (!currentMatch) return inventory;
1656
+ return {
1657
+ ...inventory,
1658
+ tabs: inventory.tabs.map(tab => ({
1659
+ ...tab,
1660
+ ...(currentMatch.windowId === tab.windowId && currentMatch.tabId === tab.tabId
1661
+ ? { active: true, frontmost: true }
1662
+ : { frontmost: false }),
1663
+ })),
1664
+ };
1403
1665
  }
1404
1666
 
1405
1667
  export async function readMacOsBrowserOwnedTabMetadata(
@@ -1407,11 +1669,24 @@ export async function readMacOsBrowserOwnedTabMetadata(
1407
1669
  ref: MacOsBrowserTabRef,
1408
1670
  timeoutMs = DEFAULT_NATIVE_TIMEOUT_MS,
1409
1671
  ): Promise<MacOsBrowserMetadata> {
1410
- const browser = browserDefinition(product);
1411
1672
  const resolvedRef = await resolveCurrentMacOsBrowserTabRef(product, ref, timeoutMs);
1673
+ return await readResolvedMacOsBrowserOwnedTabMetadata(product, resolvedRef, timeoutMs);
1674
+ }
1675
+
1676
+ /**
1677
+ * Read one exact native tab whose stable identity is already authoritative for
1678
+ * the caller. The targeted AppleScript still fails closed when that tab id is
1679
+ * gone, but does not perform another full browser inventory.
1680
+ */
1681
+ export async function readResolvedMacOsBrowserOwnedTabMetadata(
1682
+ product: MacOsBrowserProduct,
1683
+ ref: MacOsBrowserTabRef,
1684
+ timeoutMs = DEFAULT_NATIVE_TIMEOUT_MS,
1685
+ ): Promise<MacOsBrowserMetadata> {
1686
+ const browser = browserDefinition(product);
1412
1687
  return parseMetadata(product, await runBrowserAutomationText(
1413
- { action: 'metadata', product, ref: resolvedRef },
1414
- targetMetadataScript(browser, resolvedRef),
1688
+ { action: 'metadata', product, ref },
1689
+ targetMetadataScript(browser, ref),
1415
1690
  [],
1416
1691
  timeoutMs,
1417
1692
  ));
@@ -1481,12 +1756,13 @@ export async function createMacOsBrowserOwnedPageForProduct(
1481
1756
  product: MacOsBrowserProduct,
1482
1757
  url: string,
1483
1758
  attempts: MacOsBrowserAttachAttempt[],
1759
+ preferredWindowId?: string,
1484
1760
  timeoutMs = DEFAULT_NATIVE_TIMEOUT_MS,
1485
1761
  ): Promise<{ page: MacOsAppleEventsPage; attachment: MacOsBrowserAttachment }> {
1486
1762
  const browser = browserDefinition(product);
1487
1763
  const creationEvidence = await runCreateTabAutomation(
1488
1764
  { action: 'create_tab', product, url },
1489
- createOwnedTabScript(browser),
1765
+ createOwnedTabScript(browser, preferredWindowId),
1490
1766
  [url],
1491
1767
  timeoutMs,
1492
1768
  );
@@ -1544,12 +1820,28 @@ export async function closeMacOsBrowserOwnedTab(
1544
1820
  ref: MacOsBrowserTabRef,
1545
1821
  timeoutMs = DEFAULT_NATIVE_TIMEOUT_MS,
1546
1822
  ): Promise<void> {
1547
- const browser = browserDefinition(product);
1548
1823
  try {
1549
1824
  const resolvedRef = await resolveCurrentMacOsBrowserTabRef(product, ref, timeoutMs);
1825
+ await closeResolvedMacOsBrowserOwnedTab(product, resolvedRef, timeoutMs);
1826
+ } finally {
1827
+ invalidateMacOsBrowserPageHandle(product, ref);
1828
+ }
1829
+ }
1830
+
1831
+ /**
1832
+ * Close one exact native tab whose stable identity was already proven by the
1833
+ * caller's live inventory snapshot. This deliberately does not inventory again.
1834
+ */
1835
+ export async function closeResolvedMacOsBrowserOwnedTab(
1836
+ product: MacOsBrowserProduct,
1837
+ ref: MacOsBrowserTabRef,
1838
+ timeoutMs = DEFAULT_NATIVE_TIMEOUT_MS,
1839
+ ): Promise<void> {
1840
+ const browser = browserDefinition(product);
1841
+ try {
1550
1842
  await runBrowserAutomationText(
1551
- { action: 'close_tab', product, ref: resolvedRef },
1552
- closeOwnedTabScript(browser, resolvedRef),
1843
+ { action: 'close_tab', product, ref },
1844
+ closeOwnedTabScript(browser, ref),
1553
1845
  [],
1554
1846
  timeoutMs,
1555
1847
  );