@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
@@ -10,7 +10,7 @@ import {
10
10
  previewAutomaticRuntimeMaintenance,
11
11
  type RuntimeMaintenanceActionId,
12
12
  } from '../../recovery/maintenance-executor';
13
- import { appendWorkEvidence, getWorkContract, isTerminalWorkContractStatus } from '../../../../packages/kernel/work/api/index';
13
+ import { appendWorkEvidence, getWorkContract, semanticWorkState } from '../../../../packages/kernel/work/api/index';
14
14
  import {
15
15
  controllerSessionBlocksRecovery,
16
16
  getControllerSession,
@@ -27,16 +27,16 @@ import {
27
27
  getSchedule,
28
28
  listActiveOccurrences,
29
29
  listOccurrences,
30
- recordScheduleOccurrenceHandoff,
31
- resumeScheduledControllerContinuation,
30
+ reclaimStaleCreatedOccurrences,
32
31
  listSchedules,
33
32
  saveOccurrence,
34
33
  saveScheduleDecision,
35
34
  updateSchedule,
36
35
  } from '../../../../packages/kernel/scheduler/api/index';
37
36
  export { cronDue };
38
- import { ensureScheduledControllerBinding, controllerHostForScheduledBinding } from '../../root/scheduled-controller-composition';
39
- import { listHandoffItems } from '../../control-plane/facade/handoff-inbox-store';
37
+ import { ensureScheduledControllerBinding } from '../../root/scheduled-controller-composition';
38
+ import { reconcileControllerProgression } from '../../root/controller-progression-composition';
39
+ import { listUserRequests } from '../../../../packages/kernel/identity/api/index';
40
40
  import { runStandaloneChatgptPrompt } from '../../control-plane/launcher/chatgpt-work-continuation';
41
41
 
42
42
  import { classifyScheduledBrowserObservation, executeScheduledBrowserProbe } from './browser-probe';
@@ -92,30 +92,18 @@ function workBoundScheduleWorkId(schedule: RepositorySchedule): string | undefin
92
92
  return typeof value === 'string' && value.trim() ? value.trim() : undefined;
93
93
  }
94
94
 
