@moretea-labs/forge 1.7.2 → 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 (900) hide show
  1. package/AGENTS.md +121 -62
  2. package/CHANGELOG.md +40 -0
  3. package/CLAUDE.md +57 -62
  4. package/CONTRIBUTING.md +3 -2
  5. package/README.md +2 -2
  6. package/SKILL.md +0 -1
  7. package/THIRD_PARTY_NOTICES.md +5 -2
  8. package/adapters/browser/index.ts +2 -0
  9. package/adapters/chatgpt/browser-delivery-host.ts +77 -0
  10. package/adapters/chatgpt/browser-delivery-runtime.ts +1256 -0
  11. package/adapters/chatgpt/controller-binding-store.ts +134 -0
  12. package/adapters/chatgpt/controller-round-host.ts +68 -0
  13. package/adapters/chatgpt/controller-round-settlement-store.ts +99 -0
  14. package/adapters/chatgpt/provider-delivery.ts +340 -0
  15. package/adapters/chatgpt/work-conversation-binding-store.ts +218 -0
  16. package/adapters/chatgpt/wsl-bridge-delivery-host.ts +63 -0
  17. package/adapters/computer/chatgpt-extension-target.ts +463 -0
  18. package/adapters/computer/chatgpt-target-router.ts +103 -0
  19. package/adapters/computer/chrome-extension/background.js +385 -0
  20. package/adapters/computer/chrome-extension/content.js +378 -0
  21. package/adapters/computer/chrome-extension/core.js +24 -0
  22. package/adapters/computer/chrome-extension/manifest.json +30 -0
  23. package/adapters/computer/desktop-operator-contract.ts +7 -0
  24. package/adapters/computer/desktop-operator-discovery.ts +181 -0
  25. package/adapters/computer/desktop-operator-negotiation.ts +174 -0
  26. package/adapters/computer/desktop-operator-provider.ts +312 -0
  27. package/adapters/computer/index.ts +1 -0
  28. package/adapters/computer/interaction-target-authority.ts +1068 -0
  29. package/adapters/controller-process/binding-store.ts +34 -0
  30. package/adapters/controller-process/controller-host.ts +26 -0
  31. package/adapters/mcp/access-mode.ts +132 -0
  32. package/adapters/mcp/audit.ts +32 -0
  33. package/adapters/mcp/auth.ts +406 -0
  34. package/adapters/mcp/instructions.ts +37 -0
  35. package/adapters/mcp/legacy-context.ts +18 -0
  36. package/adapters/mcp/multi-repository.ts +421 -0
  37. package/adapters/mcp/oauth.ts +464 -0
  38. package/adapters/mcp/paths.ts +143 -0
  39. package/adapters/mcp/policy.ts +232 -0
  40. package/adapters/mcp/proxy-env.ts +62 -0
  41. package/adapters/mcp/readiness-projection.ts +24 -0
  42. package/adapters/mcp/redaction.ts +21 -0
  43. package/adapters/mcp/repo.ts +24 -0
  44. package/adapters/mcp/runtime-gateway/artifact-adapter.ts +52 -0
  45. package/adapters/mcp/runtime-gateway/automation-receipt-adapter.ts +87 -0
  46. package/adapters/mcp/runtime-gateway/bounded-result-runtime.ts +62 -0
  47. package/adapters/mcp/runtime-gateway/cognition-settlement.ts +201 -0
  48. package/adapters/mcp/runtime-gateway/context-adapter.ts +1167 -0
  49. package/adapters/mcp/runtime-gateway/context-pack-sidecar.ts +91 -0
  50. package/adapters/mcp/runtime-gateway/controller-authority-adapter.ts +206 -0
  51. package/adapters/mcp/runtime-gateway/core-capability-adapter.ts +258 -0
  52. package/adapters/mcp/runtime-gateway/engineering-preconditions.ts +130 -0
  53. package/adapters/mcp/runtime-gateway/engineering-tool-contract.ts +15 -0
  54. package/adapters/mcp/runtime-gateway/execution-control-adapter.ts +28 -0
  55. package/adapters/mcp/runtime-gateway/execution-tools.ts +173 -0
  56. package/adapters/mcp/runtime-gateway/filesystem-adapter.ts +38 -0
  57. package/adapters/mcp/runtime-gateway/gateway-execution-adapter.ts +412 -0
  58. package/adapters/mcp/runtime-gateway/legacy-ios-tool-adapter.ts +105 -0
  59. package/adapters/mcp/runtime-gateway/maintenance-adapter.ts +44 -0
  60. package/adapters/mcp/runtime-gateway/model-adapter.ts +63 -0
  61. package/adapters/mcp/runtime-gateway/persisted-check-process.ts +3 -0
  62. package/adapters/mcp/runtime-gateway/plugin-adapter.ts +380 -0
  63. package/adapters/mcp/runtime-gateway/process-tools.ts +457 -0
  64. package/adapters/mcp/runtime-gateway/protected-computer-adapter.ts +88 -0
  65. package/adapters/mcp/runtime-gateway/recovery-adapter.ts +285 -0
  66. package/adapters/mcp/runtime-gateway/recovery-client-adapter.ts +70 -0
  67. package/adapters/mcp/runtime-gateway/recovery-tool-contract.ts +99 -0
  68. package/adapters/mcp/runtime-gateway/repository-compat-adapter.ts +79 -0
  69. package/adapters/mcp/runtime-gateway/result-adapter.ts +114 -0
  70. package/adapters/mcp/runtime-gateway/router.ts +242 -0
  71. package/adapters/mcp/runtime-gateway/routing-policy.ts +499 -0
  72. package/adapters/mcp/runtime-gateway/runtime-observation-adapter.ts +1200 -0
  73. package/adapters/mcp/runtime-gateway/runtime-readiness-observation.ts +218 -0
  74. package/adapters/mcp/runtime-gateway/runtime-tool-definitions.ts +574 -0
  75. package/adapters/mcp/runtime-gateway/runtime-tool-shared.ts +27 -0
  76. package/adapters/mcp/runtime-gateway/runtime-tools.ts +78 -0
  77. package/adapters/mcp/runtime-gateway/scheduler-adapter.ts +187 -0
  78. package/adapters/mcp/runtime-gateway/shared-adapter.ts +45 -0
  79. package/adapters/mcp/runtime-gateway/status-inbox-adapter.ts +962 -0
  80. package/adapters/mcp/runtime-gateway/typescript-navigation-sidecar.ts +136 -0
  81. package/adapters/mcp/runtime-gateway/work-adapter.ts +325 -0
  82. package/adapters/mcp/runtime-gateway/work-controller-operations.ts +257 -0
  83. package/adapters/mcp/runtime-gateway/work-detail-projection.ts +60 -0
  84. package/adapters/mcp/runtime-gateway/work-input-wire-migration.ts +246 -0
  85. package/adapters/mcp/runtime-gateway/work-learning-operations.ts +145 -0
  86. package/adapters/mcp/runtime-gateway/work-list-projection.ts +38 -0
  87. package/adapters/mcp/runtime-gateway/work-plan-operations.ts +382 -0
  88. package/adapters/mcp/runtime-gateway/work-repair-adapter.ts +308 -0
  89. package/adapters/mcp/runtime-gateway/work-requirement-operations.ts +148 -0
  90. package/adapters/mcp/runtime-gateway/work-semantic-operations.ts +263 -0
  91. package/adapters/mcp/runtime-gateway/work-validation-reconciler.ts +1 -0
  92. package/adapters/mcp/runtime-gateway/work-workflow-operations.ts +113 -0
  93. package/adapters/mcp/runtime-gateway/workflow-supervisor-adapter.ts +156 -0
  94. package/adapters/mcp/server.ts +1092 -0
  95. package/adapters/mcp/setup.ts +789 -0
  96. package/adapters/mcp/tool-capability-cache.ts +87 -0
  97. package/adapters/mcp/tool-mapping/access-tools.ts +387 -0
  98. package/adapters/mcp/tool-mapping/legacy-tool-service.ts +5139 -0
  99. package/adapters/mcp/tool-mapping/post-finalize-work-attribution.ts +145 -0
  100. package/adapters/mcp/tool-mapping/repository-tools.ts +1682 -0
  101. package/adapters/mcp/tool-mapping/tools.ts +9 -0
  102. package/adapters/mcp/tool-mapping/umbrella-tools.ts +117 -0
  103. package/adapters/mcp/toolset-names.ts +79 -0
  104. package/adapters/mcp/toolset-selection.ts +41 -0
  105. package/adapters/mcp/toolset.ts +337 -0
  106. package/adapters/mcp/transports/http-observation.ts +365 -0
  107. package/adapters/mcp/transports/http.ts +933 -0
  108. package/adapters/mcp/transports/oauth-http.ts +322 -0
  109. package/adapters/mcp/transports/session-registry.ts +519 -0
  110. package/adapters/mcp/transports/stdio.ts +8 -0
  111. package/adapters/mcp/tunnels/openai-secure-tunnel.ts +223 -0
  112. package/adapters/mcp/types.ts +41 -0
  113. package/assets/AGENTS.md +2 -16
  114. package/assets/CLAUDE.md +2 -16
  115. package/assets/hooks/AGENTS.md +3 -14
  116. package/assets/hooks/CLAUDE.md +3 -14
  117. package/assets/hooks/hook-input.sh +9 -2
  118. package/assets/hooks/lib/workflow-state.sh +28 -10
  119. package/assets/hooks/prompt-guard.sh +63 -37
  120. package/assets/hooks/security-sentinel.sh +2 -1
  121. package/assets/hooks/session-start-context.sh +7 -5
  122. package/assets/hooks/stop-orchestrator.sh +13 -3
  123. package/assets/initializer-question-pack.v4.json +11 -7
  124. package/assets/partials/05-workflow.partial.md +18 -73
  125. package/assets/partials/07-footer.partial.md +1 -1
  126. package/assets/partials-agents/02-operating-mode.partial.md +1 -2
  127. package/assets/partials-agents/04-task-protocol.partial.md +14 -59
  128. package/assets/partials-agents/06-quality-safety.partial.md +11 -16
  129. package/assets/partials-agents/08-deep-docs.partial.md +1 -2
  130. package/assets/plan-map.json +11 -11
  131. package/assets/plugin-registry.v1.json +11 -3
  132. package/assets/plugin-trust-policy.v1.json +6 -0
  133. package/assets/recovery/ForgeRecovery.ps1 +100 -0
  134. package/assets/recovery/forge-wsl-rescue +271 -0
  135. package/assets/reference-configs/agentic-development-flow.md +25 -0
  136. package/assets/reference-configs/development-protocol.md +11 -15
  137. package/assets/reference-configs/document-generation.md +1 -1
  138. package/assets/reference-configs/global-working-rules.md +28 -1
  139. package/assets/reference-configs/harness-overview.md +22 -112
  140. package/assets/reference-configs/hook-operations.md +1 -1
  141. package/assets/reference-configs/sprint-contracts.md +2 -2
  142. package/assets/skill-version.json +2 -2
  143. package/assets/templates/helpers/architecture-event.ts +3 -34
  144. package/assets/templates/helpers/architecture-queue.sh +61 -10
  145. package/assets/templates/helpers/archive-workflow.sh +90 -180
  146. package/assets/templates/helpers/capability-config.ts +8 -11
  147. package/assets/templates/helpers/capability-resolver.ts +37 -19
  148. package/assets/templates/helpers/capture-plan.sh +2 -2
  149. package/assets/templates/helpers/check-architecture-sync.sh +1 -9
  150. package/assets/templates/helpers/check-task-sync.sh +82 -11
  151. package/assets/templates/helpers/check-task-workflow.sh +1 -3
  152. package/assets/templates/helpers/context-contract-sync.sh +1 -12
  153. package/assets/templates/helpers/contract-worktree.sh +26 -24
  154. package/assets/templates/helpers/ensure-task-workflow.sh +6 -8
  155. package/assets/templates/helpers/inspect-project-state.ts +1 -1
  156. package/assets/templates/helpers/migrate-project-template.sh +1 -1
  157. package/assets/templates/helpers/migrate-workflow-docs.ts +53 -239
  158. package/assets/templates/helpers/new-plan.sh +2 -2
  159. package/assets/templates/helpers/plan-to-todo.sh +3 -31
  160. package/assets/templates/helpers/sprint-backlog.sh +1 -1
  161. package/assets/templates/helpers/switch-plan.sh +1 -1
  162. package/assets/templates/helpers/workflow-contract.ts +1 -0
  163. package/assets/workflow-contract.v1.json +63 -171
  164. package/assets/workflows/xiaohongshu/xiaohongshu.collect-metrics.v1.draft.json +118 -0
  165. package/assets/workflows/xiaohongshu/xiaohongshu.publish-image-note.v1.draft.json +316 -0
  166. package/assets/workflows/xiaohongshu/xiaohongshu.publish-long-text.v1.draft.json +324 -0
  167. package/docs/architecture/CURRENT.md +233 -28
  168. package/docs/architecture/EVOLUTION.md +13 -0
  169. package/docs/architecture/decisions/20260801-controller-home-sqlite-state.md +2 -1
  170. package/docs/architecture/decisions/20260803-release-identity-binding-and-exit-policy.md +14 -5
  171. package/docs/architecture/decisions/20260823-immediate-controller-relay.md +6 -3
  172. package/docs/architecture/decisions/20260831-independent-windows-wsl-host-rescue.md +59 -0
  173. package/docs/architecture/decisions/20260904-ios-device-migration-baseline.md +120 -0
  174. package/docs/architecture/decisions/20260904-repository-runtime-data-boundary.md +42 -0
  175. package/docs/architecture/decisions/20260907-assistant-learning-loop.md +37 -0
  176. package/docs/architecture/decisions/20260907-controller-round-transition-policy.md +311 -0
  177. package/docs/architecture/decisions/20260907-maintenance-diagnosis-bounded-read.md +39 -0
  178. package/docs/architecture/decisions/20260916-workflow-supervisor-authority.md +249 -0
  179. package/docs/architecture/decisions/20260917-cognitive-memory-foundation.md +82 -0
  180. package/docs/architecture/decisions/20260918-stable-candidate-release-lifecycle.md +221 -0
  181. package/docs/architecture/decisions/20260919-autonomous-work-liveness.md +62 -0
  182. package/docs/architecture/decisions/20260924-thin-semantic-working-context.md +72 -0
  183. package/docs/architecture/decisions/20261001-supervisor-turn-authority.md +237 -0
  184. package/docs/architecture/decisions/20261005-forge-v3-desktop-client-boundary.md +77 -0
  185. package/docs/architecture/domains/verification.md +8 -0
  186. package/docs/architecture/domains/workflow-engine.md +7 -1
  187. package/docs/architecture/index.md +3 -3
  188. package/docs/architecture/modules/controller-runtime/transport-lifecycle.md +19 -8
  189. package/docs/architecture/requests/2026-09-04-computer-plugin-workflow-taxonomy.md +124 -0
  190. package/docs/forge-chatgpt-mcp-setup.md +5 -3
  191. package/docs/forge-plugin-management.md +20 -4
  192. package/docs/forge-runtime-self-healing-loop.md +2 -0
  193. package/docs/operations/benchmark-cross-version-freeze.md +38 -0
  194. package/docs/operations/controller-browser-plugin.md +3 -1
  195. package/docs/operations/controller-performance-and-502.md +17 -0
  196. package/docs/operations/controller-reliability-runbook.md +2 -2
  197. package/docs/operations/features.md +1 -1
  198. package/docs/operations/features.zh-CN.md +1 -1
  199. package/docs/operations/homebrew.md +2 -2
  200. package/docs/operations/mcp-tool-exposure.md +2 -0
  201. package/docs/operations/platform-support.md +16 -8
  202. package/docs/operations/platform-support.zh-CN.md +2 -2
  203. package/docs/operations/releasing.md +2 -0
  204. package/docs/operations/standalone-disaster-recovery.md +38 -5
  205. package/docs/operations/uu-remote-rescue.md +41 -0
  206. package/docs/operations/windows-wsl-host-rescue.md +133 -0
  207. package/docs/public-usage-guide.md +1 -1
  208. package/docs/public-usage-guide.zh-CN.md +1 -1
  209. package/docs/tutorials/01-install-and-start.md +1 -1
  210. package/docs/tutorials/01-install-and-start.zh-CN.md +1 -1
  211. package/docs/tutorials/02-connect-chatgpt.md +4 -4
  212. package/docs/tutorials/02-connect-chatgpt.zh-CN.md +4 -4
  213. package/docs/wiki/Implementation.md +1 -1
  214. package/package.json +46 -26
  215. package/packages/kernel/cognition/api/index.ts +6 -0
  216. package/packages/kernel/cognition/application/activation-service.ts +451 -0
  217. package/packages/kernel/cognition/application/consolidation-service.ts +185 -0
  218. package/packages/kernel/cognition/application/legacy-experience-adapter.ts +38 -0
  219. package/packages/kernel/cognition/application/memory-service.ts +64 -0
  220. package/packages/kernel/cognition/domain/learning.ts +106 -0
  221. package/packages/kernel/cognition/domain/memory.ts +254 -0
  222. package/packages/kernel/controller/api/index.ts +3 -0
  223. package/packages/kernel/controller/application/continuation-service.ts +281 -0
  224. package/packages/kernel/controller/application/controller-round-service.ts +41 -0
  225. package/packages/kernel/controller/application/controller-service.ts +30 -0
  226. package/packages/kernel/controller/domain/controller-round-transition-policy.ts +529 -0
  227. package/packages/kernel/controller/domain/controller-round.ts +110 -0
  228. package/packages/kernel/controller/domain/execution-quality.ts +135 -0
  229. package/packages/kernel/controller/domain/types.ts +56 -0
  230. package/packages/kernel/controller/index.ts +1 -0
  231. package/packages/kernel/controller/infrastructure/controller-binding-store.ts +84 -0
  232. package/packages/kernel/controller/infrastructure/controller-round-store.ts +1970 -0
  233. package/packages/kernel/controller/infrastructure/controller-session-store.ts +804 -0
  234. package/packages/kernel/controller/ports/controller-host.ts +18 -0
  235. package/packages/kernel/goal/api/index.ts +1 -0
  236. package/packages/kernel/goal/domain/types.ts +40 -0
  237. package/packages/kernel/goal/index.ts +1 -0
  238. package/packages/kernel/identity/api/index.ts +15 -0
  239. package/packages/kernel/identity/application/identity-service.ts +67 -0
  240. package/packages/kernel/identity/domain/activity-projection.ts +43 -0
  241. package/packages/kernel/identity/domain/capability-broker.ts +60 -0
  242. package/packages/kernel/identity/domain/grant.ts +72 -0
  243. package/packages/kernel/identity/domain/owned-resource.ts +116 -0
  244. package/packages/kernel/identity/domain/scope.ts +63 -0
  245. package/packages/kernel/identity/domain/semantic-sync.ts +81 -0
  246. package/packages/kernel/identity/domain/types.ts +44 -0
  247. package/packages/kernel/identity/domain/user-request.ts +93 -0
  248. package/packages/kernel/identity/domain/workspace.ts +56 -0
  249. package/packages/kernel/identity/index.ts +1 -0
  250. package/packages/kernel/identity/infrastructure/activity-projection-store.ts +77 -0
  251. package/packages/kernel/identity/infrastructure/capability-broker.ts +81 -0
  252. package/packages/kernel/identity/infrastructure/grant-store.ts +284 -0
  253. package/packages/kernel/identity/infrastructure/identity-store.ts +75 -0
  254. package/packages/kernel/identity/infrastructure/owned-resource-store.ts +259 -0
  255. package/packages/kernel/identity/infrastructure/user-request-store.ts +182 -0
  256. package/packages/kernel/memory/api/index.ts +5 -0
  257. package/packages/kernel/memory/application/experience-service.ts +118 -0
  258. package/packages/kernel/memory/application/outcome-service.ts +77 -0
  259. package/packages/kernel/memory/domain/experience.ts +103 -0
  260. package/packages/kernel/memory/domain/operational-prior.ts +92 -0
  261. package/packages/kernel/memory/index.ts +1 -0
  262. package/packages/kernel/scheduler/api/index.ts +4 -0
  263. package/packages/kernel/scheduler/application/eligibility.ts +252 -0
  264. package/packages/kernel/scheduler/application/schedule-service.ts +27 -0
  265. package/packages/kernel/scheduler/application/settlement.ts +182 -0
  266. package/packages/kernel/scheduler/domain/schedule.ts +236 -0
  267. package/packages/kernel/scheduler/index.ts +1 -0
  268. package/packages/kernel/scheduler/infrastructure/schedule-store.ts +805 -0
  269. package/packages/kernel/work/api/index.ts +16 -0
  270. package/packages/kernel/work/application/work-service.ts +123 -0
  271. package/packages/kernel/work/domain/check-receipt.ts +43 -0
  272. package/packages/kernel/work/domain/context-closure-receipt.ts +32 -0
  273. package/packages/kernel/work/domain/current-task-lineage.ts +104 -0
  274. package/packages/kernel/work/domain/engineering-contracts.ts +157 -0
  275. package/packages/kernel/work/domain/engineering-design.ts +286 -0
  276. package/packages/kernel/work/domain/engineering-profile.ts +238 -0
  277. package/packages/kernel/work/domain/evaluation-promotion-receipt.ts +186 -0
  278. package/packages/kernel/work/domain/execution-concurrency.ts +247 -0
  279. package/packages/kernel/work/domain/execution-snapshot.ts +2 -0
  280. package/packages/kernel/work/domain/implementation-review.ts +193 -0
  281. package/packages/kernel/work/domain/objective-graph.ts +119 -0
  282. package/packages/kernel/work/domain/project-engineering-contract.ts +224 -0
  283. package/packages/kernel/work/domain/repository-completion-receipt.ts +73 -0
  284. package/{src/runtime/control-plane/facade/work-state-machine.ts → packages/kernel/work/domain/state-machine.ts} +37 -66
  285. package/packages/kernel/work/domain/types.ts +534 -0
  286. package/packages/kernel/work/index.ts +1 -0
  287. package/packages/kernel/work/infrastructure/work-contract-store.ts +1967 -0
  288. package/packages/kernel/work/ports/work-contract-store.ts +21 -0
  289. package/packages/plugin-runtime/browser/index.ts +3 -0
  290. package/packages/plugin-runtime/browser/provider-registry.ts +110 -0
  291. package/packages/plugin-runtime/browser/runtime-contract.ts +150 -0
  292. package/packages/plugin-runtime/browser/session-authority.ts +62 -0
  293. package/packages/plugin-runtime/computer/chatgpt-identity.ts +24 -0
  294. package/packages/plugin-runtime/computer/conversation-target.ts +143 -0
  295. package/packages/plugin-runtime/computer/index.ts +8 -0
  296. package/packages/plugin-runtime/computer/provider-error.ts +26 -0
  297. package/packages/plugin-runtime/computer/provider-registration.ts +52 -0
  298. package/packages/plugin-runtime/computer/provider-registry.ts +63 -0
  299. package/packages/plugin-runtime/computer/provider.ts +19 -0
  300. package/packages/plugin-runtime/computer/target-authority.ts +215 -0
  301. package/packages/plugin-runtime/computer/target-persistence.ts +54 -0
  302. package/packages/plugin-runtime/external/index.ts +1 -0
  303. package/packages/plugin-runtime/external/unix-jsonl-transport.ts +581 -0
  304. package/packages/plugin-runtime/index.ts +3 -0
  305. package/packages/protocols/browser/index.ts +1 -0
  306. package/packages/protocols/browser/session.ts +98 -0
  307. package/packages/protocols/computer/contract.ts +225 -0
  308. package/packages/protocols/computer/index.ts +1 -0
  309. package/packages/protocols/failure/contract.ts +158 -0
  310. package/packages/protocols/failure/index.ts +1 -0
  311. package/packages/protocols/handoff/index.ts +1 -0
  312. package/packages/protocols/handoff/status.ts +22 -0
  313. package/packages/protocols/mcp/execution-context.ts +11 -0
  314. package/packages/protocols/mcp/index.ts +2 -0
  315. package/packages/protocols/mcp/tool-contract.ts +42 -0
  316. package/packages/workflow-runtime/api/index.ts +2 -0
  317. package/packages/workflow-runtime/application/interpreter.ts +342 -0
  318. package/packages/workflow-runtime/domain/workflow-asset.ts +223 -0
  319. package/packages/workflow-runtime/index.ts +1 -0
  320. package/scripts/activate-source-baseline.ts +7 -9
  321. package/scripts/assemble-template.ts +1 -1
  322. package/scripts/bootstrap-runtime-maintenance-recovery.sh +4 -1
  323. package/scripts/canary-chatgpt-provider-delivery.ts +97 -0
  324. package/scripts/canary-controller-semantic-wait.ts +183 -0
  325. package/scripts/canary-global-hook.sh +2 -2
  326. package/scripts/check-mcp-compatibility.ts +85 -7
  327. package/scripts/check-platform-support.mjs +28 -2
  328. package/scripts/check-public-docs.sh +1 -1
  329. package/scripts/check-repository-hygiene.mjs +92 -0
  330. package/scripts/check-runtime-architecture.mjs +1643 -127
  331. package/scripts/check-source-duplication.mjs +9 -1
  332. package/scripts/controller-ngrok-rotation.sh +5 -4
  333. package/scripts/create-project-dirs.sh +10 -74
  334. package/scripts/forge-local-recovery-helper.mjs +282 -0
  335. package/scripts/forge-uu-remote-rescue-helper.d.mts +31 -0
  336. package/scripts/forge-uu-remote-rescue-helper.mjs +409 -0
  337. package/scripts/forge-windows-host-recovery-helper.mjs +136 -0
  338. package/scripts/hook-shim.sh +2 -2
  339. package/scripts/init-project.sh +12 -70
  340. package/scripts/install-desktop-operator-registration.ts +4 -2
  341. package/scripts/install-independent-windows-wsl-recovery.ts +125 -0
  342. package/scripts/install-standalone-recovery.ts +122 -10
  343. package/scripts/install-uu-remote-rescue-registration.ts +74 -0
  344. package/scripts/install-windows-host-recovery-registration.ts +22 -0
  345. package/scripts/lib/controller-home-env.sh +6 -3
  346. package/scripts/lib/project-init-lib.sh +42 -582
  347. package/scripts/migrate-chatgpt-automation-schedules.ts +2 -2
  348. package/scripts/migrate-windows-wsl-controller-home.ts +306 -0
  349. package/scripts/open-source-audit-allowlist.txt +11 -1
  350. package/scripts/portability-bindings.mjs +70 -0
  351. package/scripts/run-bounded-command.mjs +60 -0
  352. package/scripts/run-bun-test-file.ts +22 -6
  353. package/scripts/run-governed-gate.ts +4 -2
  354. package/scripts/run-mobile-monitor-bridge.ts +0 -1
  355. package/scripts/smoke-control-plane-failure-domain.ts +94 -0
  356. package/scripts/smoke-mcp-http-runtime.ts +6 -1
  357. package/scripts/smoke-runtime-recovery.ts +13 -11
  358. package/scripts/smoke-schedule-engine.ts +24 -16
  359. package/scripts/smoke-unattended-transport-recovery.ts +223 -0
  360. package/scripts/smoke-user-request-continuation-restart.ts +232 -0
  361. package/scripts/smoke-workflow-supervisor-chrome-adapter.ts +92 -0
  362. package/scripts/smoke-workflow-supervisor-process-restart.ts +276 -0
  363. package/scripts/smoke-workflow-supervisor-restart-recovery.ts +150 -0
  364. package/scripts/smoke-workflow-supervisor.ts +103 -0
  365. package/scripts/test-governance.ts +51 -2
  366. package/scripts/verify-forge-runtime.sh +2 -1
  367. package/src/cli/agent-jobs/executor-health.ts +11 -34
  368. package/src/cli/agent-jobs/integration.ts +18 -49
  369. package/src/cli/agent-jobs/job-manager.ts +17 -4
  370. package/src/cli/chatgpt-browser/bind-server.ts +2 -1
  371. package/src/cli/chatgpt-browser/binding.ts +20 -10
  372. package/src/cli/chatgpt-browser/bridge-extension.ts +75 -0
  373. package/src/cli/chatgpt-browser/bridge-provider.ts +376 -11
  374. package/src/cli/chatgpt-browser/engine.ts +10 -11
  375. package/src/cli/chatgpt-browser/native-provider.ts +24 -83
  376. package/src/cli/chatgpt-browser/oracle-provider.ts +5 -3
  377. package/src/cli/chatgpt-browser/types.ts +1 -0
  378. package/src/cli/commands/bootstrap-control.ts +334 -0
  379. package/src/cli/commands/brain-assistant.ts +52 -0
  380. package/src/cli/commands/brain.ts +191 -40
  381. package/src/cli/commands/chatgpt.ts +32 -67
  382. package/src/cli/commands/computer.ts +437 -0
  383. package/src/cli/commands/doctor.ts +18 -1
  384. package/src/cli/commands/init-hook.ts +71 -61
  385. package/src/cli/commands/init.ts +3 -1
  386. package/src/cli/commands/mcp.ts +16 -10
  387. package/src/cli/commands/plugin.ts +38 -12
  388. package/src/cli/commands/recovery.ts +507 -80
  389. package/src/cli/commands/runtime.ts +12 -7
  390. package/src/cli/commands/setup-profile.ts +97 -39
  391. package/src/cli/commands/status.ts +2 -1
  392. package/src/cli/controller/check-runner.ts +500 -100
  393. package/src/cli/controller/completion-backlog.ts +3 -3
  394. package/src/cli/controller/completion-orchestrator.ts +4 -43
  395. package/src/cli/controller/completion-target.ts +3 -72
  396. package/src/cli/controller/context/source-materializer.ts +81 -100
  397. package/src/cli/controller/context/types.ts +7 -1
  398. package/src/cli/controller/context-pack.ts +28 -6
  399. package/src/cli/controller/execution-completion.ts +4 -7
  400. package/src/cli/controller/execution-policy.ts +36 -153
  401. package/src/cli/controller/governance.ts +2 -3
  402. package/src/cli/controller/issue-store.ts +4 -99
  403. package/src/cli/controller/launch-agents.ts +59 -18
  404. package/src/cli/controller/operational-plan.ts +24 -51
  405. package/src/cli/controller/runtime-config.ts +5 -1
  406. package/src/cli/controller/stuck-state-migration.ts +2 -3
  407. package/src/cli/controller/systemd-user.ts +148 -0
  408. package/src/cli/controller/types.ts +10 -70
  409. package/src/cli/controller/worklog.ts +67 -13
  410. package/src/cli/editing/edit-operation-contract.ts +92 -0
  411. package/src/cli/editing/edit-session.ts +290 -20
  412. package/src/cli/github/plugin.ts +17 -12
  413. package/src/cli/hook/route-registry.ts +3 -5
  414. package/src/cli/hook/runtime.ts +49 -3
  415. package/src/cli/index.ts +3 -0
  416. package/src/cli/local-bridge/connector-freshness.ts +2 -2
  417. package/src/cli/local-bridge/console-automations.ts +20 -15
  418. package/src/cli/local-bridge/console-view-models.ts +3 -12
  419. package/src/cli/local-bridge/facade-api.ts +105 -205
  420. package/src/cli/local-bridge/job-store.ts +1 -1
  421. package/src/cli/local-bridge/server.ts +48 -174
  422. package/src/cli/local-bridge/types.ts +0 -1
  423. package/src/cli/mcp/access-mode.ts +2 -132
  424. package/src/cli/mcp/access-tools.ts +2 -387
  425. package/src/cli/mcp/audit.ts +2 -32
  426. package/src/cli/mcp/auth.ts +2 -404
  427. package/src/cli/mcp/instructions.ts +2 -34
  428. package/src/cli/mcp/legacy-context.ts +2 -16
  429. package/src/cli/mcp/legacy-tool-service.ts +2 -5308
  430. package/src/cli/mcp/multi-repository.ts +2 -436
  431. package/src/cli/mcp/oauth-client-retirement.ts +74 -0
  432. package/src/cli/mcp/oauth.ts +2 -375
  433. package/src/cli/mcp/openai-secure-tunnel.ts +2 -0
  434. package/src/cli/mcp/paths.ts +2 -140
  435. package/src/cli/mcp/policy.ts +2 -232
  436. package/src/cli/mcp/post-finalize-work-attribution.ts +2 -150
  437. package/src/cli/mcp/proxy-env.ts +2 -62
  438. package/src/cli/mcp/readiness-projection.ts +2 -24
  439. package/src/cli/mcp/redaction.ts +2 -21
  440. package/src/cli/mcp/repo.ts +2 -24
  441. package/src/cli/mcp/repository-tools.ts +2 -1613
  442. package/src/cli/mcp/server.ts +2 -951
  443. package/src/cli/mcp/setup.ts +2 -737
  444. package/src/cli/mcp/tool-capability-cache.ts +2 -87
  445. package/src/cli/mcp/tool-contract.ts +2 -14
  446. package/src/cli/mcp/tools.ts +2 -9
  447. package/src/cli/mcp/toolset-names.ts +2 -70
  448. package/src/cli/mcp/toolset-selection.ts +2 -41
  449. package/src/cli/mcp/toolset.ts +2 -336
  450. package/src/cli/mcp/transports/AGENTS.md +1 -10
  451. package/src/cli/mcp/transports/CLAUDE.md +1 -10
  452. package/src/cli/mcp/transports/http.ts +2 -1414
  453. package/src/cli/mcp/transports/session-registry.ts +2 -490
  454. package/src/cli/mcp/transports/stdio.ts +2 -8
  455. package/src/cli/mcp/types.ts +2 -41
  456. package/src/cli/mcp/umbrella-tools.ts +2 -117
  457. package/src/cli/repositories/command-executor.ts +91 -39
  458. package/src/cli/repositories/command-scope.ts +139 -4
  459. package/src/cli/repositories/controller-home.ts +167 -1
  460. package/src/cli/repositories/ephemeral-workspace.ts +20 -30
  461. package/src/cli/repositories/git-command-executor.ts +2 -2
  462. package/src/cli/repositories/identity.ts +13 -0
  463. package/src/cli/repositories/registry.ts +145 -60
  464. package/src/cli/repositories/repository-snapshot.ts +53 -7
  465. package/src/cli/repositories/runtime-storage.ts +27 -2
  466. package/src/cli/repositories/safe-patch.ts +34 -38
  467. package/src/cli/repositories/selected-path-actions.ts +22 -2
  468. package/src/cli/repositories/structured-git.ts +167 -27
  469. package/src/cli/repository/session-cache.ts +92 -6
  470. package/src/cli/runtime/helper-runner.ts +7 -0
  471. package/src/cli/runtime-invocation.ts +8 -1
  472. package/src/cli/tools/codegraph.ts +44 -25
  473. package/src/core/adoption/manifest-templates.ts +1 -1
  474. package/src/core/adoption/plan.ts +3 -26
  475. package/src/core/adoption/workflow-contract-plan.ts +17 -9
  476. package/src/effects/process-runner.ts +8 -14
  477. package/src/runtime/context/assistant-context.ts +167 -0
  478. package/src/runtime/context/assistant-work-context.ts +209 -0
  479. package/src/runtime/context/automatic-learning.ts +565 -0
  480. package/src/runtime/context/codegraph-cache-boundary.ts +255 -0
  481. package/src/runtime/context/codegraph-read-provider.ts +55 -22
  482. package/src/runtime/context/codegraph-sidecar.cjs +8 -1
  483. package/src/runtime/context/cognitive-attention.ts +173 -0
  484. package/src/runtime/context/cognitive-skill-canary.ts +158 -0
  485. package/src/runtime/context/context-closure.ts +305 -0
  486. package/src/runtime/context/context-pack-process.ts +103 -0
  487. package/src/runtime/context/context-plane.ts +203 -0
  488. package/src/runtime/context/direct-controller-learning.ts +298 -0
  489. package/src/runtime/context/project-engineering-contract.ts +60 -0
  490. package/src/runtime/context/semantic-navigation-contract.ts +9 -0
  491. package/src/runtime/context/semantic-navigation.ts +6 -34
  492. package/src/runtime/context/typescript-navigation-process.ts +145 -0
  493. package/src/runtime/context/typescript-navigation.ts +89 -3
  494. package/src/runtime/control-plane/bootstrap/capability-provider.ts +74 -0
  495. package/src/runtime/control-plane/bootstrap/control-api.ts +57 -0
  496. package/src/runtime/control-plane/bootstrap/index.ts +5 -0
  497. package/src/runtime/control-plane/bootstrap/state-machine.ts +141 -0
  498. package/src/runtime/control-plane/bootstrap/store.ts +21 -0
  499. package/src/runtime/control-plane/bootstrap/types.ts +87 -0
  500. package/src/runtime/control-plane/cleanup-artifact-retention.ts +531 -0
  501. package/src/runtime/control-plane/codegraph-cache-retention.ts +164 -0
  502. package/src/runtime/control-plane/concurrency/work-execution-concurrency.ts +282 -0
  503. package/src/runtime/control-plane/execution/controller-authority-recovery.ts +380 -0
  504. package/src/runtime/control-plane/execution/edit-validation-coordinator.ts +113 -16
  505. package/src/runtime/control-plane/execution/execution-identity.ts +23 -3
  506. package/src/runtime/control-plane/execution/implementation-review-content.ts +95 -0
  507. package/src/runtime/control-plane/execution/repository-work-attribution.ts +7 -30
  508. package/src/runtime/control-plane/execution/retained-work-resume.ts +439 -102
  509. package/src/runtime/control-plane/execution/session-store.ts +31 -1
  510. package/src/runtime/control-plane/execution/validation.ts +34 -11
  511. package/src/runtime/control-plane/execution/work-authority-reconciler.ts +87 -0
  512. package/src/runtime/control-plane/execution/work-check-evidence.ts +137 -0
  513. package/src/runtime/control-plane/execution/work-completion-authority.ts +31 -44
  514. package/src/runtime/control-plane/execution/work-delivery-service.ts +497 -0
  515. package/src/runtime/control-plane/execution/work-evidence-policy.ts +46 -53
  516. package/src/runtime/control-plane/execution/work-execution-support.ts +85 -164
  517. package/src/runtime/control-plane/execution/work-handle-authority.ts +349 -73
  518. package/src/runtime/control-plane/execution/work-handle-store.ts +55 -2
  519. package/src/runtime/control-plane/execution/work-head-settlement.ts +108 -0
  520. package/src/runtime/control-plane/execution/work-lifecycle-audit.ts +173 -28
  521. package/src/runtime/control-plane/execution/work-operation-service.ts +92 -40
  522. package/src/runtime/control-plane/execution/work-preparation-service.ts +145 -269
  523. package/src/runtime/control-plane/execution/work-remote-delivery.ts +2 -3
  524. package/src/runtime/control-plane/execution/work-revision-diff.ts +39 -0
  525. package/src/runtime/control-plane/execution/work-terminal-cleanup.ts +543 -225
  526. package/src/runtime/control-plane/execution/work-validation-reconciler.ts +59 -45
  527. package/src/runtime/control-plane/execution/work-verification-context.ts +1 -1
  528. package/src/runtime/control-plane/execution/work-verification-service.ts +662 -52
  529. package/src/runtime/control-plane/execution/work-verification-snapshot.ts +205 -16
  530. package/src/runtime/control-plane/facade/capability-registry.ts +380 -44
  531. package/src/runtime/control-plane/facade/check-normalization.ts +3 -9
  532. package/src/runtime/control-plane/facade/codex-delegation.ts +10 -11
  533. package/src/runtime/control-plane/facade/controller-connection.ts +135 -0
  534. package/src/runtime/control-plane/facade/controller-session-store.ts +2 -488
  535. package/src/runtime/control-plane/facade/goal-workloop-access.ts +6 -22
  536. package/src/runtime/control-plane/facade/goal-workloop.ts +565 -1202
  537. package/src/runtime/control-plane/facade/handoff-inbox-application.ts +145 -0
  538. package/src/runtime/control-plane/facade/handoff-inbox-store.ts +266 -52
  539. package/src/runtime/control-plane/facade/index.ts +4 -3
  540. package/src/runtime/control-plane/facade/operation-digest.ts +34 -73
  541. package/src/runtime/control-plane/facade/plan-contract-store.ts +671 -245
  542. package/src/runtime/control-plane/facade/policy-gate.ts +0 -23
  543. package/src/runtime/control-plane/facade/repository-work-admission.ts +31 -23
  544. package/src/runtime/control-plane/facade/requirement-authority.ts +121 -0
  545. package/src/runtime/control-plane/facade/requirement-board.ts +9 -4
  546. package/src/runtime/control-plane/facade/rh-work-operation-contract.ts +85 -0
  547. package/src/runtime/control-plane/facade/self-healing-loop.ts +18 -53
  548. package/src/runtime/control-plane/facade/semantic-admission.ts +8 -16
  549. package/src/runtime/control-plane/facade/suggested-actions.ts +15 -15
  550. package/src/runtime/control-plane/facade/types.ts +218 -620
  551. package/src/runtime/control-plane/facade/work-continuation.ts +8 -8
  552. package/src/runtime/control-plane/facade/work-contract-store.ts +2 -1043
  553. package/src/runtime/control-plane/generated-cache-retention.ts +336 -19
  554. package/src/runtime/control-plane/global-scheduler/autonomous-continuation.ts +248 -0
  555. package/src/runtime/control-plane/global-scheduler/durable-admission.ts +13 -2
  556. package/src/runtime/control-plane/global-scheduler/maintenance.ts +274 -84
  557. package/src/runtime/control-plane/global-scheduler/periodic-cleanup-entry.ts +55 -0
  558. package/src/runtime/control-plane/global-scheduler/periodic-cleanup-process.ts +98 -0
  559. package/src/runtime/control-plane/global-scheduler/reconciliation.ts +3 -2
  560. package/src/runtime/control-plane/global-scheduler/scheduler-worker-entry.ts +10 -0
  561. package/src/runtime/control-plane/global-scheduler/scheduler.ts +227 -109
  562. package/src/runtime/control-plane/global-scheduler/wake-signal.ts +42 -2
  563. package/src/runtime/control-plane/global-scheduler/worker-launch.ts +18 -6
  564. package/src/runtime/control-plane/governance/access-policy.ts +19 -2
  565. package/src/runtime/control-plane/governance/authorization.ts +20 -3
  566. package/src/runtime/control-plane/launcher/chatgpt-round-continuation.ts +160 -0
  567. package/src/runtime/control-plane/launcher/chatgpt-work-binding-store.ts +2 -177
  568. package/src/runtime/control-plane/launcher/chatgpt-work-continuation.ts +139 -670
  569. package/src/runtime/control-plane/launcher/local-conversation-controller.ts +238 -0
  570. package/src/runtime/control-plane/launcher/provider-mcp-bootstrap.ts +25 -6
  571. package/src/runtime/control-plane/launcher/thin-launcher.ts +96 -194
  572. package/src/runtime/control-plane/lifecycle-retention-metrics.ts +60 -0
  573. package/src/runtime/control-plane/persistence/cognition-store.ts +820 -0
  574. package/src/runtime/control-plane/persistence/experience-store.ts +302 -0
  575. package/src/runtime/control-plane/persistence/operational-prior-store.ts +348 -0
  576. package/src/runtime/control-plane/persistence/requirement-store.ts +230 -80
  577. package/src/runtime/control-plane/persistence/sqlite-store.ts +654 -78
  578. package/src/runtime/control-plane/persistence/workflow-content-store.ts +98 -0
  579. package/src/runtime/control-plane/persistence/workflow-registry-store.ts +186 -0
  580. package/src/runtime/control-plane/persistence/workflow-run-store.ts +123 -0
  581. package/src/runtime/control-plane/release-retention.ts +154 -26
  582. package/src/runtime/control-plane/repository-namespace-retention.ts +208 -0
  583. package/src/runtime/control-plane/runtime-cleanup.ts +844 -38
  584. package/src/runtime/control-plane/runtime-generation.ts +6 -0
  585. package/src/runtime/control-plane/workspace/project-onboarding.ts +80 -0
  586. package/src/runtime/control-plane/workspace/semantic-sync-service.ts +479 -0
  587. package/src/runtime/control-plane/workspace/workspace-store.ts +249 -0
  588. package/src/runtime/diagnostics/incident-repair.ts +573 -0
  589. package/src/runtime/diagnostics/mcp-timing.ts +239 -6
  590. package/src/runtime/diagnostics/performance.ts +6 -14
  591. package/src/runtime/diagnostics/read-only-tool.ts +1 -1
  592. package/src/runtime/evidence/artifact-store.ts +216 -35
  593. package/src/runtime/evidence/evidence-store.ts +112 -8
  594. package/src/runtime/evidence/operational-shadow.ts +38 -0
  595. package/src/runtime/evidence/output-handle-index.ts +225 -0
  596. package/src/runtime/evidence/process-check-receipt.ts +5 -43
  597. package/src/runtime/evidence/result-store.ts +158 -44
  598. package/src/runtime/evidence/sensitive-output.ts +4 -4
  599. package/src/runtime/execution/jobs/receipt-recovery.ts +1 -1
  600. package/src/runtime/execution/jobs/store.ts +124 -6
  601. package/src/runtime/execution/managed-workspace.ts +112 -5
  602. package/src/runtime/execution/process-runtime/canary.ts +19 -5
  603. package/src/runtime/execution/process-runtime/check-classification.ts +48 -0
  604. package/src/runtime/execution/process-runtime/check-facade.ts +24 -10
  605. package/src/runtime/execution/process-runtime/check-receipt.ts +1 -1
  606. package/src/runtime/execution/process-runtime/check-result-retention.ts +132 -0
  607. package/src/runtime/execution/process-runtime/check-result.ts +177 -2
  608. package/src/runtime/execution/process-runtime/check-runner-sidecar.ts +58 -9
  609. package/src/runtime/execution/process-runtime/check-storage.ts +187 -0
  610. package/src/runtime/execution/process-runtime/command-facade.ts +117 -114
  611. package/src/runtime/execution/process-runtime/gc.ts +15 -2
  612. package/src/runtime/execution/process-runtime/handle-index.ts +176 -0
  613. package/src/runtime/execution/process-runtime/host-command-lane.ts +139 -0
  614. package/src/runtime/execution/process-runtime/index.ts +4 -0
  615. package/src/runtime/execution/process-runtime/interactive-admission.ts +2 -1
  616. package/src/runtime/execution/process-runtime/lightweight-managed.ts +283 -73
  617. package/src/runtime/execution/process-runtime/persisted-check.ts +130 -23
  618. package/src/runtime/execution/process-runtime/process-runner-entry.ts +47 -5
  619. package/src/runtime/execution/process-runtime/process-scope.ts +160 -0
  620. package/src/runtime/execution/process-runtime/resource-claims.ts +125 -64
  621. package/src/runtime/execution/process-runtime/runtime.ts +167 -17
  622. package/src/runtime/execution/process-runtime/store.ts +30 -2
  623. package/src/runtime/execution/process-runtime/types.ts +27 -0
  624. package/src/runtime/execution/workers/executor.ts +18 -19
  625. package/src/runtime/execution/workers/worker-entry.ts +1 -1
  626. package/src/runtime/gateway/mcp/execution-tools.ts +2 -207
  627. package/src/runtime/gateway/mcp/legacy-ios-tool-adapter.ts +2 -61
  628. package/src/runtime/gateway/mcp/persisted-check-process.ts +2 -3
  629. package/src/runtime/gateway/mcp/process-tools.ts +2 -289
  630. package/src/runtime/gateway/mcp/router.ts +2 -1125
  631. package/src/runtime/gateway/mcp/runtime-tool-definitions.ts +2 -565
  632. package/src/runtime/gateway/mcp/runtime-tools.ts +2 -6655
  633. package/src/runtime/gateway/mcp/work-validation-reconciler.ts +2 -1
  634. package/src/runtime/maintenance/cleanup.ts +38 -24
  635. package/src/runtime/platform/browser-product-discovery.ts +174 -0
  636. package/src/runtime/platform/computer-platform.ts +14 -0
  637. package/src/runtime/platform/executable-discovery.ts +54 -0
  638. package/src/runtime/platform/fetch-http-server.ts +90 -0
  639. package/src/runtime/platform/service-inventory.ts +130 -0
  640. package/src/runtime/platform/service-manager.ts +146 -0
  641. package/src/runtime/platform/windows-host-discovery.ts +118 -0
  642. package/src/runtime/platform/windows-recovery-deployment.ts +67 -0
  643. package/src/runtime/plugins/action-application.ts +192 -0
  644. package/src/runtime/plugins/app-store-connect-adapter.ts +47 -35
  645. package/src/runtime/plugins/browser-adapter.ts +898 -135
  646. package/src/runtime/plugins/browser-automation-service.ts +33 -34
  647. package/src/runtime/plugins/browser-macos-bridge.ts +386 -46
  648. package/src/runtime/plugins/browser-manifest-surface.ts +75 -17
  649. package/src/runtime/plugins/browser-native-session-service.ts +64 -14
  650. package/src/runtime/plugins/browser-provider-registry.ts +2 -109
  651. package/src/runtime/plugins/browser-registration.ts +32 -0
  652. package/src/runtime/plugins/browser-runtime-contract.ts +2 -154
  653. package/src/runtime/plugins/browser-runtime.ts +55 -10
  654. package/src/runtime/plugins/browser-session-authority.ts +101 -291
  655. package/src/runtime/plugins/browser-session-legacy-migration.ts +203 -0
  656. package/src/runtime/plugins/browser-session-store.ts +243 -80
  657. package/src/runtime/plugins/browser-session-types.ts +2 -98
  658. package/src/runtime/plugins/capability-authorization-grants.ts +272 -59
  659. package/src/runtime/plugins/catalog-trust.ts +82 -0
  660. package/src/runtime/plugins/computer-chatgpt-browser-adapter-installer.ts +219 -0
  661. package/src/runtime/plugins/computer-chatgpt-macos-target.ts +891 -0
  662. package/src/runtime/plugins/computer-registration.ts +1050 -0
  663. package/src/runtime/plugins/config-store.ts +119 -0
  664. package/src/runtime/plugins/desktop-operator-external-policy.ts +964 -0
  665. package/src/runtime/plugins/desktop-operator-registration.ts +123 -12
  666. package/src/runtime/plugins/errors.ts +8 -1
  667. package/src/runtime/plugins/external-adapter.ts +82 -323
  668. package/src/runtime/plugins/external-provider-policy.ts +48 -0
  669. package/src/runtime/plugins/external-registration.ts +30 -2
  670. package/src/runtime/plugins/external-unix-socket-probe.cjs +9 -3
  671. package/src/runtime/plugins/external-unix-socket.ts +64 -193
  672. package/src/runtime/plugins/first-party-external-registration.ts +163 -0
  673. package/src/runtime/plugins/first-party-registry.ts +3 -1
  674. package/src/runtime/plugins/github-adapter.ts +1 -2
  675. package/src/runtime/plugins/gmail-adapter.ts +29 -8
  676. package/src/runtime/plugins/google-calendar-adapter.ts +8 -8
  677. package/src/runtime/plugins/google-shared.ts +45 -53
  678. package/src/runtime/plugins/google-tasks-adapter.ts +8 -8
  679. package/src/runtime/plugins/ios-adapter.ts +2 -3
  680. package/src/runtime/plugins/lightweight-action.ts +208 -2
  681. package/src/runtime/plugins/local-system-adapter.ts +192 -2
  682. package/src/runtime/plugins/macos-capability-broker.ts +15 -105
  683. package/src/runtime/plugins/managed-process-adapter.ts +12 -5
  684. package/src/runtime/plugins/plugin-action-sidecar.ts +17 -13
  685. package/src/runtime/plugins/plugin-management-adapter.ts +1 -1
  686. package/src/runtime/plugins/resend-adapter.ts +15 -24
  687. package/src/runtime/plugins/store.ts +1003 -387
  688. package/src/runtime/plugins/types.ts +28 -1
  689. package/src/runtime/plugins/uu-remote-rescue-registration.ts +155 -0
  690. package/src/runtime/plugins/windows-host-recovery-install.ts +68 -0
  691. package/src/runtime/plugins/windows-host-recovery-registration.ts +85 -0
  692. package/src/runtime/plugins/xiaohongshu-publish.ts +102 -430
  693. package/src/runtime/projections/controller-context.ts +12 -6
  694. package/src/runtime/projections/git-status-sampler.ts +73 -22
  695. package/src/runtime/projections/invalidation.ts +7 -3
  696. package/src/runtime/projections/materialized-view.ts +93 -43
  697. package/src/runtime/recovery/actions.ts +3 -3
  698. package/src/runtime/recovery/capability-action-application.ts +229 -0
  699. package/src/runtime/recovery/index.ts +3 -0
  700. package/src/runtime/recovery/lifecycle-inventory.ts +338 -0
  701. package/src/runtime/recovery/local-jobs-repair.ts +14 -14
  702. package/src/runtime/recovery/maintenance-executor.ts +701 -168
  703. package/src/runtime/recovery/quarantine-retention.ts +256 -0
  704. package/src/runtime/recovery/store.ts +29 -11
  705. package/src/runtime/release/identity.ts +6 -0
  706. package/src/runtime/release/release-coordinator.ts +296 -0
  707. package/src/runtime/release/release-session.ts +716 -0
  708. package/src/runtime/release/release-state-migration.ts +25 -0
  709. package/src/runtime/resources/leases/store.ts +56 -25
  710. package/src/runtime/root/active-execution-power-assertion.ts +139 -0
  711. package/src/runtime/root/assistant-learning-loop.ts +45 -0
  712. package/src/runtime/root/browser-session-composition.ts +59 -0
  713. package/src/runtime/root/computer-composition.ts +376 -0
  714. package/src/runtime/root/computer-target-composition.ts +16 -0
  715. package/src/runtime/root/computer-target-persistence.ts +39 -0
  716. package/src/runtime/root/controller-progression-composition.ts +192 -0
  717. package/src/runtime/root/controller-round-composition.ts +126 -0
  718. package/src/runtime/root/controller-services.ts +2 -0
  719. package/src/runtime/root/deployment-topology.ts +106 -0
  720. package/src/runtime/root/entry.ts +8 -6
  721. package/src/runtime/root/gateway-adapter.ts +3 -3
  722. package/src/runtime/root/known-good-recovery.ts +184 -0
  723. package/src/runtime/root/local-bridge.ts +5 -3
  724. package/src/runtime/root/mcp-transport.ts +116 -23
  725. package/src/runtime/root/ownership.ts +261 -9
  726. package/src/runtime/root/package-connector-service.ts +212 -74
  727. package/src/runtime/root/package-runtime-release.ts +199 -33
  728. package/src/runtime/root/package-runtime-service.ts +77 -108
  729. package/src/runtime/root/release-execution-canary.ts +103 -0
  730. package/src/runtime/root/release-loader.ts +150 -0
  731. package/src/runtime/root/release-manifest.ts +185 -7
  732. package/src/runtime/root/release-materialize.ts +474 -31
  733. package/src/runtime/root/release-store.ts +425 -37
  734. package/src/runtime/root/runtime-lane.ts +191 -0
  735. package/src/runtime/root/runtime.ts +379 -32
  736. package/src/runtime/root/scheduled-controller-composition.ts +76 -0
  737. package/src/runtime/root/scheduler.ts +12 -4
  738. package/src/runtime/root/service-runner.ts +3 -3
  739. package/src/runtime/root/service.ts +73 -45
  740. package/src/runtime/root/status.ts +49 -0
  741. package/src/runtime/root/types.ts +55 -3
  742. package/src/runtime/root/workflow-supervisor-composition.ts +493 -0
  743. package/src/runtime/root/workflow-supervisor-runtime.ts +209 -0
  744. package/src/runtime/root/write-fence.ts +50 -2
  745. package/src/runtime/safe-tooling/google-credential-store.ts +76 -21
  746. package/src/runtime/safe-tooling/google-oauth-broker.ts +25 -7
  747. package/src/runtime/safe-tooling/workspace-auth.ts +1 -1
  748. package/src/runtime/shared/bounded-child-supervisor.ts +9 -1
  749. package/src/runtime/shared/local-bridge-surface.ts +1 -1
  750. package/src/runtime/shared/process-environment.ts +36 -10
  751. package/src/runtime/shared/response-budget.ts +1 -3
  752. package/src/runtime/shared/storage-capacity.ts +68 -0
  753. package/src/runtime/standalone-recovery/controller-home-migration.ts +1108 -0
  754. package/src/runtime/standalone-recovery/core.ts +4609 -495
  755. package/src/runtime/standalone-recovery/entry.ts +642 -81
  756. package/src/runtime/standalone-recovery/independent-host-rescue.ts +172 -0
  757. package/src/runtime/standalone-recovery/installer.ts +399 -177
  758. package/src/runtime/standalone-recovery/mcp-server.ts +79 -0
  759. package/src/runtime/standalone-recovery/mutation-identity-contract.ts +21 -0
  760. package/src/runtime/standalone-recovery/operation-lock.ts +160 -0
  761. package/src/runtime/standalone-recovery/performance.ts +173 -0
  762. package/src/runtime/standalone-recovery/release.ts +58 -5
  763. package/src/runtime/standalone-recovery/service-labels.ts +5 -2
  764. package/src/runtime/standalone-recovery/watchdog-heartbeat.ts +5 -2
  765. package/src/runtime/watchdog/workflow-watchdog.ts +1 -1
  766. package/src/runtime/workflow/schedules/browser-probe.ts +17 -6
  767. package/src/runtime/workflow/schedules/chatgpt-automation-migration.ts +11 -4
  768. package/src/runtime/workflow/schedules/engine.ts +298 -484
  769. package/src/runtime/workflow/schedules/pending-activation.ts +1 -1
  770. package/src/runtime/workflow/schedules/settlement.ts +2 -191
  771. package/src/runtime/workflow/schedules/store.ts +2 -607
  772. package/src/runtime/workflow/schedules/types.ts +2 -127
  773. package/src/runtime/workflow/schedules/work-continuation.ts +220 -16
  774. package/src/runtime/workflows/first-party/xiaohongshu.ts +122 -0
  775. package/src/runtime/workflows/runtime.ts +482 -0
  776. package/src/testing/test-governance.ts +95 -30
  777. package/supervisor/chatgpt-conversation.ts +23 -0
  778. package/supervisor/client.ts +201 -0
  779. package/supervisor/control-plane.ts +868 -0
  780. package/supervisor/entry.ts +15 -0
  781. package/supervisor/forge-validators.ts +80 -0
  782. package/supervisor/index.ts +5 -0
  783. package/supervisor/native-browser-adapter.ts +786 -0
  784. package/supervisor/native-messaging/host.ts +39 -0
  785. package/supervisor/native-messaging/manifest.ts +26 -0
  786. package/supervisor/native-messaging/protocol.ts +27 -0
  787. package/supervisor/paths.ts +18 -0
  788. package/supervisor/protocol.ts +202 -0
  789. package/supervisor/server.ts +404 -0
  790. package/supervisor/store.ts +1451 -0
  791. package/supervisor/tsconfig.json +8 -0
  792. package/supervisor/types.ts +255 -0
  793. package/assets/templates/helpers/archive-architecture-request.sh +0 -244
  794. package/docs/architecture/history/README.md +0 -7
  795. package/docs/architecture/history/chatgpt-handoff-facade.md +0 -397
  796. package/docs/architecture/history/global-hook-runtime.md +0 -166
  797. package/docs/architecture/history/ios-semantic-automation-provider-v2.md +0 -170
  798. package/docs/architecture/requests/archive/2026/20260528-154740-ai-hooks-ai-hooks-hook-input-sh.md +0 -59
  799. package/docs/architecture/requests/archive/2026/20260528-154816-assets-hooks-assets-hooks-hook-input-sh.md +0 -59
  800. package/docs/architecture/requests/archive/2026/20260528-161851-ai-harness-workflow-contract-json-ai-harness-workflow-contract-json.md +0 -59
  801. package/docs/architecture/requests/archive/2026/20260528-161853-scripts-check-task-workflow-sh-scripts-check-task-workflow-sh.md +0 -59
  802. package/docs/architecture/requests/archive/2026/20260528-161911-assets-workflow-contract-v1-json-assets-workflow-contract-v1-json.md +0 -59
  803. package/docs/architecture/requests/archive/2026/20260528-222416-ai-hooks-ai-hooks-hook-input-sh.md +0 -59
  804. package/docs/architecture/requests/archive/2026/20260528-222444-ai-hooks-ai-hooks-pre-edit-guard-sh.md +0 -59
  805. package/docs/architecture/requests/archive/2026/20260528-222457-ai-hooks-ai-hooks-pre-edit-guard-sh.md +0 -59
  806. package/docs/architecture/requests/archive/2026/20260528-222648-ai-hooks-ai-hooks-pre-edit-guard-sh.md +0 -59
  807. package/docs/architecture/requests/archive/2026/20260528-222705-ai-hooks-ai-hooks-worktree-guard-sh.md +0 -59
  808. package/docs/architecture/requests/archive/2026/20260528-222726-ai-hooks-ai-hooks-prompt-guard-sh.md +0 -59
  809. package/docs/architecture/requests/archive/2026/20260528-222727-ai-hooks-ai-hooks-prompt-guard-sh.md +0 -59
  810. package/docs/architecture/requests/archive/2026/20260528-224736-ai-hooks-ai-hooks-hook-input-sh.md +0 -59
  811. package/docs/architecture/requests/archive/2026/20260528-233259-ai-hooks-ai-hooks-prompt-guard-sh.md +0 -59
  812. package/docs/architecture/requests/archive/2026/20260528-233335-assets-hooks-assets-hooks-prompt-guard-sh.md +0 -59
  813. package/docs/architecture/requests/archive/2026/20260528-233456-ai-hooks-ai-hooks-prompt-guard-sh.md +0 -59
  814. package/docs/architecture/requests/archive/2026/20260528-233457-assets-hooks-assets-hooks-prompt-guard-sh.md +0 -59
  815. package/docs/architecture/requests/archive/2026/20260528-233637-ai-hooks-ai-hooks-prompt-guard-sh.md +0 -59
  816. package/docs/architecture/requests/archive/2026/20260528-233638-assets-hooks-assets-hooks-prompt-guard-sh.md +0 -59
  817. package/docs/architecture/requests/archive/2026/20260529-000322-root-package-json.md +0 -59
  818. package/docs/architecture/requests/archive/2026/20260529-004238-ai-hooks-ai-hooks-lib-workflow-state-sh.md +0 -59
  819. package/docs/architecture/requests/archive/2026/20260529-020654-ai-harness-policy-json-ai-harness-policy-json.md +0 -63
  820. package/docs/architecture/requests/archive/2026/20260529-094236-ai-hooks-ai-hooks-prompt-guard-sh.md +0 -60
  821. package/docs/architecture/requests/archive/2026/20260529-094323-assets-hooks-assets-hooks-prompt-guard-sh.md +0 -60
  822. package/docs/architecture/requests/archive/2026/20260529-094331-ai-hooks-ai-hooks-prompt-guard-sh.md +0 -60
  823. package/docs/architecture/requests/archive/2026/20260529-094339-assets-hooks-assets-hooks-prompt-guard-sh.md +0 -60
  824. package/docs/architecture/requests/archive/2026/20260529-094430-assets-hooks-assets-hooks-session-start-context-sh.md +0 -60
  825. package/docs/architecture/requests/archive/2026/20260529-094446-ai-hooks-ai-hooks-session-start-context-sh.md +0 -60
  826. package/docs/architecture/requests/archive/2026/20260613-002040-runtime-harness-hook-adapters.md +0 -68
  827. package/docs/architecture/requests/archive/2026/root.md +0 -68
  828. package/docs/architecture/requests/archive/2026/runtime-harness-hook-adapters.md +0 -76
  829. package/docs/architecture/requests/archive/2026/verification-evals-checks.md +0 -68
  830. package/docs/architecture/requests/archive/2026/workflow-engine-contract-assets.md +0 -69
  831. package/scripts/archive-architecture-request.sh +0 -4
  832. package/scripts/benchmark-background-check-overlap.ts +0 -228
  833. package/scripts/benchmark-controller-hotpath.ts +0 -212
  834. package/scripts/benchmark-controller-round2.ts +0 -139
  835. package/scripts/benchmark-ios-agent-device.ts +0 -514
  836. package/scripts/benchmark-mcp-host.sh +0 -117
  837. package/scripts/benchmark-mcp-transport.ts +0 -170
  838. package/scripts/benchmark-quality-harness.ts +0 -146
  839. package/scripts/benchmark-route-session-concurrency.ts +0 -915
  840. package/scripts/benchmark-thin-harness-gateway-ab.ts +0 -632
  841. package/scripts/benchmark-thin-harness-mcp-e2e.ts +0 -498
  842. package/scripts/benchmark-thin-harness.ts +0 -251
  843. package/scripts/benchmark-typescript-navigation.ts +0 -186
  844. package/scripts/benchmark-work-efficiency.ts +0 -334
  845. package/scripts/build-controller-ui.ts +0 -28
  846. package/scripts/check-npm-release.sh +0 -32
  847. package/scripts/check-public-release-surface.sh +0 -19
  848. package/scripts/check-release-published.sh +0 -57
  849. package/scripts/check-release-readiness.sh +0 -37
  850. package/scripts/check-release-version.mjs +0 -74
  851. package/scripts/check-tarball-install-smoke.sh +0 -67
  852. package/scripts/package-source-archive.sh +0 -147
  853. package/scripts/public-release-files.txt +0 -39
  854. package/scripts/public-release.ts +0 -174
  855. package/scripts/publish-release-tarball.sh +0 -27
  856. package/scripts/route-nl-vs-ts-eval.ts +0 -679
  857. package/scripts/run-skill-evals.ts +0 -1022
  858. package/scripts/stage-runtime-release.ts +0 -39
  859. package/src/cli/controller/progress.ts +0 -656
  860. package/src/cli/controller/work-mode.ts +0 -181
  861. package/src/cli/local-bridge/console-assets.ts +0 -17
  862. package/src/cli/local-bridge/dashboard.ts +0 -17
  863. package/src/cli/local-bridge/frontend/src/App.tsx +0 -10
  864. package/src/cli/local-bridge/frontend/src/components/Button.tsx +0 -1
  865. package/src/cli/local-bridge/frontend/src/components/DetailPane.tsx +0 -3
  866. package/src/cli/local-bridge/frontend/src/components/SearchField.tsx +0 -1
  867. package/src/cli/local-bridge/frontend/src/components/SectionHeader.tsx +0 -1
  868. package/src/cli/local-bridge/frontend/src/components/Segmented.tsx +0 -1
  869. package/src/cli/local-bridge/frontend/src/components/StatusText.tsx +0 -3
  870. package/src/cli/local-bridge/frontend/src/design/icons.tsx +0 -11
  871. package/src/cli/local-bridge/frontend/src/design/tokens.css +0 -8
  872. package/src/cli/local-bridge/frontend/src/features/automations/AutomationsView.tsx +0 -153
  873. package/src/cli/local-bridge/frontend/src/features/capabilities/CapabilitiesView.tsx +0 -37
  874. package/src/cli/local-bridge/frontend/src/features/overview/OverviewView.tsx +0 -183
  875. package/src/cli/local-bridge/frontend/src/features/repositories/RepositoriesView.tsx +0 -2
  876. package/src/cli/local-bridge/frontend/src/features/system/SystemView.tsx +0 -2
  877. package/src/cli/local-bridge/frontend/src/features/work/WorkView.tsx +0 -4
  878. package/src/cli/local-bridge/frontend/src/lib/api.ts +0 -30
  879. package/src/cli/local-bridge/frontend/src/lib/format.ts +0 -4
  880. package/src/cli/local-bridge/frontend/src/lib/routes.ts +0 -7
  881. package/src/cli/local-bridge/frontend/src/main.tsx +0 -1
  882. package/src/cli/local-bridge/frontend/src/shell/AppShell.tsx +0 -1
  883. package/src/cli/local-bridge/frontend/src/shell/CommandBar.tsx +0 -2
  884. package/src/cli/local-bridge/frontend/src/shell/Sidebar.tsx +0 -4
  885. package/src/cli/local-bridge/frontend/src/styles.css +0 -28
  886. package/src/cli/local-bridge/frontend/src/types.ts +0 -15
  887. package/src/cli/local-bridge/frontend/src/vite-env.d.ts +0 -1
  888. package/src/cli/local-bridge/frontend/vite.config.ts +0 -27
  889. package/src/cli/local-bridge/ui-dist/app.css +0 -1
  890. package/src/cli/local-bridge/ui-dist/app.js +0 -11228
  891. package/src/runtime/control-plane/execution/direct-edit-work-completion.ts +0 -385
  892. package/src/runtime/control-plane/execution/work-finalization-service.ts +0 -1913
  893. package/src/runtime/control-plane/execution/work-path-scope.ts +0 -37
  894. package/src/runtime/control-plane/execution/work-task-receipt.ts +0 -449
  895. package/src/runtime/control-plane/facade/controller-round-relay.ts +0 -1118
  896. package/src/runtime/control-plane/facade/work-admission-policy.ts +0 -93
  897. package/src/runtime/control-plane/facade/work-task-projection.ts +0 -66
  898. package/src/runtime/control-plane/routing/index.ts +0 -1
  899. package/src/runtime/control-plane/routing/route-policy.ts +0 -382
  900. package/src/runtime/control-plane/routing/workspace-admission.ts +0 -70
