@moretea-labs/forge 1.8.0 → 1.8.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (528) hide show
  1. package/AGENTS.md +70 -7
  2. package/CHANGELOG.md +14 -0
  3. package/CLAUDE.md +17 -2
  4. package/CONTRIBUTING.md +3 -2
  5. package/THIRD_PARTY_NOTICES.md +1 -1
  6. package/adapters/chatgpt/browser-delivery-host.ts +7 -1
  7. package/adapters/chatgpt/browser-delivery-runtime.ts +529 -56
  8. package/adapters/chatgpt/controller-binding-store.ts +101 -22
  9. package/adapters/chatgpt/controller-round-host.ts +15 -25
  10. package/adapters/chatgpt/controller-round-settlement-store.ts +58 -4
  11. package/adapters/chatgpt/provider-delivery.ts +228 -1
  12. package/adapters/chatgpt/work-conversation-binding-store.ts +79 -53
  13. package/adapters/computer/chatgpt-extension-target.ts +463 -0
  14. package/adapters/computer/chatgpt-target-router.ts +103 -0
  15. package/adapters/computer/chrome-extension/background.js +385 -0
  16. package/adapters/computer/chrome-extension/content.js +378 -0
  17. package/adapters/computer/chrome-extension/core.js +24 -0
  18. package/adapters/computer/chrome-extension/manifest.json +30 -0
  19. package/adapters/computer/desktop-operator-discovery.ts +11 -31
  20. package/adapters/computer/interaction-target-authority.ts +142 -18
  21. package/adapters/mcp/auth.ts +0 -1
  22. package/adapters/mcp/instructions.ts +5 -4
  23. package/adapters/mcp/multi-repository.ts +3 -19
  24. package/adapters/mcp/oauth.ts +73 -0
  25. package/adapters/mcp/paths.ts +4 -1
  26. package/adapters/mcp/runtime-gateway/automation-receipt-adapter.ts +87 -0
  27. package/adapters/mcp/runtime-gateway/bounded-result-runtime.ts +62 -0
  28. package/adapters/mcp/runtime-gateway/cognition-settlement.ts +201 -0
  29. package/adapters/mcp/runtime-gateway/context-adapter.ts +411 -73
  30. package/adapters/mcp/runtime-gateway/context-pack-sidecar.ts +91 -0
  31. package/adapters/mcp/runtime-gateway/controller-authority-adapter.ts +20 -5
  32. package/adapters/mcp/runtime-gateway/core-capability-adapter.ts +258 -0
  33. package/adapters/mcp/runtime-gateway/engineering-preconditions.ts +10 -27
  34. package/adapters/mcp/runtime-gateway/engineering-tool-contract.ts +15 -0
  35. package/adapters/mcp/runtime-gateway/execution-tools.ts +8 -42
  36. package/adapters/mcp/runtime-gateway/gateway-execution-adapter.ts +2 -1
  37. package/adapters/mcp/runtime-gateway/plugin-adapter.ts +117 -45
  38. package/adapters/mcp/runtime-gateway/process-tools.ts +190 -22
  39. package/adapters/mcp/runtime-gateway/protected-computer-adapter.ts +16 -4
  40. package/adapters/mcp/runtime-gateway/recovery-adapter.ts +69 -52
  41. package/adapters/mcp/runtime-gateway/repository-compat-adapter.ts +4 -35
  42. package/adapters/mcp/runtime-gateway/result-adapter.ts +10 -4
  43. package/adapters/mcp/runtime-gateway/router.ts +18 -504
  44. package/adapters/mcp/runtime-gateway/routing-policy.ts +499 -0
  45. package/adapters/mcp/runtime-gateway/runtime-observation-adapter.ts +14 -65
  46. package/adapters/mcp/runtime-gateway/runtime-readiness-observation.ts +218 -0
  47. package/adapters/mcp/runtime-gateway/runtime-tool-definitions.ts +113 -173
  48. package/adapters/mcp/runtime-gateway/runtime-tools.ts +15 -5
  49. package/adapters/mcp/runtime-gateway/scheduler-adapter.ts +1 -0
  50. package/adapters/mcp/runtime-gateway/shared-adapter.ts +20 -0
  51. package/adapters/mcp/runtime-gateway/status-inbox-adapter.ts +358 -266
  52. package/adapters/mcp/runtime-gateway/typescript-navigation-sidecar.ts +136 -0
  53. package/adapters/mcp/runtime-gateway/work-adapter.ts +261 -3122
  54. package/adapters/mcp/runtime-gateway/work-controller-operations.ts +257 -0
  55. package/adapters/mcp/runtime-gateway/work-detail-projection.ts +60 -0
  56. package/adapters/mcp/runtime-gateway/work-input-wire-migration.ts +246 -0
  57. package/adapters/mcp/runtime-gateway/work-learning-operations.ts +145 -0
  58. package/adapters/mcp/runtime-gateway/work-list-projection.ts +38 -0
  59. package/adapters/mcp/runtime-gateway/work-plan-operations.ts +382 -0
  60. package/adapters/mcp/runtime-gateway/work-repair-adapter.ts +308 -0
  61. package/adapters/mcp/runtime-gateway/work-requirement-operations.ts +148 -0
  62. package/adapters/mcp/runtime-gateway/work-semantic-operations.ts +263 -0
  63. package/adapters/mcp/runtime-gateway/work-workflow-operations.ts +113 -0
  64. package/adapters/mcp/runtime-gateway/workflow-supervisor-adapter.ts +156 -0
  65. package/adapters/mcp/server.ts +67 -23
  66. package/adapters/mcp/setup.ts +1 -3
  67. package/adapters/mcp/tool-mapping/legacy-tool-service.ts +44 -170
  68. package/adapters/mcp/tool-mapping/post-finalize-work-attribution.ts +4 -9
  69. package/adapters/mcp/tool-mapping/repository-tools.ts +133 -142
  70. package/adapters/mcp/toolset-names.ts +5 -0
  71. package/adapters/mcp/toolset.ts +6 -5
  72. package/adapters/mcp/transports/http-observation.ts +365 -0
  73. package/adapters/mcp/transports/http.ts +154 -677
  74. package/adapters/mcp/transports/oauth-http.ts +322 -0
  75. package/adapters/mcp/transports/session-registry.ts +6 -0
  76. package/adapters/mcp/tunnels/openai-secure-tunnel.ts +89 -5
  77. package/assets/plugin-registry.v1.json +6 -4
  78. package/assets/reference-configs/agentic-development-flow.md +25 -0
  79. package/assets/reference-configs/global-working-rules.md +19 -0
  80. package/assets/skill-version.json +2 -2
  81. package/docs/architecture/CURRENT.md +111 -41
  82. package/docs/architecture/decisions/20260803-release-identity-binding-and-exit-policy.md +14 -5
  83. package/docs/architecture/decisions/20260823-immediate-controller-relay.md +6 -3
  84. package/docs/architecture/decisions/20260907-assistant-learning-loop.md +2 -0
  85. package/docs/architecture/decisions/20260907-controller-round-transition-policy.md +19 -4
  86. package/docs/architecture/decisions/20260916-workflow-supervisor-authority.md +249 -0
  87. package/docs/architecture/decisions/20260917-cognitive-memory-foundation.md +82 -0
  88. package/docs/architecture/decisions/20260918-stable-candidate-release-lifecycle.md +221 -0
  89. package/docs/architecture/decisions/20260919-autonomous-work-liveness.md +62 -0
  90. package/docs/architecture/decisions/20260924-thin-semantic-working-context.md +72 -0
  91. package/docs/architecture/decisions/20261001-supervisor-turn-authority.md +237 -0
  92. package/docs/architecture/decisions/20261005-forge-v3-desktop-client-boundary.md +77 -0
  93. package/docs/architecture/domains/verification.md +1 -0
  94. package/docs/architecture/domains/workflow-engine.md +6 -0
  95. package/docs/architecture/modules/controller-runtime/transport-lifecycle.md +1 -1
  96. package/docs/forge-plugin-management.md +2 -2
  97. package/docs/operations/controller-performance-and-502.md +17 -0
  98. package/docs/operations/controller-reliability-runbook.md +2 -2
  99. package/docs/operations/features.md +1 -1
  100. package/docs/operations/features.zh-CN.md +1 -1
  101. package/docs/operations/homebrew.md +2 -2
  102. package/docs/operations/mcp-tool-exposure.md +2 -0
  103. package/docs/operations/releasing.md +2 -0
  104. package/docs/operations/standalone-disaster-recovery.md +14 -6
  105. package/docs/wiki/Implementation.md +1 -1
  106. package/package.json +25 -14
  107. package/packages/kernel/cognition/api/index.ts +6 -0
  108. package/packages/kernel/cognition/application/activation-service.ts +451 -0
  109. package/packages/kernel/cognition/application/consolidation-service.ts +185 -0
  110. package/packages/kernel/cognition/application/legacy-experience-adapter.ts +38 -0
  111. package/packages/kernel/cognition/application/memory-service.ts +64 -0
  112. package/packages/kernel/cognition/domain/learning.ts +106 -0
  113. package/packages/kernel/cognition/domain/memory.ts +254 -0
  114. package/packages/kernel/controller/api/index.ts +1 -0
  115. package/packages/kernel/controller/application/continuation-service.ts +281 -0
  116. package/packages/kernel/controller/application/controller-round-service.ts +12 -0
  117. package/packages/kernel/controller/domain/controller-round-transition-policy.ts +242 -21
  118. package/packages/kernel/controller/domain/controller-round.ts +4 -1
  119. package/packages/kernel/controller/domain/execution-quality.ts +3 -1
  120. package/packages/kernel/controller/infrastructure/controller-round-store.ts +689 -103
  121. package/packages/kernel/controller/infrastructure/controller-session-store.ts +297 -71
  122. package/packages/kernel/controller/ports/controller-host.ts +2 -0
  123. package/packages/kernel/identity/api/index.ts +10 -0
  124. package/packages/kernel/identity/domain/activity-projection.ts +43 -0
  125. package/packages/kernel/identity/domain/capability-broker.ts +60 -0
  126. package/packages/kernel/identity/domain/grant.ts +72 -0
  127. package/packages/kernel/identity/domain/owned-resource.ts +116 -0
  128. package/packages/kernel/identity/domain/user-request.ts +93 -0
  129. package/packages/kernel/identity/infrastructure/activity-projection-store.ts +77 -0
  130. package/packages/kernel/identity/infrastructure/capability-broker.ts +81 -0
  131. package/packages/kernel/identity/infrastructure/grant-store.ts +284 -0
  132. package/packages/kernel/identity/infrastructure/owned-resource-store.ts +259 -0
  133. package/packages/kernel/identity/infrastructure/user-request-store.ts +182 -0
  134. package/packages/kernel/scheduler/api/index.ts +0 -2
  135. package/packages/kernel/scheduler/application/schedule-service.ts +3 -0
  136. package/packages/kernel/scheduler/application/settlement.ts +0 -15
  137. package/packages/kernel/scheduler/domain/schedule.ts +87 -0
  138. package/packages/kernel/scheduler/infrastructure/schedule-store.ts +153 -133
  139. package/packages/kernel/work/api/index.ts +3 -2
  140. package/packages/kernel/work/application/work-service.ts +17 -42
  141. package/packages/kernel/work/domain/current-task-lineage.ts +104 -0
  142. package/packages/kernel/work/domain/engineering-design.ts +10 -5
  143. package/packages/kernel/work/domain/engineering-profile.ts +8 -12
  144. package/packages/kernel/work/domain/evaluation-promotion-receipt.ts +186 -0
  145. package/packages/kernel/work/domain/execution-concurrency.ts +19 -26
  146. package/packages/kernel/work/domain/execution-snapshot.ts +0 -31
  147. package/packages/kernel/work/domain/implementation-review.ts +14 -331
  148. package/packages/kernel/work/domain/objective-graph.ts +119 -0
  149. package/packages/kernel/work/domain/project-engineering-contract.ts +23 -1
  150. package/packages/kernel/work/domain/repository-completion-receipt.ts +1 -1
  151. package/packages/kernel/work/domain/state-machine.ts +25 -63
  152. package/packages/kernel/work/domain/types.ts +57 -51
  153. package/packages/kernel/work/infrastructure/work-contract-store.ts +819 -728
  154. package/packages/kernel/work/ports/work-contract-store.ts +5 -2
  155. package/packages/plugin-runtime/browser/session-authority.ts +2 -1
  156. package/packages/plugin-runtime/computer/chatgpt-identity.ts +24 -0
  157. package/packages/plugin-runtime/computer/conversation-target.ts +143 -0
  158. package/packages/plugin-runtime/computer/index.ts +2 -0
  159. package/packages/plugin-runtime/computer/target-authority.ts +26 -1
  160. package/packages/plugin-runtime/external/unix-jsonl-transport.ts +142 -18
  161. package/packages/protocols/computer/contract.ts +27 -1
  162. package/scripts/activate-source-baseline.ts +7 -9
  163. package/scripts/canary-controller-semantic-wait.ts +12 -24
  164. package/scripts/check-mcp-compatibility.ts +48 -136
  165. package/scripts/check-runtime-architecture.mjs +622 -217
  166. package/scripts/forge-local-recovery-helper.mjs +93 -15
  167. package/scripts/lib/project-init-lib.sh +3 -0
  168. package/scripts/open-source-audit-allowlist.txt +1 -2
  169. package/scripts/run-bounded-command.mjs +5 -0
  170. package/scripts/run-governed-gate.ts +0 -1
  171. package/scripts/run-mobile-monitor-bridge.ts +0 -1
  172. package/scripts/smoke-control-plane-failure-domain.ts +94 -0
  173. package/scripts/smoke-mcp-http-runtime.ts +5 -0
  174. package/scripts/smoke-runtime-recovery.ts +12 -43
  175. package/scripts/smoke-schedule-engine.ts +23 -15
  176. package/scripts/smoke-unattended-transport-recovery.ts +223 -0
  177. package/scripts/smoke-user-request-continuation-restart.ts +232 -0
  178. package/scripts/smoke-workflow-supervisor-chrome-adapter.ts +92 -0
  179. package/scripts/smoke-workflow-supervisor-process-restart.ts +276 -0
  180. package/scripts/smoke-workflow-supervisor-restart-recovery.ts +150 -0
  181. package/scripts/smoke-workflow-supervisor.ts +103 -0
  182. package/scripts/verify-forge-runtime.sh +2 -1
  183. package/src/cli/agent-jobs/executor-health.ts +11 -34
  184. package/src/cli/agent-jobs/integration.ts +18 -49
  185. package/src/cli/agent-jobs/job-manager.ts +7 -3
  186. package/src/cli/commands/brain-assistant.ts +27 -13
  187. package/src/cli/commands/brain.ts +13 -15
  188. package/src/cli/commands/chatgpt.ts +1 -163
  189. package/src/cli/commands/recovery.ts +135 -121
  190. package/src/cli/commands/runtime.ts +3 -3
  191. package/src/cli/commands/setup-profile.ts +8 -0
  192. package/src/cli/controller/check-runner.ts +13 -2
  193. package/src/cli/controller/completion-backlog.ts +3 -3
  194. package/src/cli/controller/completion-orchestrator.ts +4 -43
  195. package/src/cli/controller/completion-target.ts +3 -72
  196. package/src/cli/controller/context/source-materializer.ts +81 -100
  197. package/src/cli/controller/context-pack.ts +10 -8
  198. package/src/cli/controller/execution-completion.ts +4 -7
  199. package/src/cli/controller/execution-policy.ts +36 -153
  200. package/src/cli/controller/governance.ts +2 -3
  201. package/src/cli/controller/issue-store.ts +4 -99
  202. package/src/cli/controller/launch-agents.ts +59 -18
  203. package/src/cli/controller/operational-plan.ts +24 -51
  204. package/src/cli/controller/runtime-config.ts +5 -1
  205. package/src/cli/controller/stuck-state-migration.ts +2 -3
  206. package/src/cli/controller/systemd-user.ts +39 -1
  207. package/src/cli/editing/edit-session.ts +1 -7
  208. package/src/cli/local-bridge/console-automations.ts +18 -13
  209. package/src/cli/local-bridge/console-view-models.ts +3 -12
  210. package/src/cli/local-bridge/facade-api.ts +64 -191
  211. package/src/cli/local-bridge/server.ts +24 -147
  212. package/src/cli/local-bridge/types.ts +0 -1
  213. package/src/cli/mcp/oauth-client-retirement.ts +74 -0
  214. package/src/cli/repositories/command-executor.ts +29 -23
  215. package/src/cli/repositories/command-scope.ts +35 -16
  216. package/src/cli/repositories/controller-home.ts +48 -0
  217. package/src/cli/repositories/ephemeral-workspace.ts +20 -30
  218. package/src/cli/repositories/git-command-executor.ts +2 -2
  219. package/src/cli/repositories/registry.ts +77 -11
  220. package/src/cli/repositories/structured-git.ts +62 -2
  221. package/src/cli/repository/session-cache.ts +92 -6
  222. package/src/runtime/context/assistant-context.ts +20 -7
  223. package/src/runtime/context/assistant-work-context.ts +89 -27
  224. package/src/runtime/context/automatic-learning.ts +565 -0
  225. package/src/runtime/context/cognitive-attention.ts +173 -0
  226. package/src/runtime/context/cognitive-skill-canary.ts +158 -0
  227. package/src/runtime/context/context-closure.ts +46 -9
  228. package/src/runtime/context/context-pack-process.ts +103 -0
  229. package/src/runtime/context/context-plane.ts +1 -9
  230. package/src/runtime/context/direct-controller-learning.ts +298 -0
  231. package/src/runtime/context/semantic-navigation-contract.ts +9 -0
  232. package/src/runtime/context/semantic-navigation.ts +6 -34
  233. package/src/runtime/context/typescript-navigation-process.ts +145 -0
  234. package/src/runtime/context/typescript-navigation.ts +89 -3
  235. package/src/runtime/control-plane/cleanup-artifact-retention.ts +212 -9
  236. package/src/runtime/control-plane/concurrency/work-execution-concurrency.ts +9 -47
  237. package/src/runtime/control-plane/execution/controller-authority-recovery.ts +34 -4
  238. package/src/runtime/control-plane/execution/edit-validation-coordinator.ts +29 -20
  239. package/src/runtime/control-plane/execution/execution-identity.ts +23 -3
  240. package/src/runtime/control-plane/execution/repository-work-attribution.ts +7 -30
  241. package/src/runtime/control-plane/execution/retained-work-resume.ts +206 -199
  242. package/src/runtime/control-plane/execution/session-store.ts +31 -1
  243. package/src/runtime/control-plane/execution/validation.ts +6 -8
  244. package/src/runtime/control-plane/execution/work-authority-reconciler.ts +13 -42
  245. package/src/runtime/control-plane/execution/work-check-evidence.ts +137 -0
  246. package/src/runtime/control-plane/execution/work-completion-authority.ts +30 -85
  247. package/src/runtime/control-plane/execution/work-delivery-service.ts +497 -0
  248. package/src/runtime/control-plane/execution/work-evidence-policy.ts +12 -50
  249. package/src/runtime/control-plane/execution/work-execution-support.ts +50 -149
  250. package/src/runtime/control-plane/execution/work-handle-authority.ts +188 -109
  251. package/src/runtime/control-plane/execution/work-handle-store.ts +19 -43
  252. package/src/runtime/control-plane/execution/work-head-settlement.ts +53 -20
  253. package/src/runtime/control-plane/execution/work-lifecycle-audit.ts +52 -29
  254. package/src/runtime/control-plane/execution/work-operation-service.ts +43 -27
  255. package/src/runtime/control-plane/execution/work-preparation-service.ts +126 -266
  256. package/src/runtime/control-plane/execution/work-remote-delivery.ts +2 -3
  257. package/src/runtime/control-plane/execution/work-revision-diff.ts +39 -0
  258. package/src/runtime/control-plane/execution/work-terminal-cleanup.ts +173 -186
  259. package/src/runtime/control-plane/execution/work-validation-reconciler.ts +28 -84
  260. package/src/runtime/control-plane/execution/work-verification-service.ts +406 -50
  261. package/src/runtime/control-plane/execution/work-verification-snapshot.ts +5 -1
  262. package/src/runtime/control-plane/facade/capability-registry.ts +362 -37
  263. package/src/runtime/control-plane/facade/check-normalization.ts +3 -9
  264. package/src/runtime/control-plane/facade/codex-delegation.ts +10 -11
  265. package/src/runtime/control-plane/facade/controller-connection.ts +135 -0
  266. package/src/runtime/control-plane/facade/goal-workloop-access.ts +1 -20
  267. package/src/runtime/control-plane/facade/goal-workloop.ts +281 -1753
  268. package/src/runtime/control-plane/facade/handoff-inbox-application.ts +12 -25
  269. package/src/runtime/control-plane/facade/handoff-inbox-store.ts +256 -52
  270. package/src/runtime/control-plane/facade/index.ts +0 -1
  271. package/src/runtime/control-plane/facade/operation-digest.ts +12 -15
  272. package/src/runtime/control-plane/facade/plan-contract-store.ts +451 -991
  273. package/src/runtime/control-plane/facade/policy-gate.ts +0 -23
  274. package/src/runtime/control-plane/facade/repository-work-admission.ts +12 -22
  275. package/src/runtime/control-plane/facade/requirement-authority.ts +102 -199
  276. package/src/runtime/control-plane/facade/requirement-board.ts +3 -3
  277. package/src/runtime/control-plane/facade/rh-work-operation-contract.ts +51 -14
  278. package/src/runtime/control-plane/facade/self-healing-loop.ts +18 -53
  279. package/src/runtime/control-plane/facade/suggested-actions.ts +15 -18
  280. package/src/runtime/control-plane/facade/types.ts +49 -108
  281. package/src/runtime/control-plane/facade/work-continuation.ts +8 -8
  282. package/src/runtime/control-plane/generated-cache-retention.ts +97 -1
  283. package/src/runtime/control-plane/global-scheduler/autonomous-continuation.ts +248 -0
  284. package/src/runtime/control-plane/global-scheduler/durable-admission.ts +1 -1
  285. package/src/runtime/control-plane/global-scheduler/maintenance.ts +239 -112
  286. package/src/runtime/control-plane/global-scheduler/reconciliation.ts +2 -1
  287. package/src/runtime/control-plane/global-scheduler/scheduler.ts +66 -40
  288. package/src/runtime/control-plane/global-scheduler/wake-signal.ts +42 -2
  289. package/src/runtime/control-plane/governance/access-policy.ts +19 -2
  290. package/src/runtime/control-plane/governance/authorization.ts +20 -3
  291. package/src/runtime/control-plane/launcher/chatgpt-round-continuation.ts +63 -300
  292. package/src/runtime/control-plane/launcher/chatgpt-work-continuation.ts +28 -300
  293. package/src/runtime/control-plane/launcher/local-conversation-controller.ts +238 -0
  294. package/src/runtime/control-plane/launcher/provider-mcp-bootstrap.ts +5 -2
  295. package/src/runtime/control-plane/launcher/thin-launcher.ts +96 -240
  296. package/src/runtime/control-plane/persistence/cognition-store.ts +820 -0
  297. package/src/runtime/control-plane/persistence/experience-store.ts +162 -29
  298. package/src/runtime/control-plane/persistence/requirement-store.ts +216 -74
  299. package/src/runtime/control-plane/persistence/sqlite-store.ts +113 -6
  300. package/src/runtime/control-plane/release-retention.ts +135 -47
  301. package/src/runtime/control-plane/repository-namespace-retention.ts +2 -2
  302. package/src/runtime/control-plane/runtime-cleanup.ts +290 -21
  303. package/src/runtime/control-plane/workspace/project-onboarding.ts +80 -0
  304. package/src/runtime/control-plane/workspace/semantic-sync-service.ts +19 -5
  305. package/src/runtime/control-plane/workspace/workspace-store.ts +169 -0
  306. package/src/runtime/diagnostics/incident-repair.ts +313 -146
  307. package/src/runtime/diagnostics/mcp-timing.ts +114 -0
  308. package/src/runtime/evidence/artifact-store.ts +158 -40
  309. package/src/runtime/evidence/evidence-store.ts +112 -8
  310. package/src/runtime/evidence/output-handle-index.ts +225 -0
  311. package/src/runtime/evidence/result-store.ts +158 -44
  312. package/src/runtime/execution/jobs/store.ts +3 -4
  313. package/src/runtime/execution/managed-workspace.ts +57 -0
  314. package/src/runtime/execution/process-runtime/check-facade.ts +1 -1
  315. package/src/runtime/execution/process-runtime/check-result-retention.ts +2 -2
  316. package/src/runtime/execution/process-runtime/check-result.ts +105 -1
  317. package/src/runtime/execution/process-runtime/check-runner-sidecar.ts +18 -8
  318. package/src/runtime/execution/process-runtime/command-facade.ts +79 -27
  319. package/src/runtime/execution/process-runtime/gc.ts +15 -2
  320. package/src/runtime/execution/process-runtime/handle-index.ts +176 -0
  321. package/src/runtime/execution/process-runtime/host-command-lane.ts +139 -0
  322. package/src/runtime/execution/process-runtime/index.ts +3 -0
  323. package/src/runtime/execution/process-runtime/lightweight-managed.ts +251 -72
  324. package/src/runtime/execution/process-runtime/persisted-check.ts +3 -3
  325. package/src/runtime/execution/process-runtime/process-runner-entry.ts +47 -5
  326. package/src/runtime/execution/process-runtime/process-scope.ts +160 -0
  327. package/src/runtime/execution/process-runtime/resource-claims.ts +65 -61
  328. package/src/runtime/execution/process-runtime/runtime.ts +35 -2
  329. package/src/runtime/execution/process-runtime/store.ts +30 -2
  330. package/src/runtime/execution/process-runtime/types.ts +6 -1
  331. package/src/runtime/execution/workers/executor.ts +2 -6
  332. package/src/runtime/platform/service-inventory.ts +130 -0
  333. package/src/runtime/platform/service-manager.ts +8 -0
  334. package/src/runtime/plugins/action-application.ts +85 -28
  335. package/src/runtime/plugins/app-store-connect-adapter.ts +38 -14
  336. package/src/runtime/plugins/browser-adapter.ts +757 -34
  337. package/src/runtime/plugins/browser-automation-service.ts +23 -3
  338. package/src/runtime/plugins/browser-macos-bridge.ts +321 -29
  339. package/src/runtime/plugins/browser-manifest-surface.ts +45 -11
  340. package/src/runtime/plugins/browser-native-session-service.ts +63 -13
  341. package/src/runtime/plugins/browser-registration.ts +16 -0
  342. package/src/runtime/plugins/browser-runtime.ts +14 -1
  343. package/src/runtime/plugins/browser-session-authority.ts +2 -2
  344. package/src/runtime/plugins/browser-session-store.ts +46 -76
  345. package/src/runtime/plugins/capability-authorization-grants.ts +258 -62
  346. package/src/runtime/plugins/computer-chatgpt-browser-adapter-installer.ts +219 -0
  347. package/src/runtime/plugins/computer-chatgpt-macos-target.ts +891 -0
  348. package/src/runtime/plugins/computer-registration.ts +222 -11
  349. package/src/runtime/plugins/desktop-operator-external-policy.ts +36 -4
  350. package/src/runtime/plugins/desktop-operator-registration.ts +12 -4
  351. package/src/runtime/plugins/external-adapter.ts +42 -6
  352. package/src/runtime/plugins/external-registration.ts +21 -1
  353. package/src/runtime/plugins/gmail-adapter.ts +23 -2
  354. package/src/runtime/plugins/google-calendar-adapter.ts +2 -2
  355. package/src/runtime/plugins/google-shared.ts +14 -7
  356. package/src/runtime/plugins/google-tasks-adapter.ts +2 -2
  357. package/src/runtime/plugins/ios-adapter.ts +1 -1
  358. package/src/runtime/plugins/lightweight-action.ts +208 -2
  359. package/src/runtime/plugins/local-system-adapter.ts +12 -2
  360. package/src/runtime/plugins/managed-process-adapter.ts +12 -5
  361. package/src/runtime/plugins/plugin-action-sidecar.ts +17 -13
  362. package/src/runtime/plugins/plugin-management-adapter.ts +1 -1
  363. package/src/runtime/plugins/store.ts +602 -428
  364. package/src/runtime/plugins/types.ts +20 -0
  365. package/src/runtime/plugins/xiaohongshu-publish.ts +16 -0
  366. package/src/runtime/projections/invalidation.ts +7 -3
  367. package/src/runtime/projections/materialized-view.ts +80 -36
  368. package/src/runtime/recovery/actions.ts +3 -3
  369. package/src/runtime/recovery/capability-action-application.ts +46 -45
  370. package/src/runtime/recovery/lifecycle-inventory.ts +29 -29
  371. package/src/runtime/recovery/maintenance-executor.ts +374 -123
  372. package/src/runtime/recovery/store.ts +29 -11
  373. package/src/runtime/release/release-coordinator.ts +296 -0
  374. package/src/runtime/release/release-session.ts +716 -0
  375. package/src/runtime/release/release-state-migration.ts +25 -0
  376. package/src/runtime/resources/leases/store.ts +56 -25
  377. package/src/runtime/root/computer-composition.ts +191 -6
  378. package/src/runtime/root/controller-progression-composition.ts +192 -0
  379. package/src/runtime/root/controller-round-composition.ts +20 -1
  380. package/src/runtime/root/deployment-topology.ts +106 -0
  381. package/src/runtime/root/entry.ts +4 -3
  382. package/src/runtime/root/known-good-recovery.ts +184 -0
  383. package/src/runtime/root/local-bridge.ts +0 -1
  384. package/src/runtime/root/mcp-transport.ts +111 -18
  385. package/src/runtime/root/ownership.ts +261 -9
  386. package/src/runtime/root/package-connector-service.ts +105 -19
  387. package/src/runtime/root/package-runtime-release.ts +117 -18
  388. package/src/runtime/root/package-runtime-service.ts +17 -11
  389. package/src/runtime/root/release-execution-canary.ts +44 -12
  390. package/src/runtime/root/release-loader.ts +90 -8
  391. package/src/runtime/root/release-manifest.ts +80 -6
  392. package/src/runtime/root/release-materialize.ts +372 -28
  393. package/src/runtime/root/release-store.ts +395 -36
  394. package/src/runtime/root/runtime-lane.ts +191 -0
  395. package/src/runtime/root/runtime.ts +159 -27
  396. package/src/runtime/root/scheduled-controller-composition.ts +28 -3
  397. package/src/runtime/root/service-runner.ts +2 -2
  398. package/src/runtime/root/service.ts +36 -33
  399. package/src/runtime/root/status.ts +48 -0
  400. package/src/runtime/root/types.ts +32 -3
  401. package/src/runtime/root/workflow-supervisor-composition.ts +493 -0
  402. package/src/runtime/root/workflow-supervisor-runtime.ts +209 -0
  403. package/src/runtime/root/write-fence.ts +50 -2
  404. package/src/runtime/safe-tooling/google-credential-store.ts +76 -21
  405. package/src/runtime/safe-tooling/google-oauth-broker.ts +25 -7
  406. package/src/runtime/safe-tooling/workspace-auth.ts +1 -1
  407. package/src/runtime/shared/bounded-child-supervisor.ts +9 -1
  408. package/src/runtime/shared/process-environment.ts +20 -9
  409. package/src/runtime/shared/response-budget.ts +1 -3
  410. package/src/runtime/standalone-recovery/controller-home-migration.ts +16 -24
  411. package/src/runtime/standalone-recovery/core.ts +3702 -342
  412. package/src/runtime/standalone-recovery/entry.ts +469 -39
  413. package/src/runtime/standalone-recovery/installer.ts +262 -148
  414. package/src/runtime/standalone-recovery/mcp-server.ts +29 -193
  415. package/src/runtime/standalone-recovery/operation-lock.ts +1 -1
  416. package/src/runtime/standalone-recovery/performance.ts +54 -16
  417. package/src/runtime/standalone-recovery/release.ts +53 -5
  418. package/src/runtime/standalone-recovery/service-labels.ts +5 -2
  419. package/src/runtime/standalone-recovery/watchdog-heartbeat.ts +5 -2
  420. package/src/runtime/workflow/schedules/browser-probe.ts +17 -6
  421. package/src/runtime/workflow/schedules/chatgpt-automation-migration.ts +10 -3
  422. package/src/runtime/workflow/schedules/engine.ts +138 -172
  423. package/src/runtime/workflow/schedules/work-continuation.ts +44 -5
  424. package/src/runtime/workflows/runtime.ts +15 -19
  425. package/src/testing/test-governance.ts +5 -1
  426. package/supervisor/chatgpt-conversation.ts +23 -0
  427. package/supervisor/client.ts +201 -0
  428. package/supervisor/control-plane.ts +868 -0
  429. package/supervisor/entry.ts +15 -0
  430. package/supervisor/forge-validators.ts +80 -0
  431. package/supervisor/index.ts +5 -0
  432. package/supervisor/native-browser-adapter.ts +786 -0
  433. package/supervisor/native-messaging/host.ts +39 -0
  434. package/supervisor/native-messaging/manifest.ts +26 -0
  435. package/supervisor/native-messaging/protocol.ts +27 -0
  436. package/supervisor/paths.ts +18 -0
  437. package/supervisor/protocol.ts +202 -0
  438. package/supervisor/server.ts +404 -0
  439. package/supervisor/store.ts +1451 -0
  440. package/supervisor/tsconfig.json +8 -0
  441. package/supervisor/types.ts +255 -0
  442. package/adapters/chatgpt/controller-host.ts +0 -119
  443. package/adapters/mcp/controller-round-compatibility.ts +0 -184
  444. package/adapters/mcp/frozen-client-semantic-compatibility.ts +0 -292
  445. package/adapters/mcp/runtime-gateway/work-compat-adapter.ts +0 -502
  446. package/packages/kernel/progression/api/index.ts +0 -2
  447. package/packages/kernel/progression/application/projector.ts +0 -211
  448. package/packages/kernel/progression/domain/types.ts +0 -116
  449. package/packages/kernel/progression/index.ts +0 -1
  450. package/packages/kernel/scheduler/application/continuation-service.ts +0 -212
  451. package/packages/kernel/scheduler/domain/continuation.ts +0 -38
  452. package/packages/kernel/scheduler/infrastructure/continuation-dispatch-store.ts +0 -38
  453. package/packages/kernel/work/domain/admission-policy.ts +0 -34
  454. package/scripts/benchmark-background-check-overlap.ts +0 -228
  455. package/scripts/benchmark-computer-hotpath.ts +0 -255
  456. package/scripts/benchmark-controller-hotpath.ts +0 -212
  457. package/scripts/benchmark-controller-round2.ts +0 -191
  458. package/scripts/benchmark-ios-agent-device.ts +0 -511
  459. package/scripts/benchmark-mcp-host.sh +0 -117
  460. package/scripts/benchmark-mcp-transport.ts +0 -169
  461. package/scripts/benchmark-operational-memory-activation.ts +0 -235
  462. package/scripts/benchmark-operational-shadow.ts +0 -28
  463. package/scripts/benchmark-quality-harness.ts +0 -146
  464. package/scripts/benchmark-route-session-concurrency.ts +0 -915
  465. package/scripts/benchmark-thin-harness-gateway-ab.ts +0 -632
  466. package/scripts/benchmark-thin-harness-mcp-e2e.ts +0 -498
  467. package/scripts/benchmark-thin-harness.ts +0 -251
  468. package/scripts/benchmark-typescript-navigation.ts +0 -186
  469. package/scripts/benchmark-work-efficiency.ts +0 -334
  470. package/scripts/build-controller-ui.ts +0 -28
  471. package/scripts/check-npm-release.sh +0 -32
  472. package/scripts/check-public-release-surface.sh +0 -19
  473. package/scripts/check-release-published.sh +0 -57
  474. package/scripts/check-release-readiness.sh +0 -37
  475. package/scripts/check-release-version.mjs +0 -74
  476. package/scripts/check-tarball-install-smoke.sh +0 -150
  477. package/scripts/package-source-archive.sh +0 -147
  478. package/scripts/public-release-files.txt +0 -39
  479. package/scripts/public-release.ts +0 -174
  480. package/scripts/publish-release-tarball.sh +0 -27
  481. package/scripts/route-nl-vs-ts-eval.ts +0 -679
  482. package/scripts/stage-runtime-release.ts +0 -44
  483. package/src/cli/controller/progress.ts +0 -656
  484. package/src/cli/controller/work-mode.ts +0 -181
  485. package/src/cli/local-bridge/console-assets.ts +0 -17
  486. package/src/cli/local-bridge/dashboard.ts +0 -17
  487. package/src/cli/local-bridge/frontend/src/App.tsx +0 -10
  488. package/src/cli/local-bridge/frontend/src/components/Button.tsx +0 -1
  489. package/src/cli/local-bridge/frontend/src/components/DetailPane.tsx +0 -3
  490. package/src/cli/local-bridge/frontend/src/components/SearchField.tsx +0 -1
  491. package/src/cli/local-bridge/frontend/src/components/SectionHeader.tsx +0 -1
  492. package/src/cli/local-bridge/frontend/src/components/Segmented.tsx +0 -1
  493. package/src/cli/local-bridge/frontend/src/components/StatusText.tsx +0 -3
  494. package/src/cli/local-bridge/frontend/src/design/icons.tsx +0 -11
  495. package/src/cli/local-bridge/frontend/src/design/tokens.css +0 -8
  496. package/src/cli/local-bridge/frontend/src/features/automations/AutomationsView.tsx +0 -153
  497. package/src/cli/local-bridge/frontend/src/features/capabilities/CapabilitiesView.tsx +0 -37
  498. package/src/cli/local-bridge/frontend/src/features/overview/OverviewView.tsx +0 -183
  499. package/src/cli/local-bridge/frontend/src/features/repositories/RepositoriesView.tsx +0 -2
  500. package/src/cli/local-bridge/frontend/src/features/system/SystemView.tsx +0 -2
  501. package/src/cli/local-bridge/frontend/src/features/work/WorkView.tsx +0 -4
  502. package/src/cli/local-bridge/frontend/src/lib/api.ts +0 -30
  503. package/src/cli/local-bridge/frontend/src/lib/format.ts +0 -4
  504. package/src/cli/local-bridge/frontend/src/lib/routes.ts +0 -7
  505. package/src/cli/local-bridge/frontend/src/main.tsx +0 -1
  506. package/src/cli/local-bridge/frontend/src/shell/AppShell.tsx +0 -1
  507. package/src/cli/local-bridge/frontend/src/shell/CommandBar.tsx +0 -2
  508. package/src/cli/local-bridge/frontend/src/shell/Sidebar.tsx +0 -4
  509. package/src/cli/local-bridge/frontend/src/styles.css +0 -28
  510. package/src/cli/local-bridge/frontend/src/types.ts +0 -15
  511. package/src/cli/local-bridge/frontend/src/vite-env.d.ts +0 -1
  512. package/src/cli/local-bridge/frontend/vite.config.ts +0 -27
  513. package/src/cli/local-bridge/ui-dist/app.css +0 -1
  514. package/src/cli/local-bridge/ui-dist/app.js +0 -11228
  515. package/src/runtime/control-plane/execution/content-equivalent-commit-authority.ts +0 -169
  516. package/src/runtime/control-plane/execution/direct-canonical-work-reconciliation.ts +0 -85
  517. package/src/runtime/control-plane/execution/direct-edit-work-completion.ts +0 -655
  518. package/src/runtime/control-plane/execution/work-finalization-service.ts +0 -2850
  519. package/src/runtime/control-plane/execution/work-path-scope.ts +0 -37
  520. package/src/runtime/control-plane/execution/work-task-receipt.ts +0 -468
  521. package/src/runtime/control-plane/facade/controller-round-relay.ts +0 -3
  522. package/src/runtime/control-plane/facade/work-admission-policy.ts +0 -142
  523. package/src/runtime/control-plane/facade/work-implementation-review.ts +0 -2
  524. package/src/runtime/control-plane/facade/work-state-machine.ts +0 -2
  525. package/src/runtime/control-plane/facade/work-task-projection.ts +0 -66
  526. package/src/runtime/control-plane/routing/index.ts +0 -1
  527. package/src/runtime/control-plane/routing/route-policy.ts +0 -401
  528. package/src/runtime/control-plane/routing/workspace-admission.ts +0 -70