95
- const HUMAN_ONLY_HANDOFF_REASONS = new Set([
96
- 'policy_approval_required',
97
- 'missing_authorization',
98
- 'invalid_objective',
99
- 'destructive_action_requires_confirmation',
100
- ]);
101
-
102
- function handoffRequiresHumanReview(item: ReturnType<typeof listHandoffItems>[number]): boolean {
103
- if (item.approvalAction) return true;
104
- if (!item.creationReason) return true;
105
- return HUMAN_ONLY_HANDOFF_REASONS.has(item.creationReason);
106
- }
107
-
108
95
  async function stopReason(controllerHome: string, schedule: RepositorySchedule): Promise<string | undefined> {
109
96
  const projection = readRepositoryProjection(controllerHome, schedule.repoId);
110
97
  const workId = workBoundScheduleWorkId(schedule);
111
98
  const work = workId ? getWorkContract({ controllerHome, repoId: schedule.repoId }, workId) : undefined;
112
99
  if (schedule.stopConditions.includes('human_review_required')) {
100
+ const pendingUserRequests = listUserRequests(controllerHome, 'pending');
113
101
  if (workId) {
114
- const activeHandoff = listHandoffItems({ controllerHome, repoId: schedule.repoId, status: 'active', limit: 100 })
115
- .find((item) => item.workId === workId && handoffRequiresHumanReview(item));
116
- if (activeHandoff) return `Work ${workId} has active Handoff ${activeHandoff.id} requiring human review.`;
117
- } else if (projection.currentAttention.length > 0) {
118
- return 'Repository has jobs requiring human attention.';
102
+ const request = pendingUserRequests.find((item) => item.targetScope?.workId === workId);
103
+ if (request) return `Work ${workId} has pending UserRequest ${request.requestId} requiring human action.`;
104
+ } else {
105
+ const request = pendingUserRequests.find((item) => item.targetScope?.repoId === schedule.repoId);
106
+ if (request) return `Repository ${schedule.repoId} has pending UserRequest ${request.requestId}.`;
119
107
  }
120
108
  }
121
109
  if (schedule.stopConditions.includes('release_ready') && projection.releaseFrozen) return 'Repository is in release freeze.';
@@ -277,9 +265,9 @@ async function executeExternalControllerWake(
277
265
  updateSchedule(controllerHome, schedule.repoId, schedule.scheduleId, () => ({ enabled: false, pausedReason: `Work ${workId} no longer exists.`, lastTriggeredAt: timestamp, lastOccurrenceId: occurrence.occurrenceId }));
278
266
  return decideOccurrence(controllerHome, schedule, occurrence, 'operation_blocked', 'skipped', `EXTERNAL_CONTROLLER_WAKE_WORK_NOT_FOUND:${workId}`);
279
267
  }
280
- if (isTerminalWorkContractStatus(work.status)) {
281
- updateSchedule(controllerHome, schedule.repoId, schedule.scheduleId, () => ({ enabled: false, pausedReason: `Work ${workId} is terminal (${work.status}).`, lastTriggeredAt: timestamp, lastOccurrenceId: occurrence.occurrenceId }));
282
- return decideOccurrence(controllerHome, schedule, occurrence, 'nothing_to_do', 'skipped', `Work ${workId} is terminal (${work.status}); automatic continuation stopped.`);
268
+ if (semanticWorkState(work) !== 'open') {
269
+ updateSchedule(controllerHome, schedule.repoId, schedule.scheduleId, () => ({ enabled: false, pausedReason: `Work ${workId} is terminal (${work.semanticState}).`, lastTriggeredAt: timestamp, lastOccurrenceId: occurrence.occurrenceId }));
270
+ return decideOccurrence(controllerHome, schedule, occurrence, 'nothing_to_do', 'skipped', `Work ${workId} is terminal (${work.semanticState}); automatic continuation stopped.`);
283
271
  }
284
272
 
285
273
  const retainedSession = getRetainedControllerSession(workStore, workId);
@@ -369,6 +357,10 @@ async function executeExternalControllerWake(
369
357
  const relayScopeId = typeof schedule.action.arguments?.relay_scope_id === 'string'
370
358
  ? schedule.action.arguments.relay_scope_id
371
359
  : undefined;
360
+ const controllerRoundOccurrenceId = typeof occurrence.triggerContext?.data?.controllerRoundOccurrenceId === 'string'
361
+ && occurrence.triggerContext.data.controllerRoundOccurrenceId.trim()
362
+ ? occurrence.triggerContext.data.controllerRoundOccurrenceId.trim()
363
+ : occurrence.occurrenceId;
372
364
  const wakeDecision = decideOccurrence(
373
365
  controllerHome,
374
366
  schedule,
@@ -387,24 +379,23 @@ async function executeExternalControllerWake(
387
379
  );
388
380
 
389
381
  try {
390
- const host = controllerHostForScheduledBinding(
382
+ const progression = await reconcileControllerProgression(
391
383
  { controllerHome, repoId: schedule.repoId, repoRoot: repository.canonicalRoot },
392
- bindingRecord.binding,
393
- );
394
- const resumed = await resumeScheduledControllerContinuation(
395
- workStore,
396
384
  {
397
- scheduleId: schedule.scheduleId,
398
- occurrenceId: occurrence.occurrenceId,
385
+ occurrenceId: controllerRoundOccurrenceId,
399
386
  workId,
400
- controllerBindingId: bindingRecord.binding.bindingId,
401
387
  relayScopeId,
402
388
  continuationHint,
389
+ allowSemanticWaitRecovery: controllerType === 'chatgpt',
390
+ scheduleName: schedule.name,
391
+ bindingArgs: args,
403
392
  },
404
- host,
405
393
  );
406
- if (resumed.dispatch.status === 'semantic_wait') {
394
+
395
+ if (progression.status === 'terminal_or_missing') {
407
396
  updateSchedule(controllerHome, schedule.repoId, schedule.scheduleId, () => ({
397
+ enabled: false,
398
+ pausedReason: progression.reason,
408
399
  lastTriggeredAt: timestamp,
409
400
  lastOccurrenceId: occurrence.occurrenceId,
410
401
  }));
@@ -412,37 +403,78 @@ async function executeExternalControllerWake(
412
403
  ...wakeDecision,
413
404
  status: 'skipped',
414
405
  decision: 'nothing_to_do',
415
- reason: resumed.dispatch.reason ?? `Work ${workId} remains in unchanged semantic wait; provider dispatch suppressed.`,
406
+ reason: progression.reason,
416
407
  });
417
408
  }
418
- if (resumed.dispatch.status === 'rejected') {
419
- throw new Error(resumed.dispatch.reason ?? 'CONTROLLER_HOST_RESUME_REJECTED');
420
409
 
410
+ if (progression.status === 'semantic_wait'
411
+ || progression.status === 'wait_for_user'
412
+ || progression.status === 'retained_session_missing'
413
+ || progression.status === 'human_controller') {
414
+ updateSchedule(controllerHome, schedule.repoId, schedule.scheduleId, () => ({
415
+ lastTriggeredAt: timestamp,
416
+ lastOccurrenceId: occurrence.occurrenceId,
417
+ }));
418
+ return saveOccurrence(controllerHome, {
419
+ ...wakeDecision,
420
+ status: 'skipped',
421
+ decision: 'nothing_to_do',
422
+ reason: progression.reason ?? `Work ${workId} is not currently eligible for provider progression.`,
423
+ });
424
+ }
425
+
426
+ if (progression.status === 'rejected') {
427
+ throw new Error(progression.reason ?? 'CONTROLLER_HOST_RESUME_REJECTED');
421
428
  }
429
+
430
+ if (progression.status === 'chatgpt_not_enrolled') {
431
+ updateSchedule(controllerHome, schedule.repoId, schedule.scheduleId, () => ({
432
+ lastTriggeredAt: timestamp,
433
+ lastOccurrenceId: occurrence.occurrenceId,
434
+ }));
435
+ return saveOccurrence(controllerHome, {
436
+ ...wakeDecision,
437
+ status: 'skipped',
438
+ decision: 'nothing_to_do',
439
+ reason: `Workflow Supervisor enrollment is not yet ready (${progression.supervisorEnrollment.status}); no ChatGPT provider attempt was consumed.`,
440
+ });
441
+ }
442
+
443
+ const supervisorEnrollment = progression.status === 'chatgpt_enrolled'
444
+ ? progression.supervisorEnrollment
445
+ : { status: 'not_eligible' as const };
422
446
  updateSchedule(controllerHome, schedule.repoId, schedule.scheduleId, (current) => ({
423
447
  lastTriggeredAt: timestamp,
424
448
  lastOccurrenceId: occurrence.occurrenceId,
425
449
  consecutiveFailures: 0,
426
450
  nextEligibleAt: undefined,
427
- ...(current.enabled ? { pausedReason: undefined } : {}),
451
+ ...(supervisorEnrollment.status === 'enrolled'
452
+ ? { enabled: false, pausedReason: 'workflow_supervisor_owns_outer_turn' }
453
+ : current.enabled ? { pausedReason: undefined } : {}),
428
454
  }));
429
455
  const dispatchedOccurrence = saveOccurrence(controllerHome, {
430
456
  ...wakeDecision,
431
457
  status: 'dispatched',
432
- reason: resumed.reused
433
- ? `Controller continuation occurrence ${occurrence.occurrenceId} was already durably dispatched; external replay suppressed and semantic round closure is still pending.`
434
- : `ControllerHost accepted durable binding ${bindingRecord.binding.bindingId} for Work ${workId}; dispatch ${resumed.dispatch.hostDispatchId ?? resumed.dispatch.relayScopeId}; semantic round closure is still pending.`,
458
+ reason: progression.status === 'chatgpt_enrolled'
459
+ ? `Workflow Supervisor reserved the exact ChatGPT effect ${progression.supervisorEnrollment.effectId ?? progression.relayScopeId}; Scheduler issued no provider send.`
460
+ : progression.reused
461
+ ? `Controller continuation occurrence ${occurrence.occurrenceId} was already durably dispatched; external replay suppressed and semantic round closure is still pending.`
462
+ : `ControllerHost accepted durable binding ${bindingRecord.binding.bindingId} for Work ${workId}; dispatch ${progression.providerDispatchReceiptId ?? progression.relayScopeId}; semantic round closure is still pending.`,
435
463
  });
436
464
  appendWorkEvidence(workStore, workId, {
437
465
  evidenceId: dispatchedOccurrence.occurrenceId,
438
- title: 'scheduled Controller continuation dispatched',
439
- summary: `Schedule ${schedule.scheduleId} occurrence ${dispatchedOccurrence.occurrenceId} resumed the exact Work-bound ControllerSession through ControllerHost.`,
466
+ title: progression.status === 'chatgpt_enrolled'
467
+ ? 'scheduled Workflow Supervisor effect reserved'
468
+ : 'scheduled Controller continuation dispatched',
469
+ summary: progression.status === 'chatgpt_enrolled'
470
+ ? `Schedule ${schedule.scheduleId} materialized the exact ControllerRound occurrence and Supervisor effect; Supervisor owns ChatGPT delivery.`
471
+ : `Schedule ${schedule.scheduleId} occurrence ${dispatchedOccurrence.occurrenceId} resumed the exact Work-bound ControllerSession through ControllerHost.`,
440
472
  detailLevel: 'summary',
441
473
  });
442
474
  return dispatchedOccurrence;
443
475
  } catch (error) {
444
476
  const reason = error instanceof Error ? error.message : String(error);
445
- if (reason.startsWith('SCHEDULE_CONTINUATION_ROUND_ALREADY_OPEN:')) {
477
+ if (reason.startsWith('CONTROLLER_CONTINUATION_ROUND_ALREADY_OPEN:') || reason.startsWith('CONTROLLER_CONTINUATION_ALREADY_DISPATCHING:')) {
446
478
  updateSchedule(controllerHome, schedule.repoId, schedule.scheduleId, () => ({ lastTriggeredAt: timestamp, lastOccurrenceId: occurrence.occurrenceId }));
447
479
  return decideOccurrence(controllerHome, schedule, wakeDecision, 'nothing_to_do', 'skipped', `Work ${workId} already has an open Controller round awaiting claim or disposition.`);
448
480
  }
@@ -473,20 +505,20 @@ async function executeExternalControllerWake(
473
505
  decision: 'execute',
474
506
  reason,
475
507
  ...(failureClass === 'user_action_required' ? { pauseReason: reason } : {}),
476
- handoff: {
477
- title: `External Controller wake ${occurrence.occurrenceId} failed`,
478
- summary: 'Forge recorded the schedule trigger but could not resume the exact configured ControllerSession through ControllerHost.',
479
- reason,
480
- creationReason: 'repeated_infrastructure_failure',
481
- blockingDecision: reason.startsWith('SCHEDULE_CONTINUATION_OUTCOME_UNKNOWN:')
482
- ? 'Inspect the durable ControllerHost dispatch outcome before any retry; automatic replay is fenced.'
483
- : 'Repair the ControllerHost adapter/binding or update the retained ControllerSession.',
484
- recommendedDecision: 'Inspect the exact Scheduler continuation dispatch, ControllerSession, and adapter binding, then retrigger only when the outcome is known.',
485
- recommendedPrompt: `Resume Work ${workId} manually, inspect failed wake occurrence ${occurrence.occurrenceId}, and repair the exact ControllerHost continuation path before unattended continuation resumes.`,
486
- statusSummary: 'Scheduled ControllerHost continuation failed.',
487
- blockedBy: ['external_controller_wake_failed'],
488
- attemptedActions: [`schedule:${schedule.scheduleId}`, `work:${workId}`, `controller:${controllerType}`, `session:${retainedSession.sessionId}`, `binding:${bindingRecord.binding.bindingId}`],
489
- },
508
+ ...(failureClass === 'user_action_required' ? {
509
+ handoff: {
510
+ title: `External Controller wake ${occurrence.occurrenceId} requires user authorization`,
511
+ summary: 'Forge cannot resume the configured ControllerSession until the required user authorization is restored.',
512
+ reason,
513
+ creationReason: 'missing_authorization' as const,
514
+ blockingDecision: 'Restore the required authenticated/authorized controller capability, then retry the same scheduled Work.',
515
+ recommendedDecision: 'Restore authorization only; do not create replacement Work or replay an unknown external effect.',
516
+ recommendedPrompt: `Restore authorization for Work ${workId} and retry scheduled continuation ${occurrence.occurrenceId}.`,
517
+ statusSummary: 'Scheduled Controller continuation is waiting on user authorization.',
518
+ blockedBy: ['controller_authorization_required'],
519
+ attemptedActions: [`schedule:${schedule.scheduleId}`, `work:${workId}`, `controller:${controllerType}`, `session:${retainedSession.sessionId}`, `binding:${bindingRecord.binding.bindingId}`],
520
+ },
521
+ } : {}),
490
522
  });
491
523
  updateSchedule(controllerHome, schedule.repoId, schedule.scheduleId, () => ({ lastTriggeredAt: timestamp, lastOccurrenceId: occurrence.occurrenceId }));
492
524
  return failed.occurrence ?? saveOccurrence(controllerHome, { ...wakeDecision, status: 'failed', reason });
@@ -541,39 +573,25 @@ export async function evaluateSchedule(
541
573
  updatedAt: timestamp,
542
574
  });
543
575
 
544
- // Semantic / model-backed schedules only record a trigger + Handoff.
545
- // Deterministic allowlisted operations continue into the local engine path.
576
+ // Semantic/model-owned schedule actions record the trigger only. A trigger is
577
+ // continuation input for the external Controller/Supervisor, not a human
578
+ // blocker and therefore must not manufacture Handoff/UserRequest state.
546
579
  if (!isDeterministicSchedule(schedule)) {
547
- const externalControllerHandoff = recordScheduleOccurrenceHandoff(
580
+ const recorded = decideOccurrence(
548
581
  controllerHome,
549
582
  schedule,
550
- decideOccurrence(
551
- controllerHome,
552
- schedule,
553
- occurrence,
554
- 'operation_blocked',
555
- 'skipped',
556
- 'Schedule execution is external-controller-owned; no ExecutionJob was created.',
557
- occurrenceDecisionEvidence({ operation: schedule.action.operation, trigger: occurrence.triggerContext?.source }),
558
- ),
559
- {
560
- title: `Schedule ${schedule.name} requires an external Controller`,
561
- summary: 'The scheduled trigger was recorded without dispatching a Kernel Job.',
562
- reason: 'Schedule execution is external-controller-owned.',
563
- creationReason: 'ambiguous_outcome',
564
- blockingDecision: 'Claim or create the related Work before executing the scheduled operation.',
565
- recommendedDecision: 'Review the trigger evidence and continue it through an explicitly claimed external Controller session.',
566
- recommendedPrompt: `Review schedule ${schedule.scheduleId} occurrence ${occurrence.occurrenceId}; create or claim Work for ${schedule.action.operation} and continue through Process Runtime or Thin Launcher.`,
567
- statusSummary: 'Schedule trigger is waiting for external Controller ownership.',
568
- blockedBy: ['external_controller_required'],
569
- attemptedActions: [`operation:${schedule.action.operation}`],
570
- },
583
+ occurrence,
584
+ 'operation_blocked',
585
+ 'skipped',
586
+ 'Schedule trigger recorded for external Controller continuation; no Kernel ExecutionJob or human Handoff was created.',
587
+ occurrenceDecisionEvidence({ operation: schedule.action.operation, trigger: occurrence.triggerContext?.source }),
571
588
  );
572
589
  updateSchedule(controllerHome, schedule.repoId, schedule.scheduleId, () => ({ lastTriggeredAt: timestamp, lastOccurrenceId: occurrenceId }));
573
- return externalControllerHandoff;
590
+ return recorded;
574
591
  }
575
592
 
576
593
  const recent = listOccurrences(controllerHome, schedule.repoId, schedule.scheduleId, 1000);
594
+ reclaimStaleCreatedOccurrences(controllerHome, schedule.repoId, schedule.scheduleId);
577
595
  const active = listActiveOccurrences(controllerHome, schedule.repoId, schedule.scheduleId)
578
596
  .filter((entry) => entry.occurrenceId !== occurrence.occurrenceId);
579
597
  const admission = evaluateScheduleOccurrenceAdmission(schedule, {
@@ -593,18 +611,7 @@ export async function evaluateSchedule(
593
611
  reason: stop,
594
612
  countFailure: false,
595
613
  pauseReason: stop,
596
- handoff: {
597
- title: `Scheduled maintenance occurrence ${occurrence.occurrenceId} stopped`,
598
- summary: 'A live maintenance occurrence was blocked by an explicit schedule stop condition and requires review before automation resumes.',
599
- reason: stop,
600
- creationReason: 'ambiguous_outcome',
601
- blockingDecision: 'Review the stop condition and decide whether automatic maintenance should stay paused.',
602
- recommendedDecision: 'Resolve the stop condition, then explicitly re-enable or retrigger the maintenance schedule.',
603
- recommendedPrompt: `Review maintenance schedule ${schedule.scheduleId} for repo ${schedule.repoId}, inspect stop condition ${stop}, and decide whether to resume the schedule.`,
604
- statusSummary: 'Scheduled maintenance occurrence stopped before dispatch.',
605
- blockedBy: ['schedule_stop_condition'],
606
- attemptedActions: [`schedule:${schedule.scheduleId}`, `operation:${schedule.action.operation}`],
607
- },
614
+
608
615
  });
609
616
  return failed.occurrence ?? stopped;
610
617
  }
@@ -641,22 +648,20 @@ export async function evaluateSchedule(
641
648
  reason: preview.blockedReason ?? 'Automatic maintenance preview blocked the occurrence.',
642
649
  countFailure: !preview.blockedPermanently,
643
650
  pauseReason: preview.blockedPermanently ? preview.blockedReason : undefined,
644
- handoff: {
645
- title: `Scheduled maintenance occurrence ${occurrence.occurrenceId} blocked`,
646
- summary: 'A bounded live maintenance occurrence was blocked before dispatch and requires a human decision.',
647
- reason: preview.blockedReason ?? 'Automatic maintenance preview blocked the occurrence.',
648
- creationReason: preview.blockedPermanently ? 'missing_authorization' : 'ambiguous_outcome',
649
- blockingDecision: preview.blockedPermanently
650
- ? 'Fix the schedule operation or authorization before automatic maintenance can resume.'
651
- : 'Inspect runtime maintenance readiness before allowing another unattended attempt.',
652
- recommendedDecision: preview.blockedPermanently
653
- ? 'Correct the automatic maintenance configuration and re-enable the schedule deliberately.'
654
- : 'Review the maintenance preview, resolve the blocker, and then retrigger the schedule intentionally.',
655
- recommendedPrompt: `Review blocked maintenance occurrence ${occurrence.occurrenceId} for schedule ${schedule.scheduleId}. Determine whether the schedule configuration or runtime maintenance readiness should be corrected before retrying.`,
656
- statusSummary: 'Scheduled maintenance occurrence blocked before dispatch.',
657
- blockedBy: [decision],
658
- attemptedActions: [`schedule:${schedule.scheduleId}`, `operation:${schedule.action.operation}`],
659
- },
651
+ ...(preview.blockedPermanently ? {
652
+ handoff: {
653
+ title: `Scheduled maintenance occurrence ${occurrence.occurrenceId} needs a user decision`,
654
+ summary: 'Automatic maintenance is permanently blocked and requires an explicit user decision before the schedule can resume.',
655
+ reason: preview.blockedReason ?? 'Automatic maintenance preview blocked the occurrence.',
656
+ creationReason: 'ambiguous_outcome' as const,
657
+ blockingDecision: 'Correct the configuration/authorization or intentionally keep this schedule paused.',
658
+ recommendedDecision: 'Review the permanent blocker and explicitly decide whether to repair configuration and resume.',
659
+ recommendedPrompt: `Review permanently blocked maintenance occurrence ${occurrence.occurrenceId} for schedule ${schedule.scheduleId} and decide whether to repair and resume it.`,
660
+ statusSummary: 'Scheduled maintenance is permanently blocked pending a user decision.',
661
+ blockedBy: [decision],
662
+ attemptedActions: [`schedule:${schedule.scheduleId}`, `operation:${schedule.action.operation}`],
663
+ },
664
+ } : {}),
660
665
  });
661
666
  return failed.occurrence ?? blocked;
662
667
  }
@@ -693,22 +698,20 @@ export async function evaluateSchedule(
693
698
  reason: preview.blockedReason ?? 'Automatic maintenance preview blocked the occurrence.',
694
699
  countFailure: !preview.blockedPermanently,
695
700
  pauseReason: preview.blockedPermanently ? preview.blockedReason : undefined,
696
- handoff: {
697
- title: `Scheduled maintenance occurrence ${occurrence.occurrenceId} blocked`,
698
- summary: 'A bounded live maintenance occurrence was blocked before dispatch and requires a human decision.',
699
- reason: preview.blockedReason ?? 'Automatic maintenance preview blocked the occurrence.',
700
- creationReason: preview.blockedPermanently ? 'missing_authorization' : 'ambiguous_outcome',
701
- blockingDecision: preview.blockedPermanently
702
- ? 'Fix the schedule operation or authorization before automatic maintenance can resume.'
703
- : 'Inspect runtime maintenance readiness before allowing another unattended attempt.',
704
- recommendedDecision: preview.blockedPermanently
705
- ? 'Correct the automatic maintenance configuration and re-enable the schedule deliberately.'
706
- : 'Review the maintenance preview, resolve the blocker, and then retrigger the schedule intentionally.',
707
- recommendedPrompt: `Review blocked maintenance occurrence ${occurrence.occurrenceId} for schedule ${schedule.scheduleId}. Determine whether the schedule configuration or runtime maintenance readiness should be corrected before retrying.`,
708
- statusSummary: 'Scheduled maintenance occurrence blocked before dispatch.',
709
- blockedBy: [decision],
710
- attemptedActions: [`schedule:${schedule.scheduleId}`, `operation:${schedule.action.operation}`],
711
- },
701
+ ...(preview.blockedPermanently ? {
702
+ handoff: {
703
+ title: `Scheduled maintenance occurrence ${occurrence.occurrenceId} needs a user decision`,
704
+ summary: 'Automatic maintenance is permanently blocked and requires an explicit user decision before the schedule can resume.',
705
+ reason: preview.blockedReason ?? 'Automatic maintenance preview blocked the occurrence.',
706
+ creationReason: 'ambiguous_outcome' as const,
707
+ blockingDecision: 'Correct the configuration/authorization or intentionally keep this schedule paused.',
708
+ recommendedDecision: 'Review the permanent blocker and explicitly decide whether to repair configuration and resume.',
709
+ recommendedPrompt: `Review permanently blocked maintenance occurrence ${occurrence.occurrenceId} for schedule ${schedule.scheduleId} and decide whether to repair and resume it.`,
710
+ statusSummary: 'Scheduled maintenance is permanently blocked pending a user decision.',
711
+ blockedBy: [decision],
712
+ attemptedActions: [`schedule:${schedule.scheduleId}`, `operation:${schedule.action.operation}`],
713
+ },
714
+ } : {}),
712
715
  });
713
716
  return failed.occurrence ?? blocked;
714
717
  }
@@ -778,18 +781,7 @@ export async function evaluateSchedule(
778
781
  outcome: 'failed',
779
782
  decision: 'execute',
780
783
  reason,
781
- handoff: {
782
- title: `GitHub issue watcher occurrence ${occurrence.occurrenceId} failed`,
783
- summary: 'The local GitHub issue poll failed before Forge could compare issue state.',
784
- reason,
785
- creationReason: 'repeated_infrastructure_failure',
786
- blockingDecision: 'Repair GitHub CLI authentication/connectivity before unattended issue monitoring resumes.',
787
- recommendedDecision: 'Restore gh read access, then retrigger the watcher.',
788
- recommendedPrompt: `Inspect GitHub issue watcher occurrence ${occurrence.occurrenceId} and restore the local read-only gh issue polling path.`,
789
- statusSummary: 'GitHub issue watcher poll failed.',
790
- blockedBy: ['github_issue_watch_failed'],
791
- attemptedActions: [`schedule:${schedule.scheduleId}`, 'gh:api:issues'],
792
- },
784
+
793
785
  });
794
786
  return failed.occurrence ?? occurrence;
795
787
  }
@@ -808,9 +800,9 @@ export async function evaluateSchedule(
808
800
  updateSchedule(controllerHome, schedule.repoId, schedule.scheduleId, () => ({ enabled: false, pausedReason: `Work ${workId} no longer exists.`, lastTriggeredAt: timestamp, lastOccurrenceId: occurrenceId }));
809
801
  return decideOccurrence(controllerHome, schedule, occurrence, 'operation_blocked', 'skipped', `SCHEDULE_BROWSER_PROBE_WORK_NOT_FOUND:${workId}`);
810
802
  }
811
- if (isTerminalWorkContractStatus(work.status)) {
812
- updateSchedule(controllerHome, schedule.repoId, schedule.scheduleId, () => ({ enabled: false, pausedReason: `Work ${workId} is terminal (${work.status}).`, lastTriggeredAt: timestamp, lastOccurrenceId: occurrenceId }));
813
- return decideOccurrence(controllerHome, schedule, occurrence, 'nothing_to_do', 'skipped', `Work ${workId} is terminal (${work.status}); browser watcher stopped before probing.`);
803
+ if (semanticWorkState(work) !== 'open') {
804
+ updateSchedule(controllerHome, schedule.repoId, schedule.scheduleId, () => ({ enabled: false, pausedReason: `Work ${workId} is terminal (${work.semanticState}).`, lastTriggeredAt: timestamp, lastOccurrenceId: occurrenceId }));
805
+ return decideOccurrence(controllerHome, schedule, occurrence, 'nothing_to_do', 'skipped', `Work ${workId} is terminal (${work.semanticState}); browser watcher stopped before probing.`);
814
806
  }
815
807
  }
816
808
 
@@ -932,18 +924,7 @@ export async function evaluateSchedule(
932
924
  outcome: 'failed',
933
925
  decision: 'execute',
934
926
  reason,
935
- handoff: {
936
- title: `Browser watcher occurrence ${occurrence.occurrenceId} failed`,
937
- summary: 'A bounded browser probe failed before Forge could compare the external observation.',
938
- reason,
939
- creationReason: 'repeated_infrastructure_failure',
940
- blockingDecision: 'Repair browser/session readiness or update the watcher target before unattended probing resumes.',
941
- recommendedDecision: 'Inspect the browser plugin/session and retrigger the watcher after the target is readable.',
942
- recommendedPrompt: `Inspect browser watcher schedule ${schedule.scheduleId} for Work ${workId}, repair the failed browser probe, then retrigger one bounded occurrence.`,
943
- statusSummary: 'Scheduled browser watcher failed.',
944
- blockedBy: ['browser_probe_failed'],
945
- attemptedActions: [`schedule:${schedule.scheduleId}`, `work:${workId}`, 'operation:browser_probe'],
946
- },
927
+
947
928
  });