@@ -0,0 +1,786 @@
1
+ import { randomUUID } from 'node:crypto';
2
+ import type {
3
+ ComputerChatgptConversationIdentity,
4
+ ComputerChatgptConversationObservation,
5
+ ComputerChatgptConversationTarget,
6
+ ComputerChatgptConversationTargetPort,
7
+ } from '../packages/plugin-runtime/computer';
8
+ import {
9
+ CHATGPT_AUTOMATION_RATE_LIMITED,
10
+ CHATGPT_AUTOMATION_CONVERSATION_LIMIT_REACHED,
11
+ chatgptProviderBackpressureRemainingMs,
12
+ chatgptProviderPageFailure,
13
+ noteChatgptProviderBackpressure,
14
+ withChatgptProviderDispatchLane,
15
+ } from '../adapters/chatgpt/provider-delivery';
16
+ import { parseChatgptConversationIdentity } from './chatgpt-conversation';
17
+ import { WorkflowSupervisorControlPlane } from './control-plane';
18
+ import { hasCommittedSupervisorEnvelope, renderEffectMarker, sha256 } from './protocol';
19
+ import type { WorkflowSupervisorEphemeralDiscovery } from './server';
20
+ import type {
21
+ WorkflowSupervisorBrowserCommand,
22
+ WorkflowSupervisorBrowserTask,
23
+ WorkflowSupervisorConsumerStatus,
24
+ } from './types';
25
+
26
+ const DEFAULT_INTERVAL_MS = 1_000;
27
+ const IDLE_INTERVAL_MS = 5_000;
28
+ const MAX_TRANSPORT_BACKOFF_MS = 60_000;
29
+ const MAX_TRANSPORT_BACKOFF_STEPS = 6;
30
+ const MAX_LOCAL_OBSERVATION_ATTEMPTS = 3;
31
+ const USER_VISIBLE_DEGRADED_AFTER_MS = 30_000;
32
+ /**
33
+ * A task-local target/conversation failure must space its *own* retries. The
34
+ * exact conversation is a provider resource: re-navigating or replacing its tab
35
+ * on every tick is what produced conversation-read 429s, and a 429 is answered
36
+ * by sending fewer requests, never by opening another conversation.
37
+ *
38
+ * Only failures about *this exact conversation or target* are spaced here.
39
+ * Provider-wide unavailability already backs off the whole consumer, so spacing
40
+ * it again would delay a legitimate resume without reducing any request volume.
41
+ * A new exact-conversation failure code must be added to this mechanical
42
+ * retry-spacing classification.
43
+ */
44
+ const TASK_TARGET_RETRY_BASE_MS = 30_000;
45
+ /** Slow read-only probe cadence for an applied turn whose bounded resume is exhausted. */
46
+ const AWAITING_RECEIPT_OBSERVATION_MS = 60_000;
47
+ const TASK_TARGET_RETRY_MAX_MS = 10 * 60_000;
48
+ // Preparation may inspect/change a local draft, but never sends to ChatGPT.
49
+ // Stop after bounded unsuccessful preflights; an unchanged failing provider
50
+ // must not become either an infinite UI loop or a spent send generation.
51
+ const SUPERVISOR_PRE_SEND_BLOCKED = 'WORKFLOW_SUPERVISOR_PRE_SEND_BLOCKED';
52
+
53
+ export const TASK_TARGET_SPACED_FAILURE_CODES: ReadonlySet<string> = new Set([
54
+ 'COMPUTER_CHATGPT_CONVERSATION_CONTENT_UNAVAILABLE',
55
+ // Desktop Operator has already bounded and reaped the Apple Events holder.
56
+ // Space this task's next native attempt instead of immediately recontending
57
+ // the one global browser lane on another Supervisor tick.
58
+ 'BROWSER_AUTOMATION_TIMEOUT',
59
+ 'BROWSER_AUTOMATION_SERIALIZATION_BUSY',
60
+ 'WORKFLOW_SUPERVISOR_EXACT_CONVERSATION_UNPROVEN',
61
+ 'COMPUTER_CHATGPT_EXACT_TARGET_UNPROVEN',
62
+ 'COMPUTER_CHATGPT_EXACT_TARGET_AMBIGUOUS',
63
+ 'COMPUTER_CHATGPT_EXTENSION_EXACT_TARGET_AMBIGUOUS',
64
+ 'COMPUTER_CHATGPT_RESTORED_TARGET_UNPROVEN',
65
+ 'COMPUTER_CHATGPT_TARGET_RESTORE_FAILED',
66
+ 'COMPUTER_CHATGPT_BOOTSTRAP_TARGET_UNAVAILABLE',
67
+ 'COMPUTER_CHATGPT_EXTENSION_TARGET_OPEN_OUTCOME_UNKNOWN',
68
+ 'COMPUTER_CHATGPT_EXTENSION_BOOTSTRAP_OPEN_OUTCOME_UNKNOWN',
69
+ SUPERVISOR_PRE_SEND_BLOCKED,
70
+ 'WORKFLOW_SUPERVISOR_BOOTSTRAP_EXISTING_CONVERSATION',
71
+ ]);
72
+ function taskTargetRetryDelayMs(streak: number): number {
73
+ const exponent = Math.max(0, Math.min(6, Math.trunc(streak) - 1));
74
+ return Math.min(TASK_TARGET_RETRY_MAX_MS, TASK_TARGET_RETRY_BASE_MS * 2 ** exponent);
75
+ }
76
+
77
+ type ObservedConversation = {
78
+ conversation_id: string;
79
+ canonical_url: string;
80
+ title?: string;
81
+ projectTitle?: string;
82
+ projectUrl?: string;
83
+ is_current?: boolean;
84
+ };
85
+
86
+ type TaskTransportFailure = {
87
+ code: string;
88
+ observedAtMs: number;
89
+ firstFailureAtMs: number;
90
+ effectId?: string;
91
+ projectionVisible: boolean;
92
+ /** Consecutive identical failures; drives this task's own retry spacing. */
93
+ streak: number;
94
+ };
95
+
96
+ export interface WorkflowSupervisorTransportProjection {
97
+ taskId?: string;
98
+ effectId?: string;
99
+ state: 'degraded' | 'recovered';
100
+ code?: string;
101
+ firstFailureAt?: string;
102
+ observedAt: string;
103
+ }
104
+
105
+ export interface WorkflowSupervisorStallProjection {
106
+ taskId: string;
107
+ effectId: string;
108
+ state: 'exhausted' | 'recovered';
109
+ stallKind: 'retryable' | 'provider_resume_exhausted';
110
+ generations?: number;
111
+ maxGenerations?: number;
112
+ observedAt: string;
113
+ }
114
+
115
+ export interface WorkflowSupervisorComputerBrowserDependencies {
116
+ targetPort: ComputerChatgptConversationTargetPort;
117
+ nowMs(): number;
118
+ providerIdleGraceMs: number;
119
+ providerScopeKey: string;
120
+ sleep(ms: number): Promise<void>;
121
+ setInterval(handler: () => void, ms: number): ReturnType<typeof setInterval>;
122
+ clearInterval(timer: ReturnType<typeof setInterval>): void;
123
+ onError(error: unknown): void;
124
+ reportTransportState?(projection: WorkflowSupervisorTransportProjection): void;
125
+ reportTaskStall?(projection: WorkflowSupervisorStallProjection): void;
126
+ requestHumanAction?(input: {
127
+ taskId: string;
128
+ effectId?: string;
129
+ action: 'login' | 'grant_permission';
130
+ code: string;
131
+ }): void;
132
+ }
133
+
134
+ export interface WorkflowSupervisorNativeBrowserHandle {
135
+ readonly adapter: WorkflowSupervisorNativeBrowserAdapter;
136
+ status(): WorkflowSupervisorConsumerStatus;
137
+ close(): Promise<void>;
138
+ }
139
+
140
+ function normalize(value: string): string { return value.replace(/\s+/g, ' ').trim(); }
141
+ function localObservationDelayMs(completedAttempts: number, baseMs: number, maxMs: number): number {
142
+ const exponent = Math.max(0, Math.min(8, Math.trunc(completedAttempts) - 1));
143
+ return Math.min(maxMs, baseMs * 2 ** exponent);
144
+ }
145
+ function consumerFailureCode(error: unknown, fallback: string): string {
146
+ const message = error instanceof Error ? error.message : String(error);
147
+ const candidate = message.split(':', 1)[0]?.trim() ?? '';
148
+ return /^[A-Z][A-Z0-9_]+$/.test(candidate) ? candidate : fallback;
149
+ }
150
+ function isoTime(value: number | undefined): string | undefined {
151
+ return value === undefined ? undefined : new Date(value).toISOString();
152
+ }
153
+ function targetMarkerPresent(text: string, effectId: string): boolean { return text.includes(renderEffectMarker(effectId)); }
154
+ function snapshotTargetMarkerPresent(snapshot: ComputerChatgptConversationObservation, effectId: string): boolean {
155
+ return targetMarkerPresent(snapshot.latestUserText, effectId)
156
+ || snapshot.userMessages?.some((message) => targetMarkerPresent(message, effectId)) === true;
157
+ }
158
+ function unknownObservationFingerprint(effectId: string, reason: string, snapshot: ComputerChatgptConversationObservation): string {
159
+ return sha256(JSON.stringify({
160
+ effectId,
161
+ reason,
162
+ url: snapshot.url,
163
+ latestUserText: normalize(snapshot.latestUserText),
164
+ latestAssistantResponse: normalize(snapshot.latestAssistantResponse),
165
+ composerText: snapshot.composerText === undefined ? null : normalize(snapshot.composerText),
166
+ latestTurnRole: snapshot.latestTurnRole ?? null,
167
+ isGenerating: snapshot.isGenerating,
168
+ }));
169
+ }
170
+ function exactConversation(snapshot: ComputerChatgptConversationObservation, task: WorkflowSupervisorBrowserTask): boolean {
171
+ try { return parseChatgptConversationIdentity(snapshot.url).conversationId === task.conversationId; }
172
+ catch { return false; }
173
+ }
174
+ function identityForTask(task: WorkflowSupervisorBrowserTask): ComputerChatgptConversationIdentity {
175
+ const parsed = parseChatgptConversationIdentity(task.conversationUrl);
176
+ if (parsed.conversationId !== task.conversationId) throw new Error('WORKFLOW_SUPERVISOR_CONVERSATION_IDENTITY_MISMATCH');
177
+ return { namespace: 'chatgpt.conversation', conversationId: parsed.conversationId, canonicalUrl: parsed.canonicalUrl };
178
+ }
179
+ function conversationContentAvailable(snapshot: ComputerChatgptConversationObservation): boolean {
180
+ // Navigation can commit the exact URL before ChatGPT loads the conversation.
181
+ // An empty/error shell is transport evidence, never evidence about a send or
182
+ // about whether the model stopped working.
183
+ return snapshot.composerText !== undefined || snapshot.isGenerating
184
+ || Boolean(snapshot.latestUserText.trim() || snapshot.latestAssistantResponse.trim() || snapshot.providerActivityText.trim());
185
+ }
186
+ function projectMetadataFromConversationUrl(value: string): { projectTitle?: string; projectUrl?: string } {
187
+ try {
188
+ const parsed = new URL(value);
189
+ const match = /^\/g\/(g-p-[a-z0-9]+)(?:-([^/]+))?\/c\/[a-z0-9-]+\/?$/i.exec(parsed.pathname);
190
+ if (!match?.[1]) return {};
191
+ const slug = match[2]?.trim();
192
+ return {
193
+ ...(slug ? { projectTitle: slug.replace(/[-_]+/g, ' ').replace(/\s+/g, ' ').trim() } : {}),
194
+ projectUrl: `https://chatgpt.com/g/${match[1]}/project`,
195
+ };
196
+ } catch { return {}; }
197
+ }
198
+
199
+ export class WorkflowSupervisorNativeBrowserAdapter {
200
+ private readonly observedAssistant = new Map<string, string>();
201
+ private readonly providerFailureSeen = new Map<string, string>();
202
+ /** A recovery sent while an error surface is still visible must not inherit that stale error as its own failure. */
203
+ private readonly providerFailureAwaitingClear = new Map<string, string>();
204
+ private readonly freshSendCheckedAt = new Map<string, number>();
205
+ private timer?: ReturnType<typeof setInterval>;
206
+ private inflight?: Promise<void>;
207
+ private closed = false;
208
+ private nextRunAtMs = 0;
209
+ private lastRunHadTasks = false;
210
+ private lastRunTransportUnavailable = false;
211
+ private transportFailureStreak = 0;
212
+ private servicingFreshSend = false;
213
+ private conversations: ObservedConversation[] = [];
214
+ private lastTickStartedAtMs?: number;
215
+ private lastTickCompletedAtMs?: number;
216
+ private lastCommandAttemptAtMs?: number;
217
+ private lastFailure?: { code: string; observedAtMs: number; taskId?: string; effectId?: string };
218
+ private firstTransportFailureAtMs?: number;
219
+ private transportProjectionVisible = false;
220
+ private readonly taskTransportFailures = new Map<string, TaskTransportFailure>();
221
+ /** Derived projection cache only; Supervisor store remains the stall authority. */
222
+ private readonly projectedTaskStalls = new Map<string, Omit<WorkflowSupervisorStallProjection, 'taskId' | 'state' | 'observedAt'>>();
223
+ /** Spacing for read-only observation of a turn whose bounded resume is exhausted. */
224
+ private readonly awaitingReceiptObservedAtMs = new Map<string, number>();
225
+
226
+ constructor(
227
+ private readonly control: WorkflowSupervisorControlPlane,
228
+ private readonly discovery: WorkflowSupervisorEphemeralDiscovery,
229
+ private readonly deps: WorkflowSupervisorComputerBrowserDependencies,
230
+ ) {}
231
+
232
+ private noteFailure(code: string, task?: WorkflowSupervisorBrowserTask, effectId?: string): void {
233
+ const nowMs = this.deps.nowMs();
234
+ this.lastFailure = { code, observedAtMs: nowMs, ...(task ? { taskId: task.taskId } : {}), ...(effectId ? { effectId } : {}) };
235
+ this.firstTransportFailureAtMs ??= nowMs;
236
+ if (!this.transportProjectionVisible && nowMs - this.firstTransportFailureAtMs >= USER_VISIBLE_DEGRADED_AFTER_MS) {
237
+ this.transportProjectionVisible = true;
238
+ this.deps.reportTransportState?.({
239
+ state: 'degraded', code,
240
+ ...(task ? { taskId: task.taskId } : {}), ...(effectId ? { effectId } : {}),
241
+ firstFailureAt: new Date(this.firstTransportFailureAtMs).toISOString(), observedAt: new Date(nowMs).toISOString(),
242
+ });
243
+ }
244
+ }
245
+
246
+ private clearTransportFailure(): void {
247
+ this.lastFailure = undefined;
248
+ if (this.firstTransportFailureAtMs !== undefined) {
249
+ const nowMs = this.deps.nowMs();
250
+ if (this.transportProjectionVisible) this.deps.reportTransportState?.({ state: 'recovered', observedAt: new Date(nowMs).toISOString() });
251
+ this.firstTransportFailureAtMs = undefined;
252
+ this.transportProjectionVisible = false;
253
+ }
254
+ }
255
+
256
+ private noteTaskFailure(code: string, task: WorkflowSupervisorBrowserTask, effectId?: string): void {
257
+ const nowMs = this.deps.nowMs();
258
+ const previous = this.taskTransportFailures.get(task.taskId);
259
+ const failure: TaskTransportFailure = {
260
+ code,
261
+ observedAtMs: nowMs,
262
+ firstFailureAtMs: previous?.code === code ? previous.firstFailureAtMs : nowMs,
263
+ ...(effectId ? { effectId } : previous?.effectId ? { effectId: previous.effectId } : {}),
264
+ projectionVisible: previous?.projectionVisible ?? false,
265
+ // A materially different failure reason is new evidence and restarts the
266
+ // spacing; an unchanged one keeps growing it.
267
+ streak: previous?.code === code ? previous.streak + 1 : 1,
268
+ };
269
+ if (!failure.projectionVisible && nowMs - failure.firstFailureAtMs >= USER_VISIBLE_DEGRADED_AFTER_MS) {
270
+ failure.projectionVisible = true;
271
+ this.deps.reportTransportState?.({
272
+ state: 'degraded', code, taskId: task.taskId,
273
+ ...(failure.effectId ? { effectId: failure.effectId } : {}),
274
+ firstFailureAt: new Date(failure.firstFailureAtMs).toISOString(), observedAt: new Date(nowMs).toISOString(),
275
+ });
276
+ }
277
+ this.taskTransportFailures.set(task.taskId, failure);
278
+ }
279
+
280
+ private clearTaskFailure(taskId: string, effectId?: string): void {
281
+ const failure = this.taskTransportFailures.get(taskId);
282
+ if (!failure) return;
283
+ this.taskTransportFailures.delete(taskId);
284
+ const recoveredEffectId = effectId ?? failure.effectId;
285
+ if (failure.projectionVisible) this.deps.reportTransportState?.({
286
+ state: 'recovered', taskId,
287
+ ...(recoveredEffectId ? { effectId: recoveredEffectId } : {}),
288
+ observedAt: new Date(this.deps.nowMs()).toISOString(),
289
+ });
290
+ }
291
+
292
+ private noteTargetUnavailable(task: WorkflowSupervisorBrowserTask, effectId: string | undefined, failure: { code: string; humanAction?: 'login' | 'grant_permission' }): void {
293
+ // Exact-target failure is task-local. It must not back off unrelated
294
+ // Supervisor conversations; only provider-wide inventory/backpressure does.
295
+ this.noteTaskFailure(failure.code, task, effectId);
296
+ if (failure.humanAction) this.deps.requestHumanAction?.({ taskId: task.taskId, ...(effectId ? { effectId } : {}), action: failure.humanAction, code: failure.code });
297
+ }
298
+
299
+ private syncTaskStallProjections(): void {
300
+ const activeTaskIds = new Set<string>();
301
+ const observedAt = new Date(this.deps.nowMs()).toISOString();
302
+ for (const task of this.control.listTasks(true)) {
303
+ activeTaskIds.add(task.taskId);
304
+ let stall: ReturnType<WorkflowSupervisorControlPlane['taskStall']>;
305
+ try { stall = this.control.taskStall(task.taskId); }
306
+ catch (error) { this.deps.onError(error); continue; }
307
+ if (stall.state === 'retryable' || stall.state === 'provider_resume_exhausted') {
308
+ const next = {
309
+ effectId: stall.effectId,
310
+ stallKind: stall.state,
311
+ ...(stall.state === 'retryable' ? { generations: stall.generations, maxGenerations: stall.maxGenerations } : {}),
312
+ } as Omit<WorkflowSupervisorStallProjection, 'taskId' | 'state' | 'observedAt'>;
313
+ const prior = this.projectedTaskStalls.get(task.taskId);
314
+ const unchanged = prior?.effectId === next.effectId
315
+ && prior.stallKind === next.stallKind
316
+ && prior.generations === next.generations
317
+ && prior.maxGenerations === next.maxGenerations;
318
+ if (!unchanged) {
319
+ try { this.deps.reportTaskStall?.({ taskId: task.taskId, state: 'exhausted', observedAt, ...next }); }
320
+ catch (error) { this.deps.onError(error); }
321
+ this.projectedTaskStalls.set(task.taskId, next);
322
+ }
323
+ continue;
324
+ }
325
+ const prior = this.projectedTaskStalls.get(task.taskId);
326
+ if (prior) {
327
+ try { this.deps.reportTaskStall?.({ taskId: task.taskId, state: 'recovered', observedAt, ...prior }); }
328
+ catch (error) { this.deps.onError(error); }
329
+ this.projectedTaskStalls.delete(task.taskId);
330
+ }
331
+ }
332
+ for (const [taskId, prior] of this.projectedTaskStalls) {
333
+ if (activeTaskIds.has(taskId)) continue;
334
+ try { this.deps.reportTaskStall?.({ taskId, state: 'recovered', observedAt, ...prior }); }
335
+ catch (error) { this.deps.onError(error); }
336
+ this.projectedTaskStalls.delete(taskId);
337
+ }
338
+ }
339
+
340
+ private dueCommand(nowMs: number): WorkflowSupervisorConsumerStatus['dueCommand'] {
341
+ const candidates: NonNullable<WorkflowSupervisorConsumerStatus['dueCommand']>[] = [];
342
+ for (const task of this.control.browserTasks()) {
343
+ try {
344
+ const poll = task.conversationId.startsWith('bootstrap:') ? this.control.bootstrapPoll(task.taskId) : this.control.browserPoll({ conversationId: task.conversationId, conversationUrl: task.conversationUrl });
345
+ const command = poll.command;
346
+ if (!command) continue;
347
+ const effect = this.control.getEffect(command.effectId);
348
+ const createdAtMs = effect?.createdAt ? Date.parse(effect.createdAt) : Number.NaN;
349
+ candidates.push({ taskId: task.taskId, conversationId: task.conversationId, effectId: command.effectId, mode: command.mode, kind: command.kind,
350
+ ...(effect?.createdAt ? { createdAt: effect.createdAt } : {}), ...(Number.isFinite(createdAtMs) ? { ageMs: Math.max(0, nowMs - createdAtMs) } : {}) });
351
+ } catch { /* read projection only */ }
352
+ }
353
+ candidates.sort((left, right) => (right.ageMs ?? -1) - (left.ageMs ?? -1));
354
+ return candidates[0];
355
+ }
356
+
357
+ status(): WorkflowSupervisorConsumerStatus {
358
+ const nowMs = this.deps.nowMs();
359
+ const dueCommand = this.dueCommand(nowMs);
360
+ const dueTaskFailure = dueCommand ? this.taskTransportFailures.get(dueCommand.taskId) : undefined;
361
+ const projectedFailure = dueTaskFailure
362
+ ? { code: dueTaskFailure.code, observedAtMs: dueTaskFailure.observedAtMs, taskId: dueCommand!.taskId, ...(dueTaskFailure.effectId ? { effectId: dueTaskFailure.effectId } : {}) }
363
+ : this.lastFailure;
364
+ const stalled = Boolean(this.inflight && this.lastTickStartedAtMs !== undefined && nowMs - this.lastTickStartedAtMs > MAX_TRANSPORT_BACKOFF_MS + 10_000);
365
+ return {
366
+ enabled: true, running: Boolean(this.timer) && !this.closed, observedAt: new Date(nowMs).toISOString(),
367
+ ...(isoTime(this.lastTickStartedAtMs) ? { lastTickStartedAt: isoTime(this.lastTickStartedAtMs) } : {}),
368
+ ...(isoTime(this.lastTickCompletedAtMs) ? { lastTickCompletedAt: isoTime(this.lastTickCompletedAtMs) } : {}),
369
+ ...(isoTime(this.lastCommandAttemptAtMs) ? { lastCommandAttemptAt: isoTime(this.lastCommandAttemptAtMs) } : {}),
370
+ ...(this.nextRunAtMs > 0 ? { nextAttemptAt: new Date(this.nextRunAtMs).toISOString() } : {}),
371
+ transportFailureStreak: this.transportFailureStreak,
372
+ providerBackpressureMs: chatgptProviderBackpressureRemainingMs(this.deps.providerScopeKey, nowMs), stalled,
373
+ ...(dueCommand ? { dueCommand } : {}),
374
+ ...(projectedFailure ? { lastFailure: { code: projectedFailure.code, observedAt: new Date(projectedFailure.observedAtMs).toISOString(),
375
+ ...(projectedFailure.taskId ? { taskId: projectedFailure.taskId } : {}), ...(projectedFailure.effectId ? { effectId: projectedFailure.effectId } : {}) } } : {}),
376
+ };
377
+ }
378
+
379
+ start(intervalMs = DEFAULT_INTERVAL_MS): void {
380
+ if (this.timer || this.closed) return;
381
+ const activeIntervalMs = Math.max(1, Math.trunc(intervalMs));
382
+ const idleIntervalMs = Math.max(activeIntervalMs, IDLE_INTERVAL_MS);
383
+ const tick = () => {
384
+ if (this.inflight || this.closed || this.deps.nowMs() < this.nextRunAtMs) return;
385
+ this.inflight = this.runOnce().catch((error) => { this.noteFailure(consumerFailureCode(error, 'WORKFLOW_SUPERVISOR_COMPUTER_TARGET_CONSUMER_FAILED')); this.deps.onError(error); }).finally(() => {
386
+ const baseIntervalMs = this.lastRunHadTasks ? activeIntervalMs : idleIntervalMs;
387
+ this.nextRunAtMs = this.deps.nowMs() + (this.lastRunTransportUnavailable
388
+ ? Math.min(baseIntervalMs * 2 ** Math.min(this.transportFailureStreak, MAX_TRANSPORT_BACKOFF_STEPS), MAX_TRANSPORT_BACKOFF_MS)
389
+ : baseIntervalMs);
390
+ this.inflight = undefined;
391
+ });
392
+ };
393
+ tick();
394
+ // This consumer is part of the persistent canonical Runtime, not optional
395
+ // background cleanup. Keep the timer referenced so provider continuation
396
+ // cannot silently stop while the Runtime and MCP listener remain healthy.
397
+ this.timer = this.deps.setInterval(tick, activeIntervalMs);
398
+ }
399
+
400
+ async close(): Promise<void> {
401
+ this.closed = true;
402
+ if (this.timer) this.deps.clearInterval(this.timer);
403
+ this.timer = undefined;
404
+ await this.inflight?.catch(() => undefined);
405
+ await this.deps.targetPort.close().catch(() => undefined);
406
+ this.observedAssistant.clear(); this.providerFailureSeen.clear(); this.providerFailureAwaitingClear.clear(); this.freshSendCheckedAt.clear(); this.taskTransportFailures.clear(); this.projectedTaskStalls.clear(); this.awaitingReceiptObservedAtMs.clear();
407
+ }
408
+
409
+ async runOnce(): Promise<void> {
410
+ if (this.closed) return;
411
+ this.lastTickStartedAtMs = this.deps.nowMs();
412
+ // Preserve fresh-send fairness across ticks. serviceFreshSend prunes
413
+ // retired effect ids; resetting here repeatedly favors the first task.
414
+ this.lastRunTransportUnavailable = false;
415
+ this.syncTaskStallProjections();
416
+ const tasks = this.control.browserTasks();
417
+ this.lastRunHadTasks = tasks.length > 0;
418
+ let inventory;
419
+ try { inventory = await this.deps.targetPort.inventory(); }
420
+ catch (error) {
421
+ this.lastRunTransportUnavailable = true;
422
+ this.noteFailure(consumerFailureCode(error, 'WORKFLOW_SUPERVISOR_COMPUTER_TARGET_INVENTORY_UNAVAILABLE'));
423
+ this.transportFailureStreak = Math.min(this.transportFailureStreak + 1, MAX_TRANSPORT_BACKOFF_STEPS);
424
+ this.lastTickCompletedAtMs = this.deps.nowMs();
425
+ throw error;
426
+ }
427
+ this.conversations = inventory.conversations.map((conversation) => ({ conversation_id: conversation.conversationId, canonical_url: conversation.canonicalUrl,
428
+ ...(conversation.title ? { title: conversation.title } : {}), ...(conversation.projectTitle ? { projectTitle: conversation.projectTitle } : {}),
429
+ ...(conversation.projectUrl ? { projectUrl: conversation.projectUrl } : {}), ...(conversation.isCurrent ? { is_current: true } : {}) }));
430
+ if (!inventory.complete && tasks.length > 0) {
431
+ this.lastRunTransportUnavailable = true;
432
+ this.noteFailure('WORKFLOW_SUPERVISOR_NATIVE_INVENTORY_INCOMPLETE');
433
+ } else if (inventory.complete) {
434
+ this.clearTransportFailure();
435
+ }
436
+ // Due-work omits tasks during observation/retry spacing. Retention follows
437
+ // task lifetime; otherwise every cooldown closes the tab and the next
438
+ // observation reloads the same conversation from the provider.
439
+ const activeResourceKeys = this.control.listTasks(true).map((task) => task.conversationId.startsWith('bootstrap:') ? `chatgpt.bootstrap:${task.taskId}` : `chatgpt.conversation:${task.conversationId}`);
440
+ await this.deps.targetPort.cleanup(activeResourceKeys).catch((error) => this.deps.onError(error));
441
+ for (const task of tasks) {
442
+ if (this.closed) break;
443
+ await this.serviceFreshSend();
444
+ try {
445
+ const poll = task.conversationId.startsWith('bootstrap:') ? this.control.bootstrapPoll(task.taskId) : this.control.browserPoll({ conversationId: task.conversationId, conversationUrl: task.conversationUrl });
446
+ if (poll.terminal || poll.command?.mode === 'send') continue;
447
+ await this.processTask(task);
448
+ } catch (error) {
449
+ this.noteTaskFailure(consumerFailureCode(error, 'WORKFLOW_SUPERVISOR_COMPUTER_TARGET_COMMAND_FAILED'), task);
450
+ this.deps.onError(error);
451
+ }
452
+ }
453
+ await this.serviceFreshSend();
454
+ this.discovery.update(this.conversations, 'computer-browser');
455
+ this.control.recordBrowserDiscovery('computer-browser', this.discovery.sourceConversations('computer-browser'));
456
+ this.transportFailureStreak = this.lastRunTransportUnavailable ? Math.min(this.transportFailureStreak + 1, MAX_TRANSPORT_BACKOFF_STEPS) : 0;
457
+ this.lastTickCompletedAtMs = this.deps.nowMs();
458
+ }
459
+
460
+ private async serviceFreshSend(excludeTaskId?: string): Promise<void> {
461
+ if (this.closed || this.servicingFreshSend) return;
462
+ const nowMs = this.deps.nowMs();
463
+ const eligible = this.control.browserTasks().flatMap((task) => {
464
+ if (task.taskId === excludeTaskId) return [];
465
+ try {
466
+ const poll = task.conversationId.startsWith('bootstrap:') ? this.control.bootstrapPoll(task.taskId) : this.control.browserPoll({ conversationId: task.conversationId, conversationUrl: task.conversationUrl });
467
+ if (poll.command?.mode !== 'send') return [];
468
+ return [{ task, effectId: poll.command.effectId, checkedAt: this.freshSendCheckedAt.get(poll.command.effectId) }];
469
+ } catch { return []; }
470
+ });
471
+ const pending = new Set(eligible.map(({ effectId }) => effectId));
472
+ for (const effectId of this.freshSendCheckedAt.keys()) if (!pending.has(effectId)) this.freshSendCheckedAt.delete(effectId);
473
+ eligible.sort((left, right) => (left.checkedAt ?? 0) - (right.checkedAt ?? 0));
474
+ const next = eligible.find(({ checkedAt }) => checkedAt === undefined || nowMs - checkedAt >= DEFAULT_INTERVAL_MS);
475
+ if (!next) return;
476
+ this.freshSendCheckedAt.set(next.effectId, nowMs); this.lastCommandAttemptAtMs = nowMs; this.servicingFreshSend = true;
477
+ try { await this.processTask(next.task); }
478
+ catch (error) { this.noteTaskFailure(consumerFailureCode(error, 'WORKFLOW_SUPERVISOR_COMPUTER_TARGET_COMMAND_FAILED'), next.task, next.effectId); this.deps.onError(error); }
479
+ finally { this.servicingFreshSend = false; }
480
+ }
481
+
482
+ private async processTask(task: WorkflowSupervisorBrowserTask): Promise<void> {
483
+ // Retry spacing is task-local and covers every exact-target/conversation
484
+ // failure, not just an unloaded page: the retained tab is re-observed at a
485
+ // growing interval instead of being closed, re-opened, and reloaded.
486
+ const transportFailure = this.taskTransportFailures.get(task.taskId);
487
+ // Derived from the durable effect log, not this adapter's process memory.
488
+ const stall = this.control.taskStall(task.taskId);
489
+ if (stall.state === 'spaced' && stall.reason === 'pre_send_infrastructure_blocked') return;
490
+ if (transportFailure
491
+ && TASK_TARGET_SPACED_FAILURE_CODES.has(transportFailure.code)
492
+ && this.deps.nowMs() - transportFailure.observedAtMs < taskTargetRetryDelayMs(transportFailure.streak)) return;
493
+ if (task.conversationId.startsWith('bootstrap:')) { await this.bootstrapTask(task); return; }
494
+ let poll = this.control.browserPoll({ conversationId: task.conversationId, conversationUrl: task.conversationUrl });
495
+ if (poll.terminal) return;
496
+ if (poll.command) this.lastCommandAttemptAtMs = this.deps.nowMs();
497
+ // A turn whose bounded resume is exhausted keeps one slow read-only probe so
498
+ // late evidence can still land, without polling an unchanged surface at the
499
+ // active tick rate and without minting any new provider turn.
500
+ if (!poll.command && this.control.taskStall(task.taskId).state === 'provider_resume_exhausted') {
501
+ const observedAt = this.awaitingReceiptObservedAtMs.get(task.taskId) ?? 0;
502
+ if (this.deps.nowMs() - observedAt < AWAITING_RECEIPT_OBSERVATION_MS) return;
503
+ this.awaitingReceiptObservedAtMs.set(task.taskId, this.deps.nowMs());
504
+ }
505
+ // Acquiring a conversation the inventory does not already expose is a
506
+ // provider navigation/history read, not local observation. The ChatGPT rate
507
+ // limit is account-wide, so while explicit backpressure is active the answer
508
+ // is strictly fewer requests: keep an already-retained surface observable and
509
+ // never open another one. Cooldown is transient, so this defers rather than
510
+ // strands the task.
511
+ if (chatgptProviderBackpressureRemainingMs(this.deps.providerScopeKey, this.deps.nowMs()) > 0
512
+ && !this.conversations.some((conversation) => conversation.conversation_id === task.conversationId)) return;
513
+ const ensured = await this.deps.targetPort.ensureExact(identityForTask(task));
514
+ if (ensured.state !== 'ready') { this.noteTargetUnavailable(task, poll.command?.effectId, ensured.failure); return; }
515
+ const target = ensured.target;
516
+ const snapshot = ensured.observation ?? await target.observe({ includeUserHistory: false, includePageText: false });
517
+ if (!exactConversation(snapshot, task)) { this.noteTargetUnavailable(task, poll.command?.effectId, { code: 'WORKFLOW_SUPERVISOR_EXACT_CONVERSATION_UNPROVEN' }); return; }
518
+ if (!conversationContentAvailable(snapshot)) { this.noteTargetUnavailable(task, poll.command?.effectId, { code: 'COMPUTER_CHATGPT_CONVERSATION_CONTENT_UNAVAILABLE' }); return; }
519
+ // Do not clear a pre-send failure merely because a conversation loaded:
520
+ // only a successful provider preparation proves the obstacle is gone.
521
+ if (transportFailure?.code !== SUPERVISOR_PRE_SEND_BLOCKED) this.clearTaskFailure(task.taskId, poll.command?.effectId);
522
+ this.conversations.push({ conversation_id: task.conversationId, canonical_url: task.conversationUrl,
523
+ ...(snapshot.title.trim() ? { title: snapshot.title.trim().slice(0, 512) } : {}), ...projectMetadataFromConversationUrl(snapshot.url) });
524
+ const providerBusy = snapshot.isGenerating;
525
+ const latestRoleStillUser = snapshot.latestTurnRole === 'user';
526
+ // Capacity is only authoritative on dedicated live provider UI. A model
527
+ // can quote the same phrase in an ordinary assistant turn; historical
528
+ // transcript text must never trigger automatic conversation migration.
529
+ const liveFailure = chatgptProviderPageFailure(snapshot.providerFailureText);
530
+ const turnFailure = chatgptProviderPageFailure(snapshot.providerActivityText);
531
+ const observedProviderFailureCode = liveFailure
532
+ ?? (turnFailure === CHATGPT_AUTOMATION_CONVERSATION_LIMIT_REACHED ? undefined : turnFailure);
533
+ const providerFailureAwaitingClear = this.providerFailureAwaitingClear.get(task.conversationId);
534
+ if (!observedProviderFailureCode) this.providerFailureAwaitingClear.delete(task.conversationId);
535
+ const providerFailureCode = observedProviderFailureCode && observedProviderFailureCode !== providerFailureAwaitingClear
536
+ ? observedProviderFailureCode
537
+ : undefined;
538
+ if (observedProviderFailureCode === CHATGPT_AUTOMATION_CONVERSATION_LIMIT_REACHED) {
539
+ // This conversation cannot produce another meaningful turn. Unlike a
540
+ // provider 429, fresh migration is justified by an explicit terminal
541
+ // capacity message on the exact bound provider surface. The existing
542
+ // Supervisor CAS transaction preserves already-applied source effects.
543
+ this.control.migrateConversation({
544
+ taskId: task.taskId,
545
+ expectedConversationId: task.conversationId,
546
+ fresh: true,
547
+ requestId: `capacity:${task.conversationId}`,
548
+ reason: 'live_provider_conversation_capacity_exhausted',
549
+ authorizedBy: 'user-authorized-automatic-conversation-rotation',
550
+ });
551
+ return;
552
+ }
553
+ const priorProviderFailure = this.providerFailureSeen.get(task.conversationId);
554
+ if (!observedProviderFailureCode) this.providerFailureSeen.delete(task.conversationId);
555
+ else if (priorProviderFailure !== observedProviderFailureCode) { noteChatgptProviderBackpressure(this.deps.providerScopeKey, observedProviderFailureCode, this.deps.nowMs()); this.providerFailureSeen.set(task.conversationId, observedProviderFailureCode); }
556
+ let providerBackpressureMs = chatgptProviderBackpressureRemainingMs(this.deps.providerScopeKey, this.deps.nowMs());
557
+ if (poll.command?.mode !== 'reconcile' && providerFailureCode === CHATGPT_AUTOMATION_RATE_LIMITED && providerBackpressureMs > 0) return;
558
+ let missingReceiptForAppliedTurn = false;
559
+ if (!poll.command && !providerBusy && snapshot.latestTurnRole === 'assistant' && snapshot.latestAssistantResponse.trim()) {
560
+ const responseFingerprint = sha256(snapshot.latestAssistantResponse);
561
+ const pending = this.control.taskStall(task.taskId);
562
+ // Text-only replies are not receipts. Observe their stable idle digest,
563
+ // but avoid generating an identical parser error on every browser tick.
564
+ missingReceiptForAppliedTurn = !hasCommittedSupervisorEnvelope(snapshot.latestAssistantResponse)
565
+ && 'effectId' in pending && Boolean(pending.effectId && targetMarkerPresent(snapshot.latestUserText, pending.effectId));
566
+ if (!missingReceiptForAppliedTurn && this.observedAssistant.get(task.conversationId) !== responseFingerprint) {
567
+ try { await this.control.browserObserveAssistant({ conversationId: task.conversationId, conversationUrl: task.conversationUrl, responseText: snapshot.latestAssistantResponse }); this.observedAssistant.set(task.conversationId, responseFingerprint); }
568
+ catch (error) {
569
+ const message = error instanceof Error ? error.message : String(error);
570
+ if (message.includes('WORKFLOW_SUPERVISOR_') && !message.includes('WORKFLOW_SUPERVISOR_COMPACT_RECEIPT_CHALLENGE_MISMATCH')) this.observedAssistant.set(task.conversationId, responseFingerprint);
571
+ if (!message.includes('WORKFLOW_SUPERVISOR_TASK_TERMINAL')) this.deps.onError(error);
572
+ }
573
+ }
574
+ poll = this.control.browserPoll({ conversationId: task.conversationId, conversationUrl: task.conversationUrl });
575
+ if (poll.terminal) return;
576
+ }
577
+ // A queued continuation must not hide a visible failure from the preceding
578
+ // provider turn. Observe the error first so the existing bounded recovery
579
+ // chain owns it instead of repeatedly attempting the queued send.
580
+ if (!poll.command || providerFailureCode) {
581
+ this.control.browserObserveProviderTurn({ conversationId: task.conversationId, conversationUrl: task.conversationUrl,
582
+ generating: providerFailureCode ? false : providerBusy || latestRoleStillUser, latestAssistantResponse: snapshot.latestAssistantResponse,
583
+ providerActivityText: snapshot.providerActivityText, receiptMissing: missingReceiptForAppliedTurn, providerFailureCode: providerFailureCode === CHATGPT_AUTOMATION_RATE_LIMITED ? undefined : providerFailureCode,
584
+ observedAtMs: this.deps.nowMs(), graceMs: this.deps.providerIdleGraceMs });
585
+ poll = this.control.browserPoll({ conversationId: task.conversationId, conversationUrl: task.conversationUrl });
586
+ const staleTurnRecovery = poll.command?.kind === 'recovery';
587
+ if (providerBusy && !providerFailureCode && !staleTurnRecovery) return;
588
+ if (latestRoleStillUser && !providerFailureCode && !staleTurnRecovery) return;
589
+ }
590
+ providerBackpressureMs = chatgptProviderBackpressureRemainingMs(this.deps.providerScopeKey, this.deps.nowMs());
591
+ const completedSource = poll.command ? Boolean(this.control.getEffect(poll.command.effectId)?.sourceCompletionFingerprint) : false;
592
+ const staleTurnRecovery = poll.command?.kind === 'recovery';
593
+ const commandMutationBlocked = providerBackpressureMs > 0
594
+ || (providerBusy && !providerFailureCode && !staleTurnRecovery)
595
+ || (latestRoleStillUser && !providerFailureCode && !completedSource && !staleTurnRecovery);
596
+ if (poll.command?.mode === 'send' && commandMutationBlocked) return;
597
+ if (poll.command) {
598
+ if (poll.command.kind === 'recovery' && observedProviderFailureCode) {
599
+ this.providerFailureAwaitingClear.set(task.conversationId, observedProviderFailureCode);
600
+ }
601
+ await this.executeCommand(target, poll.command, task);
602
+ }
603
+ }
604
+
605
+ private async bootstrapTask(task: WorkflowSupervisorBrowserTask): Promise<void> {
606
+ const poll = this.control.bootstrapPoll(task.taskId);
607
+ const command = poll.command;
608
+ if (!command) return;
609
+ if (command.mode === 'reconcile') { await this.reconcileBootstrapTask(task, command); return; }
610
+ if (command.mode !== 'send') return;
611
+ // Bootstrap opens a provider project surface and then submits the first
612
+ // prompt. Both are provider requests, so account-wide backpressure defers the
613
+ // whole attempt instead of racing it against an explicit rate limit.
614
+ if (chatgptProviderBackpressureRemainingMs(this.deps.providerScopeKey, this.deps.nowMs()) > 0) return;
615
+ const opened = await this.deps.targetPort.openBootstrap(this.control.bootstrapProjectUrl(task.taskId), task.taskId);
616
+ if (opened.state !== 'ready') { this.noteTargetUnavailable(task, command.effectId, opened.failure); return; }
617
+ const target = opened.target;
618
+ // Bootstrap must originate on the Project/new-composer surface. A retained
619
+ // provider tab can silently reopen the exhausted /c/<id>; sending there
620
+ // burns a fresh effect and can make the migration bind its old source.
621
+ // Reject before beginning an external effect, release the stale target and
622
+ // retain the same unspent enrollment for a later exact-target attempt.
623
+ const beforeSend = opened.observation ?? await target.observe({ includeUserHistory: false, includePageText: false });
624
+ let preexistingConversation = false;
625
+ try { parseChatgptConversationIdentity(beforeSend.url); preexistingConversation = true; }
626
+ catch { /* A Project page without a conversation id is the expected entry. */ }
627
+ if (preexistingConversation) {
628
+ await this.deps.targetPort.release(target.targetId).catch(() => undefined);
629
+ this.noteTargetUnavailable(task, command.effectId, {
630
+ code: 'WORKFLOW_SUPERVISOR_BOOTSTRAP_EXISTING_CONVERSATION',
631
+ });
632
+ return;
633
+ }
634
+ let prepared: Awaited<ReturnType<ComputerChatgptConversationTarget['prepare']>>;
635
+ try { prepared = await target.prepare(command.prompt, { reasoning: 'xhigh' }); }
636
+ catch (error) {
637
+ this.control.recordProviderPreparationFailure({ taskId: task.taskId, effectId: command.effectId, reasonCode: consumerFailureCode(error, 'COMPUTER_PREPARE_FAILED') });
638
+ this.noteTaskFailure(SUPERVISOR_PRE_SEND_BLOCKED, task, command.effectId); this.deps.onError(error); return;
639
+ }
640
+ if (!prepared.ready) {
641
+ this.control.recordProviderPreparationFailure({ taskId: task.taskId, effectId: command.effectId, reasonCode: consumerFailureCode(new Error(prepared.reasonCode), 'COMPUTER_PREPARE_REJECTED') });
642
+ this.noteTaskFailure(SUPERVISOR_PRE_SEND_BLOCKED, task, command.effectId);
643
+ this.deps.onError(new Error(prepared.reasonCode));
644
+ return;
645
+ }
646
+ this.clearTaskFailure(task.taskId, command.effectId);
647
+ if (!this.control.bootstrapBeginEffect({ taskId: task.taskId, effectId: command.effectId, dispatchId: `bootstrap-${randomUUID()}`, dispatchGeneration: command.dispatchGeneration })) return;
648
+ try {
649
+ const dispatch = await withChatgptProviderDispatchLane(this.deps.providerScopeKey, () => target.dispatch(command.prompt, { reasoning: 'xhigh' }),
650
+ (result) => result.mutation === 'attempted' ? { providerAccepted: result.confirmed === true } : { code: result.reasonCode, message: result.reasonCode });
651
+ if (dispatch.mutation === 'not_attempted') {
652
+ this.control.bootstrapObserveEffect({ taskId: task.taskId, effectId: command.effectId, observationId: `bootstrap-${randomUUID()}`, outcome: 'not_applied', evidence: { pre_send_rejection: true, reason: dispatch.reasonCode } });
653
+ await this.deps.targetPort.release(target.targetId).catch(() => undefined);
654
+ return;
655
+ }
656
+ let reason = 'bootstrap_outbound_not_confirmed';
657
+ for (let attempt = 1; attempt <= MAX_LOCAL_OBSERVATION_ATTEMPTS; attempt += 1) {
658
+ try {
659
+ const snapshot = await target.observe({ includeUserHistory: true, includePageText: false });
660
+ const identity = parseChatgptConversationIdentity(snapshot.url);
661
+ if (!snapshotTargetMarkerPresent(snapshot, command.effectId)) throw new Error('WORKFLOW_SUPERVISOR_BOOTSTRAP_EFFECT_MARKER_NOT_OBSERVED');
662
+ const promoted = await this.deps.targetPort.promoteBootstrap(target.targetId, { namespace: 'chatgpt.conversation', conversationId: identity.conversationId, canonicalUrl: identity.canonicalUrl });
663
+ if (promoted.state !== 'ready') throw new Error(promoted.failure.code);
664
+ this.control.bindBootstrapConversation({ taskId: task.taskId, conversationId: identity.conversationId, conversationUrl: identity.canonicalUrl });
665
+ this.control.bootstrapObserveEffect({ taskId: task.taskId, effectId: command.effectId, observationId: `bootstrap-${randomUUID()}`, outcome: 'applied' });
666
+ this.clearTaskFailure(task.taskId, command.effectId);
667
+ return;
668
+ } catch (error) { reason = error instanceof Error ? error.message : String(error); if (attempt < MAX_LOCAL_OBSERVATION_ATTEMPTS) await this.deps.sleep(localObservationDelayMs(attempt, 1_000, 4_000)); }
669
+ }
670
+ this.control.bootstrapObserveEffect({ taskId: task.taskId, effectId: command.effectId, observationId: `bootstrap-${randomUUID()}`, outcome: 'unknown', evidence: { reconciliation: true, reason } });
671
+ } catch (error) {
672
+ this.control.bootstrapObserveEffect({ taskId: task.taskId, effectId: command.effectId, observationId: `bootstrap-${randomUUID()}`, outcome: 'unknown', evidence: { reconciliation: true, reason: error instanceof Error ? error.message : String(error) } });
673
+ throw error;
674
+ }
675
+ }
676
+
677
+ private async reconcileBootstrapTask(task: WorkflowSupervisorBrowserTask, command: WorkflowSupervisorBrowserCommand): Promise<void> {
678
+ const matches = await this.deps.targetPort.findBySubmittedMarker(
679
+ renderEffectMarker(command.effectId),
680
+ task.taskId,
681
+ async () => { await this.serviceFreshSend(task.taskId); },
682
+ );
683
+ const ready = matches.filter((result): result is Extract<typeof result, { state: 'ready' }> => result.state === 'ready');
684
+ const observeUnknown = (reason: string): void => this.control.bootstrapObserveEffect({ taskId: task.taskId, effectId: command.effectId, observationId: `bootstrap-reconcile-${randomUUID()}`, outcome: 'unknown', evidence: { reconciliation: true, reason } });
685
+ if (ready.length === 0) { observeUnknown('bootstrap_target_not_observed'); return; }
686
+ if (ready.length !== 1) { observeUnknown('bootstrap_reconcile_ambiguous'); return; }
687
+ const match = ready[0]!;
688
+ const snapshot = match.observation ?? await match.target.observe({ includeUserHistory: true, includePageText: false });
689
+ let identity;
690
+ try { identity = parseChatgptConversationIdentity(snapshot.url); } catch { observeUnknown('bootstrap_conversation_identity_unavailable'); return; }
691
+ if (!snapshotTargetMarkerPresent(snapshot, command.effectId)) { observeUnknown('bootstrap_effect_marker_not_observed'); return; }
692
+ const promoted = await this.deps.targetPort.promoteBootstrap(match.target.targetId, { namespace: 'chatgpt.conversation', conversationId: identity.conversationId, canonicalUrl: identity.canonicalUrl });
693
+ if (promoted.state !== 'ready') { observeUnknown(promoted.failure.code); return; }
694
+ this.control.bindBootstrapConversation({ taskId: task.taskId, conversationId: identity.conversationId, conversationUrl: identity.canonicalUrl });
695
+ this.control.bootstrapObserveEffect({ taskId: task.taskId, effectId: command.effectId, observationId: `bootstrap-reconcile-${randomUUID()}`, outcome: 'applied' });
696
+ this.clearTaskFailure(task.taskId, command.effectId);
697
+ }
698
+
699
+ private async executeCommand(target: ComputerChatgptConversationTarget, command: WorkflowSupervisorBrowserCommand, task: WorkflowSupervisorBrowserTask): Promise<void> {
700
+ let snapshot = await target.observe({ includeUserHistory: true, includePageText: true });
701
+ if (!exactConversation(snapshot, task) || !conversationContentAvailable(snapshot)) {
702
+ this.noteTargetUnavailable(task, command.effectId, { code: 'COMPUTER_CHATGPT_CONVERSATION_CONTENT_UNAVAILABLE' });
703
+ return;
704
+ }
705
+ if (command.mode === 'send' && snapshot.isGenerating && command.kind !== 'recovery') return;
706
+ let mode = command.mode;
707
+ if (mode === 'send') {
708
+ let prepared: Awaited<ReturnType<ComputerChatgptConversationTarget['prepare']>>;
709
+ try { prepared = await target.prepare(command.prompt, {
710
+ ...(command.kind === 'recovery' ? { mode: 'recover' as const } : {}), reasoning: 'xhigh',
711
+ }); }
712
+ catch (error) {
713
+ this.control.recordProviderPreparationFailure({ taskId: task.taskId, effectId: command.effectId, reasonCode: consumerFailureCode(error, 'COMPUTER_PREPARE_FAILED') });
714
+ this.noteTaskFailure(SUPERVISOR_PRE_SEND_BLOCKED, task, command.effectId); this.deps.onError(error); return;
715
+ }
716
+ if (!prepared.ready) {
717
+ this.control.recordProviderPreparationFailure({ taskId: task.taskId, effectId: command.effectId, reasonCode: consumerFailureCode(new Error(prepared.reasonCode), 'COMPUTER_PREPARE_REJECTED') });
718
+ this.noteTaskFailure(SUPERVISOR_PRE_SEND_BLOCKED, task, command.effectId);
719
+ this.deps.onError(new Error(prepared.reasonCode));
720
+ return;
721
+ }
722
+ this.clearTaskFailure(task.taskId, command.effectId);
723
+ const begin = this.control.browserBeginEffect({ conversationId: command.conversationId, conversationUrl: command.conversationUrl, effectId: command.effectId,
724
+ dispatchId: `computer-${randomUUID()}`, dispatchGeneration: command.dispatchGeneration,
725
+ evidence: { surface: 'computer-chatgpt-target', target_id: target.targetId, latest_user_text: snapshot.latestUserText, latest_assistant_response: snapshot.latestAssistantResponse } });
726
+ if (!begin.started) mode = 'reconcile';
727
+ }
728
+ if (mode === 'reconcile') {
729
+ const exact = normalize(snapshot.latestUserText) === normalize(command.prompt);
730
+ const markerPresent = snapshotTargetMarkerPresent(snapshot, command.effectId);
731
+ if (exact || markerPresent) {
732
+ this.control.browserObserveEffect({ conversationId: command.conversationId, conversationUrl: command.conversationUrl, effectId: command.effectId,
733
+ observationId: `computer-observe-${randomUUID()}`, outcome: 'applied',
734
+ evidence: { surface: 'computer-chatgpt-target', target_id: target.targetId, exact_user_message: exact, reconciliation: true, target_marker_present: markerPresent } });
735
+ return;
736
+ }
737
+ const reason = 'submission_not_observed';
738
+ this.control.browserObserveEffect({ conversationId: command.conversationId, conversationUrl: command.conversationUrl, effectId: command.effectId,
739
+ observationId: `computer-observe-${randomUUID()}`, outcome: 'unknown',
740
+ evidence: { surface: 'computer-chatgpt-target', target_id: target.targetId, reconciliation: true, target_marker_present: false, reason,
741
+ observation_fingerprint: unknownObservationFingerprint(command.effectId, reason, snapshot) } });
742
+ return;
743
+ }
744
+ let dispatch: Awaited<ReturnType<ComputerChatgptConversationTarget['dispatch']>>;
745
+ try {
746
+ dispatch = await withChatgptProviderDispatchLane(this.deps.providerScopeKey, () => target.dispatch(command.prompt, { ...(command.kind === 'recovery' ? { mode: 'recover' as const } : {}), reasoning: 'xhigh' }),
747
+ (result) => result.mutation === 'attempted' ? { providerAccepted: result.confirmed === true } : { code: result.reasonCode, message: result.reasonCode });
748
+ } catch (error) {
749
+ this.control.browserObserveEffect({ conversationId: command.conversationId, conversationUrl: command.conversationUrl, effectId: command.effectId,
750
+ observationId: `computer-observe-${randomUUID()}`, outcome: 'unknown',
751
+ evidence: { surface: 'computer-chatgpt-target', target_id: target.targetId, reconciliation: true, reason: consumerFailureCode(error, 'provider_dispatch_exception') } });
752
+ throw error;
753
+ }
754
+ if (dispatch.mutation === 'not_attempted') {
755
+ this.control.browserObserveDispatchFailure({ conversationId: command.conversationId, conversationUrl: command.conversationUrl, effectId: command.effectId,
756
+ observationId: `computer-observe-${randomUUID()}`, dispatchGeneration: command.dispatchGeneration, reason: dispatch.reasonCode });
757
+ return;
758
+ }
759
+ if (dispatch.confirmed) {
760
+ this.control.browserObserveEffect({ conversationId: command.conversationId, conversationUrl: command.conversationUrl, effectId: command.effectId,
761
+ observationId: `computer-observe-${randomUUID()}`, outcome: 'applied', evidence: { surface: 'computer-chatgpt-target', target_id: target.targetId, provider_confirmed: true, ...(dispatch.reasoningVerified ? { reasoning_verified: dispatch.reasoningVerified } : {}) } });
762
+ return;
763
+ }
764
+ let exact = false; let markerPresent = false;
765
+ for (let attempt = 1; attempt <= MAX_LOCAL_OBSERVATION_ATTEMPTS; attempt += 1) {
766
+ snapshot = await target.observe({ includeUserHistory: true, includePageText: true });
767
+ exact = normalize(snapshot.latestUserText) === normalize(command.prompt); markerPresent = snapshotTargetMarkerPresent(snapshot, command.effectId);
768
+ if (exact || markerPresent || attempt >= MAX_LOCAL_OBSERVATION_ATTEMPTS) break;
769
+ await this.deps.sleep(localObservationDelayMs(attempt, 1_000, 4_000));
770
+ }
771
+ this.control.browserObserveEffect({ conversationId: command.conversationId, conversationUrl: command.conversationUrl, effectId: command.effectId,
772
+ observationId: `computer-observe-${randomUUID()}`, outcome: exact || markerPresent ? 'applied' : 'unknown',
773
+ evidence: { surface: 'computer-chatgpt-target', target_id: target.targetId, exact_user_message: exact, target_marker_present: markerPresent, ...(dispatch.reasoningVerified ? { reasoning_verified: dispatch.reasoningVerified } : {}),
774
+ ...(!exact && !markerPresent ? { reason: 'outbound_not_confirmed', observation_fingerprint: unknownObservationFingerprint(command.effectId, 'outbound_not_confirmed', snapshot) } : {}) } });
775
+ }
776
+ }
777
+
778
+ export function startWorkflowSupervisorNativeBrowserAdapter(
779
+ control: WorkflowSupervisorControlPlane,
780
+ discovery: WorkflowSupervisorEphemeralDiscovery,
781
+ dependencies: WorkflowSupervisorComputerBrowserDependencies,
782
+ ): WorkflowSupervisorNativeBrowserHandle {
783
+ const adapter = new WorkflowSupervisorNativeBrowserAdapter(control, discovery, dependencies);
784
+ adapter.start();
785
+ return { adapter, status: () => adapter.status(), close: async () => { await adapter.close(); } };
786
+ }