@@ -0,0 +1,25 @@
1
+ import { migrateReleaseSessionState, type ReleaseSessionStateMigration } from './release-session';
2
+ import { migrateRuntimeReleaseAuthorityState, readRuntimeReleaseAuthority, type RuntimeReleaseAuthority } from '../root/release-store';
3
+
4
+ export interface ReleaseDurableStateMigration {
5
+ authority?: RuntimeReleaseAuthority;
6
+ sessions: ReleaseSessionStateMigration;
7
+ }
8
+
9
+ /**
10
+ * One migration boundary for all persisted Runtime release semantics.
11
+ * Runtime and Recovery cross this boundary before they declare themselves ready
12
+ * or consume ReleaseSession state. RuntimeReleaseAuthority upgrades its storage
13
+ * schema; ReleaseSession keeps downgrade-readable wire schema 1 while migrating
14
+ * once to semanticEpoch 2. Steady-state readers consume only the current model.
15
+ */
16
+ export function migrateReleaseDurableState(controllerHome: string): ReleaseDurableStateMigration {
17
+ const authority = migrateRuntimeReleaseAuthorityState(controllerHome);
18
+ const sessions = migrateReleaseSessionState(controllerHome, {
19
+ readAuthority: () => authority ?? readRuntimeReleaseAuthority(controllerHome),
20
+ });
21
+ return {
22
+ ...(authority ? { authority } : {}),
23
+ sessions,
24
+ };
25
+ }
@@ -1,7 +1,7 @@
1
1
  import { createHash, randomUUID } from 'crypto';