948
929
  updateSchedule(controllerHome, schedule.repoId, schedule.scheduleId, () => ({ lastTriggeredAt: timestamp, lastOccurrenceId: occurrenceId }));
949
930
  return failed.occurrence ?? saveOccurrence(controllerHome, { ...occurrence, status: 'failed', decision: 'execute', reason });
@@ -1008,22 +989,7 @@ export async function evaluateSchedule(
1008
989
  outcome: 'failed',
1009
990
  decision: 'execute',
1010
991
  reason,
1011
- handoff: {
1012
- title: `Scheduled maintenance occurrence ${occurrence.occurrenceId} failed`,
1013
- summary: 'A bounded live maintenance occurrence failed during deterministic apply and requires review before the schedule continues unattended.',
1014
- reason,
1015
- creationReason: 'repeated_infrastructure_failure',
1016
- blockingDecision: 'Review the failed maintenance occurrence and decide whether the schedule should continue automatically.',
1017
- recommendedDecision: 'Inspect the failed occurrence, fix the runtime blocker, then re-enable or retrigger the schedule intentionally.',
1018
- recommendedPrompt: `Review schedule occurrence ${occurrence.occurrenceId} for ${schedule.scheduleId}, inspect the failed runtime maintenance action, and decide whether to resume automatic maintenance.`,
1019
- statusSummary: 'Scheduled maintenance execution failed.',
1020
- blockedBy: ['scheduled_execution_failed'],
1021
- attemptedActions: [
1022
- `schedule:${schedule.scheduleId}`,
1023
- `operation:${schedule.action.operation}`,
1024
- actionIdRaw ? `action:${actionIdRaw}` : 'action:unknown',
1025
- ],
1026
- },
992
+
1027
993
  });