2
2
  import { existsSync, readdirSync } from 'fs';
3
3
  import { join } from 'path';
4
- import { repositoryControllerRoot } from '../../../cli/repositories/controller-home';
4
+ import { controllerSystemRoot } from '../../../cli/repositories/controller-home';
5
5
  import { ControllerLockContentionError, withControllerLock } from '../../../cli/repositories/locks';
6
6
  import type { ResourceClaimSpec } from '../../execution/jobs/types';
7
7
  import { readJsonFile, removeFile, writeJsonAtomic } from '../../shared/json-files';
@@ -9,7 +9,7 @@ import { markRepositoryProjectionDirty } from '../../projections/invalidation';
9
9
  import { touchSchedulerWakeSignal } from '../../control-plane/global-scheduler/wake-signal';
10
10
  import { claimsConflict } from '../claims/conflicts';
11
11
  import { appendRuntimeEvent } from '../../evidence/event-ledger';
12
- import { assertRuntimeMayWrite, assertRuntimeMayWriteOrThrow } from '../../root/write-fence';
12
+ import { assertRuntimeMayWrite, assertRuntimeMayWriteOrThrow, getRuntimeWriteClaim, isRuntimeWriteFenceError } from '../../root/write-fence';
13
13
  import type {
14
14
  ExecutionLease,
15
15
  LeaseAcquisitionOptions,
@@ -18,8 +18,10 @@ import type {
18
18
  ExecutionLeaseOwnerIdentity,
19
19
  } from './types';
20
20
 
21
- function leaseRoot(controllerHome: string, repoId: string): string {
22
- return join(repositoryControllerRoot(controllerHome, repoId), 'leases');
21
+ function leaseRoot(controllerHome: string, _repoId: string): string {
22
+ // Concrete resource leases coordinate across the whole ForgeInstance. repoId
23
+ // is provenance/filter metadata, never the storage partition.
24
+ return join(controllerSystemRoot(controllerHome), 'execution-leases');
23
25
  }
24
26
  function activeRoot(controllerHome: string, repoId: string): string { return join(leaseRoot(controllerHome, repoId), 'active'); }
25
27
  function leasePath(controllerHome: string, repoId: string, leaseId: string): string { return join(activeRoot(controllerHome, repoId), `${leaseId}.json`); }
@@ -29,6 +31,21 @@ function counterPath(controllerHome: string, repoId: string, resourceKey: string
29
31
  }
30
32
  function expired(lease: ExecutionLease): boolean { return Date.parse(lease.expiresAt) <= Date.now(); }
31
33
 
34
+ function currentManagedRuntimeClaim(controllerHome: string) {
35
+ const fence = assertRuntimeMayWrite(undefined, controllerHome);
36
+ if (!fence.allowed) return undefined;
37
+ const current = getRuntimeWriteClaim();
38
+ return current && !current.unmanaged ? current : undefined;
39
+ }
40
+
41
+ function fencedEphemeralOwner(lease: ExecutionLease, current: ReturnType<typeof getRuntimeWriteClaim>): boolean {
42
+ if (lease.visibility !== 'ephemeral' || !lease.ownerIdentity || !current || current.unmanaged) return false;
43
+ const ownerInstanceId = lease.ownerIdentity.controllerInstanceId?.trim();
44
+ const ownerGeneration = lease.ownerIdentity.controllerGeneration?.trim();
45
+ if (!ownerInstanceId || !ownerGeneration || ownerGeneration === 'unbound') return false;
46
+ return ownerInstanceId !== current.runtimeInstanceId;
47
+ }
48
+
32
49
  function validateClaimScopes(repoId: string, claims: ResourceClaimSpec[]): void {
33
50
  const checkoutIds = new Set<string>();
34
51
  const workIds = new Set<string>();
@@ -82,10 +99,12 @@ function normalizedOwnerIdentity(
82
99
  branch: provided?.branch?.trim() || 'unknown',
83
100
  principalId: provided?.principalId?.trim() || `owner:${ownerJobId}`,
84
101
  controllerInstanceId: provided?.controllerInstanceId?.trim()
102
+ || process.env.FORGE_RUNTIME_INSTANCE_ID?.trim()
85
103
  || process.env.FORGE_WRITER_INSTANCE_ID?.trim()
86
104
  || process.env.FORGE_DAEMON_INSTANCE_ID?.trim()
87
105
  || `process:${process.pid}`,
88
106
  controllerGeneration: provided?.controllerGeneration?.trim()
107
+ || process.env.FORGE_RUNTIME_INCARNATION_GENERATION?.trim()
89
108
  || process.env.FORGE_WRITER_GENERATION?.trim()
90
109
  || process.env.FORGE_ACTIVE_RUNTIME_REVISION?.trim()
91
110
  || 'unbound',
@@ -139,19 +158,29 @@ export function resetLeaseSideEffectMetrics(): void {
139
158
  leaseSideEffectMetrics.ephemeralReleases = 0;
140
159
  }
141
160
 
142
- export function listActiveLeases(controllerHome: string, repoId: string): ExecutionLease[] {
143
- try {
144
- const leases: ExecutionLease[] = [];
145
- for (const name of readdirSync(activeRoot(controllerHome, repoId)).filter((entry) => entry.endsWith('.json'))) {
146
- const path = join(activeRoot(controllerHome, repoId), name);
147
- try {
148
- const lease = readJsonFile<ExecutionLease>(path);
149
- if (expired(lease)) removeFile(path);
150
- else leases.push(lease);
151
- } catch { removeFile(path); }
161
+ function listAllActiveLeases(controllerHome: string): ExecutionLease[] {
162
+ const root = activeRoot(controllerHome, '__instance__');
163
+ if (!existsSync(root)) return [];
164
+ const currentRuntime = currentManagedRuntimeClaim(controllerHome);
165
+ const leases: ExecutionLease[] = [];
166
+ for (const name of readdirSync(root).filter((entry) => entry.endsWith('.json'))) {
167
+ const path = join(root, name);
168
+ try {
169
+ const lease = readJsonFile<ExecutionLease>(path);
170
+ if (!lease?.leaseId || !lease.repoId || !lease.resourceKey || !lease.ownerJobId) {
171
+ throw new Error('required lease identity is missing');
172
+ }
173
+ if (expired(lease) || fencedEphemeralOwner(lease, currentRuntime)) removeFile(path);
174
+ else leases.push(lease);
175
+ } catch (error) {
176
+ throw new Error(`LEASE_STORE_CORRUPT: ${path}: ${error instanceof Error ? error.message : String(error)}`);
152
177
  }
153
- return leases;
154
- } catch { return []; }
178
+ }
179
+ return leases;
180
+ }
181
+
182
+ export function listActiveLeases(controllerHome: string, repoId: string): ExecutionLease[] {
183
+ return listAllActiveLeases(controllerHome).filter((lease) => lease.repoId === repoId);
155
184
  }
156
185
 
157
186
  export function acquireExecutionLeases(
@@ -186,8 +215,9 @@ export function acquireExecutionLeases(
186
215
  const identityDigest = ownerIdentityDigest(ownerIdentity);
187
216
 
188
217
  try {
189
- return withControllerLock(controllerHome, { scope: 'repository', repoId }, `lease-acquire:${ownerJobId}`, () => {
190
- const active = listActiveLeases(controllerHome, repoId).filter((lease) => lease.ownerJobId !== ownerJobId);
218
+ return withControllerLock(controllerHome, { scope: 'global', resource: 'execution-leases' }, `lease-acquire:${ownerJobId}`, () => {
219
+ const active = listAllActiveLeases(controllerHome)
220
+ .filter((lease) => lease.ownerJobId !== ownerJobId || lease.repoId !== repoId);
191
221
  const blockers = claims.flatMap((claim) => active
192
222
  .filter((lease) => claimsConflict(claim, lease))
193
223
  .map((lease) => ({ resourceKey: lease.resourceKey, ownerJobId: lease.ownerJobId, leaseId: lease.leaseId, mode: lease.mode, ownerIdentityDigest: lease.ownerIdentityDigest })));
@@ -297,10 +327,10 @@ export function renewExecutionLeases(
297
327
  try {
298
328
  assertRuntimeMayWriteOrThrow('renew_lease', controllerHome);
299
329
  } catch (error) {
300
- if (error instanceof Error && error.message.startsWith('WRITER_FENCED:')) throw error;
330
+ if (isRuntimeWriteFenceError(error)) throw error;
301
331
  /* unbound legacy */
302
332
  }
303
- return withControllerLock(controllerHome, { scope: 'repository', repoId }, `lease-renew:${ownerJobId}`, () => {
333
+ return withControllerLock(controllerHome, { scope: 'global', resource: 'execution-leases' }, `lease-renew:${ownerJobId}`, () => {
304
334
  const expectedRefs = expectedLeaseMap(expected);
305
335
  const timestamp = new Date().toISOString();
306
336
  const owned = listActiveLeases(controllerHome, repoId)
@@ -329,10 +359,10 @@ export function releaseExecutionLeases(
329
359
  try {
330
360
  assertRuntimeMayWriteOrThrow('release_lease', controllerHome);
331
361
  } catch (error) {
332
- if (error instanceof Error && error.message.startsWith('WRITER_FENCED:')) throw error;
362
+ if (isRuntimeWriteFenceError(error)) throw error;
333
363
  /* unbound legacy */
334
364
  }
335
- return withControllerLock(controllerHome, { scope: 'repository', repoId }, `lease-release:${ownerJobId}`, () => {
365
+ return withControllerLock(controllerHome, { scope: 'global', resource: 'execution-leases' }, `lease-release:${ownerJobId}`, () => {
336
366
  const expectedRefs = expectedLeaseMap(expected);
337
367
  let releasedCount = 0;
338
368
  let visibility: LeaseVisibility = options?.visibility ?? 'durable';
@@ -384,10 +414,10 @@ export function releaseExactExecutionLeases(
384
414
  try {
385
415
  assertRuntimeMayWriteOrThrow('release_lease', controllerHome);
386
416
  } catch (error) {
387
- if (error instanceof Error && error.message.startsWith('WRITER_FENCED:')) throw error;
417
+ if (isRuntimeWriteFenceError(error)) throw error;
388
418
  /* unbound legacy */
389
419
  }
390
- return withControllerLock(controllerHome, { scope: 'repository', repoId }, `lease-release-exact:${ownerJobId}`, () => {
420
+ return withControllerLock(controllerHome, { scope: 'global', resource: 'execution-leases' }, `lease-release-exact:${ownerJobId}`, () => {
391
421
  const expectedRefs = expectedLeaseMap(expected) ?? new Map<string, ExpectedLeaseRef>();
392
422
  if (expectedRefs.size !== expected.length) {
393
423
  throw new Error(`LEASE_SET_INVALID: ${ownerJobId} contains duplicate lease ids`);
@@ -460,7 +490,7 @@ export function releaseTerminalProcessLeases(
460
490
  const normalizedProcessId = processId.trim();
461
491
  if (!normalizedProcessId) throw new Error('TERMINAL_PROCESS_ID_REQUIRED');
462
492
  const ownerJobId = `process:${normalizedProcessId}`;
463
- return withControllerLock(controllerHome, { scope: 'repository', repoId }, `terminal-lease-release:${ownerJobId}`, () => {
493
+ return withControllerLock(controllerHome, { scope: 'global', resource: 'execution-leases' }, `terminal-lease-release:${ownerJobId}`, () => {
464
494
  const expectedRefs = expectedLeaseMap(expected) ?? new Map<string, ExpectedLeaseRef>();
465
495
  if (expectedRefs.size !== expected.length) {
466
496
  throw new Error(`TERMINAL_PROCESS_LEASE_SET_INVALID: ${normalizedProcessId} contains duplicate lease ids`);
@@ -530,6 +560,7 @@ export function assertFencingToken(
530
560
  const path = leasePath(controllerHome, repoId, leaseId);
531
561
  if (!existsSync(path)) throw new Error(`LEASE_EXPIRED: ${leaseId}`);
532
562
  const lease = readJsonFile<ExecutionLease>(path);
563
+ if (lease.repoId !== repoId) throw new Error(`LEASE_REPOSITORY_SCOPE_MISMATCH: expected ${repoId}, received ${lease.repoId}`);
533
564
  if (expired(lease)) {
534
565
  removeFile(path);
535
566
  throw new Error(`LEASE_EXPIRED: ${leaseId}`);
@@ -3,9 +3,12 @@ import {
3
3
  ComputerProviderRegistry,
4
4
  computerProviderRegistrationSnapshot,
5
5
  } from '../../../packages/plugin-runtime/computer/index';
6
+ import { randomUUID } from 'crypto';
6
7
  import {
7
8
  COMPUTER_BROWSER_AUTOMATION_CAPABILITY,
8
9
  COMPUTER_CONSOLE_UNLOCK_CAPABILITY,
10
+ COMPUTER_ELEMENT_OBSERVE_CAPABILITY,
11
+ COMPUTER_INPUT_CAPABILITY,
9
12
  type ComputerBrowserAutomationRequest,
10
13
  type ComputerBrowserProduct,
11
14
  type ComputerConsoleUnlockCommandRequest,
@@ -37,7 +40,7 @@ function computerCompositionKey(controllerHome: string): string {
37
40
  const registration = currentDesktopOperatorRegistration(controllerHome);
38
41
  const fingerprint = registration
39
42
  ? `${registration.revision}:${registration.registrationFingerprint}:${registration.enabled ? 'enabled' : 'disabled'}`
40
- : 'desktop_operator:unregistered_v0_2';
43
+ : 'desktop_operator:unregistered';
41
44
  return `${controllerHome}:${currentComputerPlatform()}:${fingerprint}`;
42
45
  }
43
46
 
@@ -54,9 +57,6 @@ function ensureComputerComposition(controllerHome: string = resolveControllerHom
54
57
  if (providerPluginId !== DESKTOP_OPERATOR_PROVIDER_PLUGIN_ID || !registration) return undefined;
55
58
  return computerProviderRegistrationSnapshot(registration);
56
59
  },
57
- // Compatibility is an explicit Runtime composition decision, never an adapter fallback.
58
- // Remove this switch once Desktop Operator 0.2.x support is retired.
59
- legacyFallback: 'unregistered_v0_2',
60
60
  });
61
61
  next.register(desktopOperatorProvider);
62
62
  }
@@ -111,8 +111,8 @@ export async function executeRuntimeComputerConsoleUnlock(
111
111
  controllerHome: string = resolveControllerHome(),
112
112
  ): Promise<Record<string, unknown>> {
113
113
  if (request.capability !== COMPUTER_CONSOLE_UNLOCK_CAPABILITY
114
- || !['prepare_unlock_console', 'unlock_console'].includes(request.action)) {
115
- throw new AssistantPluginError('COMPUTER_CONSOLE_UNLOCK_REQUEST_INVALID', 'Protected console unlock accepts only computer.console.unlock.v1 prepare/unlock commands.', { retryable: false });
114
+ || !['prepare_unlock_console', 'unlock_console', 'console_unlock_enroll', 'console_unlock_status', 'console_unlock_recover', 'console_unlock_revoke'].includes(request.action)) {
115
+ throw new AssistantPluginError('COMPUTER_CONSOLE_UNLOCK_REQUEST_INVALID', 'Protected console unlock accepts only declared computer.console.unlock.v1 temporary or unattended-recovery commands.', { retryable: false });
116
116
  }
117
117
  if (authorization.kind !== 'explicit_single_use'
118
118
  || authorization.confirmed !== true
@@ -143,6 +143,191 @@ export async function executeRuntimeComputerBrowserAutomation(
143
143
  return await desktopOperatorProvider.executeBrowserCompatibility(request, timeoutMs);
144
144
  }
145
145
 
146
+ type BrowserTrustedInputSemanticProof = {
147
+ domRole: string;
148
+ accessibleName: string;
149
+ editable: true;
150
+ focused: true;
151
+ multiline: boolean;
152
+ };
153
+ type BrowserTrustedInputRequest = Extract<ComputerBrowserAutomationRequest, { action: 'trusted_input' }> & {
154
+ semanticTarget?: BrowserTrustedInputSemanticProof;
155
+ };
156
+ function objectValue(value: unknown): Record<string, unknown> | undefined {
157
+ return value && typeof value === 'object' && !Array.isArray(value) ? value as Record<string, unknown> : undefined;
158
+ }
159
+ function stringValue(record: Record<string, unknown> | undefined, ...keys: string[]): string {
160
+ for (const key of keys) {
161
+ const value = record?.[key];
162
+ if (typeof value === 'string' && value.trim()) return value.trim();
163
+ }
164
+ return '';
165
+ }
166
+ function browserTrustedInputAction(
167
+ controllerHome: string,
168
+ actionId: string,
169
+ args: Record<string, unknown>,
170
+ requestId: string,
171
+ timeoutMs: number,
172
+ ): AssistantPluginActionExecutionInput {
173
+ return {
174
+ controllerHome,
175
+ repoId: '__controller__',
176
+ repoRoot: controllerHome,
177
+ pluginId: DESKTOP_OPERATOR_PROVIDER_PLUGIN_ID,
178
+ actionId,
179
+ requestId,
180
+ args,
181
+ origin: { surface: 'system', actor: 'native-browser-trusted-input' },
182
+ timeoutMs,
183
+ };
184
+ }
185
+
186
+ /**
187
+ * Trusted text/key input is a Unified Computer concern, not Browser compatibility.
188
+ * Browser owns the exact tab and DOM identity; the Desktop Operator interaction is
189
+ * a short-lived transport binding used only after that exact tab is already
190
+ * foreground. No provider session is promoted into a second semantic authority.
191
+ */
192
+ export async function executeRuntimeComputerBrowserTrustedInput(
193
+ request: BrowserTrustedInputRequest,
194
+ timeoutMs: number,
195
+ controllerHome: string = resolveControllerHome(),
196
+ ): Promise<Record<string, unknown>> {
197
+ if (request.input.kind !== 'text' && request.input.kind !== 'key') {
198
+ throw new AssistantPluginError(
199
+ 'PLUGIN_BROWSER_NATIVE_UNIFIED_INPUT_KIND_UNSUPPORTED',
200
+ `Unified native Browser input handles text/key only, not ${request.input.kind}.`,
201
+ { retryable: false, details: { browserProduct: request.product, inputKind: request.input.kind } },
202
+ );
203
+ }
204
+ if (currentComputerPlatform() !== 'darwin') {
205
+ throw new AssistantPluginError(
206
+ 'PLUGIN_BROWSER_NATIVE_TRUSTED_INPUT_UNSUPPORTED_PLATFORM',
207
+ `Native Browser trusted input is unavailable on ${currentComputerPlatform()}.`,
208
+ { retryable: false, details: { browserProduct: request.product } },
209
+ );
210
+ }
211
+ const expectedBundleId = NATIVE_BROWSER_BUNDLE_IDS[request.product];
212
+ const desktopOperator = getExternalPluginAdapter(controllerHome, DESKTOP_OPERATOR_PROVIDER_PLUGIN_ID);
213
+ if (!desktopOperator) {
214
+ throw new AssistantPluginError(
215
+ 'PLUGIN_BROWSER_TRUSTED_INPUT_UNAVAILABLE',
216
+ 'Native Browser trusted input requires the Unified Computer provider.',
217
+ { retryable: true, details: { browserProduct: request.product, providerId: DESKTOP_OPERATOR_PROVIDER_PLUGIN_ID } },
218
+ );
219
+ }
220
+ const invocationId = randomUUID();
221
+ let interactionId = '';
222
+ let effectCompleted = false;
223
+ try {
224
+ const opened = await desktopOperator.executeAction(browserTrustedInputAction(
225
+ controllerHome,
226
+ 'desktop_session_open',
227
+ { bundle_id: expectedBundleId, launch: false, activate: false },
228
+ `native-browser-trusted-input:${invocationId}:open`,
229
+ timeoutMs,
230
+ ));
231
+ interactionId = stringValue(opened, 'interactionId', 'interaction_id');
232
+ const observedBundleId = stringValue(opened, 'bundleIdentifier', 'bundle_id');
233
+ if (!interactionId || observedBundleId !== expectedBundleId) {
234
+ throw new AssistantPluginError(
235
+ observedBundleId ? 'PLUGIN_BROWSER_TRUSTED_INPUT_IDENTITY_MISMATCH' : 'PLUGIN_BROWSER_TRUSTED_INPUT_IDENTITY_UNVERIFIED',
236
+ 'Unified Computer did not bind the exact requested native browser application.',
237
+ { retryable: false, details: { browserProduct: request.product, expectedBundleId, observedBundleId: observedBundleId || undefined } },
238
+ );
239
+ }
240
+
241
+ if (request.input.kind === 'text') {
242
+ if (request.input.text.length > 10_000) {
243
+ throw new AssistantPluginError('PLUGIN_ACTION_ARGUMENT_INVALID', 'Trusted Browser text input must be at most 10000 characters.', { retryable: false });
244
+ }
245
+ const proof = request.semanticTarget;
246
+ if (!proof || proof.editable !== true || proof.focused !== true || !proof.accessibleName.trim() || !proof.domRole.trim()) {
247
+ throw new AssistantPluginError(
248
+ 'PLUGIN_BROWSER_TRUSTED_INPUT_SEMANTIC_TARGET_REQUIRED',
249
+ 'Unified Computer text input requires exact Browser-owned DOM semantic target proof.',
250
+ { retryable: false, details: { browserProduct: request.product } },
251
+ );
252
+ }
253
+ const expectedAxRole = proof.domRole === 'textbox'
254
+ ? (proof.multiline ? 'AXTextArea' : 'AXTextField')
255
+ : proof.domRole;
256
+ const observed = await executeRuntimeComputer({
257
+ capability: COMPUTER_ELEMENT_OBSERVE_CAPABILITY,
258
+ action: 'observe_elements',
259
+ interactionId,
260
+ maxDepth: 2,
261
+ maxNodes: 16,
262
+ includeValues: true,
263
+ rootSelector: { role: expectedAxRole },
264
+ }, timeoutMs, controllerHome);
265
+ const root = objectValue(observed.root);
266
+ const target = objectValue(root?.target);
267
+ const ref = stringValue(root, 'ref');
268
+ const targetInteractionId = stringValue(target, 'interactionId');
269
+ const targetBundleId = stringValue(target, 'bundleIdentifier');
270
+ const axAccessibleNames = [stringValue(root, 'description'), stringValue(root, 'name')].filter(Boolean);
271
+ const semanticIdentityMatches = axAccessibleNames.includes(proof.accessibleName.trim());
272
+ if (stringValue(root, 'role') !== expectedAxRole
273
+ || !semanticIdentityMatches
274
+ || !ref
275
+ || targetInteractionId !== interactionId
276
+ || targetBundleId !== expectedBundleId
277
+ || typeof target?.pid !== 'number'
278
+ || !Number.isInteger(target.pid)
279
+ || typeof target?.appName !== 'string'
280
+ || typeof target?.snapshotRevision !== 'number'
281
+ || !Number.isInteger(target.snapshotRevision)) {
282
+ throw new AssistantPluginError(
283
+ 'PLUGIN_BROWSER_TRUSTED_INPUT_SEMANTIC_TARGET_MISMATCH',
284
+ 'Unified Computer element identity no longer matches the Browser-owned active DOM target.',
285
+ { retryable: true, details: { browserProduct: request.product, interactionId, expectedAxRole, accessibleName: proof.accessibleName, observedRole: root?.role, observedNames: axAccessibleNames, ref: ref || undefined } },
286
+ );
287
+ }
288
+ // AX set_value can report success for Chromium contenteditable controls while
289
+ // React immediately restores the DOM value. Keep element.observe.v2 as the
290
+ // exact identity fence, then perform the actual text mutation through the
291
+ // Unified Computer input capability bound to that exact observed AX ref.
292
+ await executeRuntimeComputer({
293
+ capability: COMPUTER_INPUT_CAPABILITY,
294
+ action: 'type_text',
295
+ interactionId: targetInteractionId,
296
+ selector: { ref },
297
+ text: request.input.text,
298
+ replace: true,
299
+ }, timeoutMs, controllerHome);
300
+ } else {
301
+ await desktopOperator.executeAction(browserTrustedInputAction(
302
+ controllerHome,
303
+ 'desktop_key',
304
+ { interaction_id: interactionId, keys: [request.input.key] },
305
+ `native-browser-trusted-input:${invocationId}:key`,
306
+ timeoutMs,
307
+ ));
308
+ }
309
+ effectCompleted = true;
310
+ return { performed: true, transport: 'computer', inputKind: request.input.kind };
311
+ } finally {
312
+ if (interactionId) {
313
+ try {
314
+ await desktopOperator.executeAction(browserTrustedInputAction(
315
+ controllerHome,
316
+ 'desktop_session_close',
317
+ { interaction_id: interactionId },
318
+ `native-browser-trusted-input:${invocationId}:close`,
319
+ timeoutMs,
320
+ ));
321
+ } catch (error) {
322
+ // Provider-session cleanup is transport hygiene, never external-effect
323
+ // outcome authority. In particular, do not convert a confirmed text/key
324
+ // mutation into a replayable failure because session retirement failed.
325
+ process.stderr.write(`[computer-browser-trusted-input] cleanup_failed effect_completed=${effectCompleted} ${error instanceof Error ? error.message : String(error)}\n`);
326
+ }
327
+ }
328
+ }
329
+ }
330
+
146
331
  export async function activateRuntimeComputerBrowserApplication(
147
332
  input: AssistantPluginActionExecutionInput,
148
333
  product: ComputerBrowserProduct,
@@ -0,0 +1,192 @@
1
+ import {
2
+ beginControllerRoundRelayAfterRelease,
3
+ controllerRoundBlockerClass,
4
+ getControllerRoundRelay,
5
+ getControllerWorkBinding,
6
+ getRetainedControllerSession,
7
+ prepareControllerRoundOccurrence,
8
+ resumeControllerRoundOccurrence,
9
+ type ControllerBinding,
10
+ type ControllerHost,
11
+ } from '../../../packages/kernel/controller/api/index';
12
+ import { getWorkContract, semanticWorkState } from '../../../packages/kernel/work/api/index';
13
+ import {
14
+ controllerHostForScheduledBinding,
15
+ ensureScheduledControllerBindingForWork,
16
+ } from './scheduled-controller-composition';
17
+ import {
18
+ ensureWorkflowSupervisorEnrollmentForWork,
19
+ type WorkflowSupervisorEnrollmentStatus,
20
+ } from './workflow-supervisor-composition';
21
+
22
+ export interface ControllerProgressionInput {
23
+ workId: string;
24
+ occurrenceId: string;
25
+ relayScopeId?: string;
26
+ continuationHint?: string;
27
+ allowSemanticWaitRecovery?: boolean;
28
+ scheduleName?: string;
29
+ bindingArgs?: Record<string, unknown>;
30
+ }
31
+
32
+ export interface ControllerProgressionDependencies {
33
+ ensureBinding?: typeof ensureScheduledControllerBindingForWork;
34
+ hostForBinding?: typeof controllerHostForScheduledBinding;
35
+ prepareOccurrence?: typeof prepareControllerRoundOccurrence;
36
+ resumeOccurrence?: typeof resumeControllerRoundOccurrence;
37
+ ensureSupervisorEnrollment?: typeof ensureWorkflowSupervisorEnrollmentForWork;
38
+ }
39
+
40
+ export type ControllerProgressionResult =
41
+ | { status: 'terminal_or_missing'; reason: string }
42
+ | { status: 'retained_session_missing'; reason: string }
43
+ | { status: 'human_controller'; reason: string }
44
+ | { status: 'semantic_wait'; reason?: string; binding: ControllerBinding }
45
+ | { status: 'wait_for_user'; reason?: string; binding: ControllerBinding }
46
+ | { status: 'rejected'; reason?: string; binding: ControllerBinding }
47
+ | {
48
+ status: 'chatgpt_enrolled';
49
+ binding: ControllerBinding;
50
+ relayScopeId: string;
51
+ reused: boolean;
52
+ supervisorEnrollment: {
53
+ status: WorkflowSupervisorEnrollmentStatus;
54
+ taskId?: string;
55
+ effectId?: string;
56
+ reason?: string;
57
+ };
58
+ }
59
+ | {
60
+ status: 'chatgpt_not_enrolled';
61
+ binding: ControllerBinding;
62
+ relayScopeId: string;
63
+ reused: boolean;
64
+ supervisorEnrollment: {
65
+ status: WorkflowSupervisorEnrollmentStatus;
66
+ taskId?: string;
67
+ effectId?: string;
68
+ reason?: string;
69
+ };
70
+ }
71
+ | {
72
+ status: 'provider_dispatched';
73
+ binding: ControllerBinding;
74
+ relayScopeId: string;
75
+ reused: boolean;
76
+ providerDispatchReceiptId?: string;
77
+ };
78
+
79
+ /**
80
+ * Stateless composition for one already-authorized Controller progression
81
+ * occurrence. It owns no persistence and introduces no lifecycle state.
82
+ *
83
+ * Work decides semantic terminality. ControllerSession/ControllerRound provide
84
+ * retained execution identity and one mechanical occurrence. Workflow Supervisor
85
+ * exclusively reserves and delivers Work-bound ChatGPT effects. Non-ChatGPT
86
+ * ControllerHost remains the direct provider boundary.
87
+ */
88
+ export async function reconcileControllerProgression(
89
+ options: { controllerHome: string; repoId: string; repoRoot: string },
90
+ input: ControllerProgressionInput,
91
+ dependencies: ControllerProgressionDependencies = {},
92
+ ): Promise<ControllerProgressionResult> {
93
+ const store = { controllerHome: options.controllerHome, repoId: options.repoId };
94
+ const work = getWorkContract(store, input.workId);
95
+ if (!work || semanticWorkState(work) !== 'open') {
96
+ return { status: 'terminal_or_missing', reason: work ? `WORK_TERMINAL:${semanticWorkState(work)}` : 'WORK_NOT_FOUND' };
97
+ }
98
+
99
+ const retainedSession = getRetainedControllerSession(store, input.workId);
100
+ if (!retainedSession) return { status: 'retained_session_missing', reason: 'CONTROLLER_SESSION_NOT_RETAINED' };
101
+ if (retainedSession.controllerType === 'human') return { status: 'human_controller', reason: 'HUMAN_CONTROLLER' };
102
+
103
+ const ensureBinding = dependencies.ensureBinding ?? ensureScheduledControllerBindingForWork;
104
+ const existingBinding = getControllerWorkBinding(store, input.workId)?.binding;
105
+ const binding = existingBinding ?? ensureBinding(store, {
106
+ workId: input.workId,
107
+ session: retainedSession,
108
+ scheduleName: input.scheduleName,
109
+ args: input.bindingArgs ?? {},
110
+ });
111
+
112
+ if (retainedSession.controllerType === 'chatgpt') {
113
+ const ensureSupervisorEnrollment = dependencies.ensureSupervisorEnrollment ?? ensureWorkflowSupervisorEnrollmentForWork;
114
+ let existingRound = getControllerRoundRelay(store, input.workId);
115
+ let controllerRoundOccurrenceId = input.occurrenceId;
116
+ if (existingRound?.status === 'pending_release') {
117
+ // The semantic turn already chose continue_immediately. Once its exact
118
+ // ControllerSession lease has been released, reopen that same durable
119
+ // ControllerRound for dispatch before reserving another Supervisor effect.
120
+ // Schedule occurrence ids are trigger evidence, not a replacement
121
+ // ControllerRound identity for an already-open continuation chain.
122
+ existingRound = beginControllerRoundRelayAfterRelease(store, {
123
+ workId: input.workId,
124
+ releasedSession: retainedSession,
125
+ }) ?? getControllerRoundRelay(store, input.workId);
126
+ }
127
+ // An already-open recoverable ControllerRound keeps its durable occurrence
128
+ // identity across Scheduler wake attempts. A fresh ScheduleOccurrence is
129
+ // trigger/evidence identity only; replacing the round occurrence here would
130
+ // manufacture a second open round and permanently self-block continuation.
131
+ if (existingRound?.occurrenceId?.trim()
132
+ && ['dispatching', 'dispatched', 'claimed'].includes(existingRound.status)) {
133
+ controllerRoundOccurrenceId = existingRound.occurrenceId.trim();
134
+ }
135
+ if (existingRound?.status === 'blocked'
136
+ && controllerRoundBlockerClass(existingRound) === 'provider_dispatch_outcome_unknown') {
137
+ const supervisorEnrollment = await ensureSupervisorEnrollment(store, input.workId);
138
+ return {
139
+ status: supervisorEnrollment.status === 'enrolled' ? 'chatgpt_enrolled' : 'chatgpt_not_enrolled',
140
+ binding,
141
+ relayScopeId: existingRound.relayScopeId,
142
+ reused: true,
143
+ supervisorEnrollment,
144
+ };
145
+ }
146
+
147
+ const prepareOccurrence = dependencies.prepareOccurrence ?? prepareControllerRoundOccurrence;
148
+ const prepared = prepareOccurrence(store, {
149
+ occurrenceId: controllerRoundOccurrenceId,
150
+ workId: input.workId,
151
+ controllerBindingId: binding.bindingId,
152
+ relayScopeId: input.relayScopeId,
153
+ continuationHint: input.continuationHint,
154
+ allowSemanticWaitRecovery: input.allowSemanticWaitRecovery,
155
+ });
156
+ if (prepared.outcome === 'semantic_wait') return { status: 'semantic_wait', reason: prepared.reason, binding };
157
+ if (prepared.outcome === 'wait_for_user') return { status: 'wait_for_user', reason: prepared.reason, binding };
158
+ if (prepared.outcome === 'rejected') return { status: 'rejected', reason: prepared.reason, binding };
159
+
160
+ const supervisorEnrollment = await ensureSupervisorEnrollment(store, input.workId);
161
+ return {
162
+ status: supervisorEnrollment.status === 'enrolled' ? 'chatgpt_enrolled' : 'chatgpt_not_enrolled',
163
+ binding,
164
+ relayScopeId: prepared.relay.relayScopeId,
165
+ reused: prepared.reused,
166
+ supervisorEnrollment,
167
+ };
168
+ }
169
+
170
+ const hostForBinding = dependencies.hostForBinding ?? controllerHostForScheduledBinding;
171
+ const host: ControllerHost = hostForBinding(options, binding);
172
+ const resumeOccurrence = dependencies.resumeOccurrence ?? resumeControllerRoundOccurrence;
173
+ const resumed = await resumeOccurrence(store, {
174
+ occurrenceId: input.occurrenceId,
175
+ workId: input.workId,
176
+ controllerBindingId: binding.bindingId,
177
+ relayScopeId: input.relayScopeId,
178
+ continuationHint: input.continuationHint,
179
+ allowSemanticWaitRecovery: input.allowSemanticWaitRecovery,
180
+ }, host);
181
+
182
+ if (resumed.outcome === 'semantic_wait') return { status: 'semantic_wait', reason: resumed.reason, binding };
183
+ if (resumed.outcome === 'wait_for_user') return { status: 'wait_for_user', reason: resumed.reason, binding };
184
+ if (resumed.outcome === 'rejected') return { status: 'rejected', reason: resumed.reason, binding };
185
+ return {
186
+ status: 'provider_dispatched',
187
+ binding,
188
+ relayScopeId: resumed.relay.relayScopeId,
189
+ reused: resumed.reused,
190
+ providerDispatchReceiptId: resumed.providerDispatchReceiptId,
191
+ };
192
+ }