1028
994
  updateSchedule(controllerHome, schedule.repoId, schedule.scheduleId, () => ({
1029
995
  lastTriggeredAt: timestamp,
@@ -1,10 +1,11 @@
1
1
  import { createHash } from 'crypto';
2
- import { getWorkContract, isTerminalWorkContractStatus, type WorkContract } from '../../../../packages/kernel/work/api/index';
3
- import { getRetainedControllerSession, type ControllerRoundRelayRecord, type ControllerType } from '../../../../packages/kernel/controller/api/index';
2
+ import { getWorkContract, semanticWorkState, type WorkContract } from '../../../../packages/kernel/work/api/index';
3
+ import { getControllerRoundRelay, getRetainedControllerSession, rearmControllerRoundAfterProviderUserAction, type ControllerRoundRelayRecord, type ControllerType } from '../../../../packages/kernel/controller/api/index';
4
4
  import { ensureScheduledControllerBinding } from '../../root/scheduled-controller-composition';
5
5
  import { resolveHandoffItem } from '../../control-plane/facade/handoff-inbox-store';
6
6
  import type { HandoffItem } from '../../control-plane/facade/types';
7
7
  import { readWorkHandle, type WorkHandleState } from '../../control-plane/execution/work-handle-store';
8
+ import { touchSchedulerWakeSignal } from '../../control-plane/global-scheduler/wake-signal';
8
9
 
9
10
  import { assertAutomatedOperationAllowed } from '../../control-plane/governance/external-effects';
10
11
  import { evaluateSchedule } from './engine';
@@ -31,6 +32,8 @@ export interface WorkContinuationScheduleInput {
31
32
  workId?: string;
32
33
  scheduleMode?: WorkScheduleMode;
33
34
  controllerType?: ContinuationControllerType;
35
+ /** Exact interactive Browser grants to carry into the scheduled Controller binding. */
36
+ authorizationGrantRefs?: string[];
34
37
  executable?: string;
35
38
  launchArgs?: string[];
36
39
  launchReservationMs?: number;
@@ -85,7 +88,7 @@ function requiredWork(controllerHome: string, repoId: string, workId: string): W
85
88
 
86
89
  function activeWork(controllerHome: string, repoId: string, workId: string): WorkContract {
87
90
  const work = requiredWork(controllerHome, repoId, workId);
88
- if (isTerminalWorkContractStatus(work.status)) throw new Error(`WORK_ALREADY_TERMINAL: ${work.workId}:${work.status}`);
91
+ if (semanticWorkState(work) !== 'open') throw new Error(`WORK_ALREADY_TERMINAL: ${work.workId}:${semanticWorkState(work)}`);
89
92
  return work;
90
93
  }
91
94
 
@@ -116,6 +119,9 @@ function providerSeedArguments(input: WorkContinuationScheduleInput, controllerT
116
119
  return {
117
120
  ...(workId ? { work_id: workId } : {}),
118
121
  controller_type: controllerType,
122
+ ...(input.authorizationGrantRefs?.length
123
+ ? { authorization_grant_refs: [...new Set(input.authorizationGrantRefs.map(String).map(value => value.trim()).filter(Boolean))] }
124
+ : {}),
119
125
  ...(input.executable?.trim() ? { executable: input.executable.trim() } : {}),
120
126
  ...(input.launchArgs ? { launch_args: input.launchArgs.map(String) } : {}),
121
127
  ...(input.launchReservationMs !== undefined ? { launch_reservation_ms: input.launchReservationMs } : {}),
@@ -456,14 +462,47 @@ export async function resolveHandoffAndTriggerContinuation(
456
462
  input: { decision: string; resolver: string },
457
463
  ): Promise<{ item: HandoffItem; continuationOccurrences: Array<{ scheduleId: string; occurrenceId?: string; status?: string }> }> {
458
464
  const item = resolveHandoffItem({ controllerHome, repoId }, handoffId, input);
465
+ const continuationOccurrences = await triggerResolvedHandoffContinuation(controllerHome, repoId, item);
466
+ return { item, continuationOccurrences };
467
+ }
468
+
469
+ /**
470
+ * The Inbox application resolves persistence before it calls its continuation
471
+ * port. Keep the post-resolution transition here so every transport re-arms
472
+ * the exact ControllerRound before it can wake its Work schedule.
473
+ */
474
+ export async function triggerResolvedHandoffContinuation(
475
+ controllerHome: string,
476
+ repoId: string,
477
+ item: HandoffItem,
478
+ ): Promise<Array<{ scheduleId: string; occurrenceId?: string; status?: string }>> {
479
+ const relay = item.workId ? getControllerRoundRelay({ controllerHome, repoId }, item.workId) : undefined;
480
+ const rearmedRelay = item.workId && relay?.status === 'waiting_for_user' && relay.blockedReason === 'provider_user_action_required' && relay.handoffId === item.id
481
+ ? rearmControllerRoundAfterProviderUserAction({ controllerHome, repoId }, { workId: item.workId, handoffId: item.id })
482
+ : undefined;
483
+ if (rearmedRelay) {
484
+ // The ControllerRound itself is the continuation authority. A repository-event
485
+ // Schedule is optional policy, not the wake mechanism for an already rearmed
486
+ // provider dispatch. Wake the canonical Scheduler immediately so a resolved
487
+ // provider blocker resumes the same occurrence even when no Schedule exists.
488
+ touchSchedulerWakeSignal(controllerHome, `provider-user-action-resolved:${item.workId}`);
489
+ }
459
490
  const continuationOccurrences = item.workId
460
491
  ? await triggerWorkContinuationRepositoryEvent(
461
492
  controllerHome,
462
493
  repoId,
463
494
  handoffResolvedContinuationEventName(item.id),
464
495
  `handoff:${item.id}:${item.updatedAt}`,
465
- { workId: item.workId, data: { handoffId: item.id, status: item.status, decision: item.decision } },
496
+ {
497
+ workId: item.workId,
498
+ data: {
499
+ handoffId: item.id,
500
+ status: item.status,
501
+ decision: item.decision,
502
+ ...(rearmedRelay?.occurrenceId ? { controllerRoundOccurrenceId: rearmedRelay.occurrenceId } : {}),
503
+ },
504
+ },
466
505
  )
467
506
  : [];
468
- return { item, continuationOccurrences };
507
+ return continuationOccurrences;
469
508
  }