@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
@@ -3,6 +3,11 @@ import type { AssistantContextSnapshot, ControllerRoundRelayRecord } from '../..
3
3
  import { prepareAssistantWorkContext } from '../context/assistant-work-context';
4
4
  import { renderAssistantContext, type AssistantContextResolution } from '../context/assistant-context';
5
5
  import { getChatgptWorkConversationBinding } from '../../../adapters/chatgpt/work-conversation-binding-store';
6
+ import {
7
+ chatgptControllerProviderBindingId,
8
+ upsertChatgptControllerBinding,
9
+ type ChatgptControllerBindingPayload,
10
+ } from '../../../adapters/chatgpt/controller-binding-store';
6
11
  import {
7
12
  buildChatgptControllerRoundPrompt,
8
13
  chatgptControllerRoundBindingAuthorizesRecovery,
@@ -22,6 +27,18 @@ export interface ChatgptControllerRoundBindingSnapshot {
22
27
  bindingId?: string;
23
28
  browserSessionId?: string;
24
29
  conversationUrl?: string;
30
+ authorizationGrantRefs?: string[];
31
+ }
32
+
33
+ export function chatgptControllerRoundBindingId(workId: string): string {
34
+ return chatgptControllerProviderBindingId(workId);
35
+ }
36
+
37
+ export function upsertChatgptControllerRoundTransportBinding(
38
+ store: ControllerRoundCompositionStore,
39
+ input: Omit<ChatgptControllerBindingPayload, 'schemaVersion' | 'bindingId' | 'repoId' | 'createdAt' | 'updatedAt'>,
40
+ ) {
41
+ return upsertChatgptControllerBinding(store, input);
25
42
  }
26
43
 
27
44
  export function chatgptControllerRoundBinding(
@@ -34,6 +51,7 @@ export function chatgptControllerRoundBinding(
34
51
  bindingId: binding.bindingId,
35
52
  browserSessionId: binding.latestBrowserSessionId,
36
53
  conversationUrl: binding.conversationUrl,
54
+ authorizationGrantRefs: [...(binding.authorizationGrantRefs ?? [])],
37
55
  };
38
56
  }
39
57
 
@@ -65,6 +83,7 @@ export function recordChatgptControllerRoundTabSettlement(
65
83
  relayScopeId: string;
66
84
  status: ChatgptControllerRoundSettlementStatus;
67
85
  error?: string;
86
+ attemptIdentity?: string;
68
87
  },
69
88
  ): void {
70
89
  recordChatgptControllerRoundSettlement(store, input);
@@ -79,7 +98,7 @@ function controllerAssistantContextSnapshot(resolution: AssistantContextResoluti
79
98
  sourceRevision: item.provenance.sourceRevision,
80
99
  }));
81
100
  const identity = {
82
- projectId: resolution.projectId,
101
+ ...(resolution.projectId ? { projectId: resolution.projectId } : {}),
83
102
  items,
84
103
  gaps: resolution.gaps,
85
104
  missingRequiredSources: resolution.missingRequiredSources,
@@ -0,0 +1,106 @@
1
+ export type RuntimeRemoteControllerKind = 'chatgpt' | 'mcp';
2
+
3
+ export interface RuntimeDeploymentTopology {
4
+ schemaVersion: 1;
5
+ remoteControllers: RuntimeRemoteControllerKind[];
6
+ capabilityIntents: string[];
7
+ persistentRuntimeRequired: boolean;
8
+ components: {
9
+ workflowSupervisor: boolean;
10
+ workflowSupervisorNativeBrowser: boolean;
11
+ };
12
+ }
13
+
14
+ const REMOTE_CONTROLLERS = new Set<RuntimeRemoteControllerKind>(['chatgpt', 'mcp']);
15
+
16
+ function normalizeCapabilityIntent(value: string): string {
17
+ const normalized = value.trim().toLowerCase();
18
+ if (!/^[-a-z0-9_.]{3,128}$/.test(normalized)) throw new Error(`RUNTIME_TOPOLOGY_CAPABILITY_INTENT_INVALID: ${value}`);
19
+ return normalized;
20
+ }
21
+
22
+ function normalizedRemoteControllers(values: readonly string[] | undefined): RuntimeRemoteControllerKind[] {
23
+ return Array.from(new Set(
24
+ (values ?? [])
25
+ .map((value) => value.trim().toLowerCase())
26
+ .filter((value): value is RuntimeRemoteControllerKind => REMOTE_CONTROLLERS.has(value as RuntimeRemoteControllerKind)),
27
+ )).sort();
28
+ }
29
+
30
+ export function deriveRuntimeDeploymentTopology(input: {
31
+ controllers?: readonly string[];
32
+ capabilityIntents?: readonly string[];
33
+ }): RuntimeDeploymentTopology {
34
+ const remoteControllers = normalizedRemoteControllers(input.controllers);
35
+ const capabilityIntents = Array.from(new Set(
36
+ (input.capabilityIntents ?? []).map(normalizeCapabilityIntent),
37
+ )).sort();
38
+ const chatgpt = remoteControllers.includes('chatgpt');
39
+ return {
40
+ schemaVersion: 1,
41
+ remoteControllers,
42
+ capabilityIntents,
43
+ persistentRuntimeRequired: remoteControllers.length > 0,
44
+ components: {
45
+ // Requirement-level ChatGPT continuation uses Supervisor Core as its
46
+ // outer-turn authority. Generic remote MCP transport does not.
47
+ workflowSupervisor: chatgpt,
48
+ // ChatGPT Work has one controlled outer-turn executor: the Supervisor's
49
+ // Computer adapter. It owns exact-conversation delivery and its durable
50
+ // effect ledger; Scheduler must never fall back to direct Browser delivery.
51
+ workflowSupervisorNativeBrowser: chatgpt,
52
+ },
53
+ };
54
+ }
55
+
56
+ /**
57
+ * Missing topology means an installation predates this contract. Preserve the
58
+ * complete ChatGPT Supervisor composition during upgrade.
59
+ */
60
+ export function legacyRuntimeDeploymentTopology(): RuntimeDeploymentTopology {
61
+ return deriveRuntimeDeploymentTopology({ controllers: ['chatgpt'] });
62
+ }
63
+
64
+ export function normalizeRuntimeDeploymentTopology(value: unknown): RuntimeDeploymentTopology {
65
+ if (value === undefined || value === null) return legacyRuntimeDeploymentTopology();
66
+ if (!value || typeof value !== 'object' || Array.isArray(value)) throw new Error('RUNTIME_TOPOLOGY_INVALID');
67
+ const record = value as Record<string, unknown>;
68
+ if (record.schemaVersion !== 1) throw new Error('RUNTIME_TOPOLOGY_VERSION_UNSUPPORTED');
69
+ if (!Array.isArray(record.remoteControllers)
70
+ || record.remoteControllers.some((entry) => typeof entry !== 'string' || !REMOTE_CONTROLLERS.has(entry as RuntimeRemoteControllerKind))) {
71
+ throw new Error('RUNTIME_TOPOLOGY_REMOTE_CONTROLLERS_INVALID');
72
+ }
73
+ if (!Array.isArray(record.capabilityIntents)
74
+ || record.capabilityIntents.some((entry) => typeof entry !== 'string')) {
75
+ throw new Error('RUNTIME_TOPOLOGY_CAPABILITY_INTENTS_INVALID');
76
+ }
77
+ const remoteControllers = normalizedRemoteControllers(record.remoteControllers as string[]);
78
+ const capabilityIntents = Array.from(new Set(
79
+ (record.capabilityIntents as string[]).map(normalizeCapabilityIntent),
80
+ )).sort();
81
+ const canonical = deriveRuntimeDeploymentTopology({ controllers: remoteControllers, capabilityIntents });
82
+ const components = record.components;
83
+ if (!components || typeof components !== 'object' || Array.isArray(components)) throw new Error('RUNTIME_TOPOLOGY_COMPONENTS_REQUIRED');
84
+ const componentRecord = components as Record<string, unknown>;
85
+ if (typeof componentRecord.workflowSupervisor !== 'boolean'
86
+ || typeof componentRecord.workflowSupervisorNativeBrowser !== 'boolean') {
87
+ throw new Error('RUNTIME_TOPOLOGY_COMPONENTS_INVALID');
88
+ }
89
+ if (componentRecord.workflowSupervisor !== canonical.components.workflowSupervisor
90
+ || record.persistentRuntimeRequired !== canonical.persistentRuntimeRequired) {
91
+ throw new Error('RUNTIME_TOPOLOGY_DERIVATION_MISMATCH');
92
+ }
93
+ // The flag is derived, so stale persisted topology cannot disable the sole
94
+ // autonomous delivery owner or reintroduce an alternate Browser path.
95
+ return canonical;
96
+ }
97
+
98
+ export function parseRuntimeDeploymentTopologyArgument(value: string | undefined): RuntimeDeploymentTopology {
99
+ if (!value?.trim()) return legacyRuntimeDeploymentTopology();
100
+ try {
101
+ return normalizeRuntimeDeploymentTopology(JSON.parse(value));
102
+ } catch (error) {
103
+ const detail = error instanceof Error ? error.message : String(error);
104
+ throw new Error(`RUNTIME_TOPOLOGY_ARGUMENT_INVALID: ${detail}`);
105
+ }
106
+ }
@@ -3,6 +3,7 @@ import { resolve } from 'path';
3
3
  import { pathToFileURL } from 'url';
4
4
  import { Command } from 'commander';
5
5
  import { CanonicalForgeRuntime } from './runtime';
6
+ import { parseRuntimeDeploymentTopologyArgument } from './deployment-topology';
6
7
 
7
8
  interface CliOptions {
8
9
  controllerHome: string;
@@ -11,7 +12,7 @@ interface CliOptions {
11
12
  host: string;
12
13
  port: string;
13
14
  authTokenFile: string;
14
- exclusiveWorkId?: string;
15
+ deploymentTopology?: string;
15
16
  }
16
17
 
17
18
  function readAuthToken(path: string): string {
@@ -29,7 +30,7 @@ export async function runCanonicalRuntimeCli(argv = process.argv): Promise<void>
29
30
  .requiredOption('--host <host>', 'MCP listener host')
30
31
  .requiredOption('--port <port>', 'MCP listener port')
31
32
  .requiredOption('--auth-token-file <path>', 'Bearer token file')
32
- .option('--exclusive-work-id <id>', 'Persistently admit only this P0 Work while migration is active');
33
+ .option('--deployment-topology <json>', 'Normalized product-level Runtime deployment topology');
33
34
  command.parse(argv);
34
35
  const options = command.opts<CliOptions>();
35
36
  const port = Number(options.port);
@@ -40,8 +41,8 @@ export async function runCanonicalRuntimeCli(argv = process.argv): Promise<void>
40
41
  releaseManifestPath: resolve(options.releaseManifest),
41
42
  host: options.host,
42
43
  port,
44
+ topology: parseRuntimeDeploymentTopologyArgument(options.deploymentTopology),
43
45
  authToken: readAuthToken(options.authTokenFile),
44
- exclusiveWorkId: options.exclusiveWorkId,
45
46
  });
46
47
  await runtime.start();
47
48
  process.stderr.write(`${JSON.stringify({
@@ -0,0 +1,184 @@
1
+ import { createHash } from 'crypto';
2
+ import { closeSync, existsSync, openSync, readFileSync, readSync, realpathSync } from 'fs';
3
+ import { basename, dirname, join, relative, resolve } from 'path';
4
+ import { inspectControlPlaneDatabaseFile, type ControlPlaneDatabaseInspection } from '../control-plane/persistence/sqlite-store';
5
+ import { loadRuntimeReleaseManifest } from './release-manifest';
6
+ import { forgeRuntimeServicePaths, validateForgeRuntimeServiceConfig, type ForgeRuntimeServiceConfig } from './service';
7
+
8
+ /**
9
+ * A Recovery-owned, bounded restore point. The release is immutable Runtime
10
+ * authority; the SQLite copy and service contract are the state and bootstrap
11
+ * material needed to make that release useful after the Kernel is dead.
12
+ */
13
+ export interface KnownGoodRecoveryBundle {
14
+ schemaVersion: 1;
15
+ attestationId: string;
16
+ root: string;
17
+ database: {
18
+ path: string;
19
+ sha256: string;
20
+ schemaVersion: number;
21
+ recordCount: number;
22
+ auditEventCount: number;
23
+ };
24
+ serviceContract: {
25
+ path: string;
26
+ sha256: string;
27
+ };
28
+ createdAt: string;
29
+ }
30
+
31
+ export interface KnownGoodReleaseIdentity {
32
+ path: string;
33
+ revision: string;
34
+ artifactIdentity: string;
35
+ manifestSha256: string;
36
+ workerProtocolVersion: number;
37
+ controllerHome?: string;
38
+ recoveryBundle?: KnownGoodRecoveryBundle;
39
+ }
40
+
41
+ export interface InspectedKnownGoodRecoveryBundle {
42
+ releaseRoot: string;
43
+ database: ControlPlaneDatabaseInspection;
44
+ serviceConfig: ForgeRuntimeServiceConfig;
45
+ }
46
+
47
+ const SHA256_FILE_CHUNK_BYTES = 1024 * 1024;
48
+
49
+ /** Hash arbitrarily large Recovery artifacts without allocating the whole file. */
50
+ export function sha256FileBounded(path: string): string {
51
+ const descriptor = openSync(path, 'r');
52
+ const hash = createHash('sha256');
53
+ const buffer = Buffer.allocUnsafe(SHA256_FILE_CHUNK_BYTES);
54
+ try {
55
+ for (;;) {
56
+ const bytesRead = readSync(descriptor, buffer, 0, buffer.length, null);
57
+ if (bytesRead === 0) break;
58
+ hash.update(buffer.subarray(0, bytesRead));
59
+ }
60
+ return hash.digest('hex');
61
+ } finally {
62
+ closeSync(descriptor);
63
+ }
64
+ }
65
+
66
+ function canonical(path: string): string {
67
+ try { return realpathSync(path); }
68
+ catch { return resolve(path); }
69
+ }
70
+
71
+ function directChild(root: string, path: string): boolean {
72
+ return canonical(dirname(path)) === canonical(root);
73
+ }
74
+
75
+ function inside(root: string, path: string): boolean {
76
+ const value = relative(canonical(root), canonical(path));
77
+ return value === '' || (!value.startsWith('..') && value !== '..');
78
+ }
79
+
80
+ function requiredText(value: unknown, code: string): string {
81
+ if (typeof value !== 'string' || !value.trim()) throw new Error(code);
82
+ return value.trim();
83
+ }
84
+
85
+ function requiredPositiveInteger(value: unknown, code: string): number {
86
+ if (!Number.isInteger(value) || Number(value) < 1) throw new Error(code);
87
+ return Number(value);
88
+ }
89
+
90
+ function validateRecoveryBundleShape(entry: KnownGoodReleaseIdentity, controllerHome: string): KnownGoodRecoveryBundle {
91
+ const bundle = entry.recoveryBundle;
92
+ if (!bundle || bundle.schemaVersion !== 1) throw new Error('KNOWN_GOOD_RECOVERY_BUNDLE_MISSING');
93
+ const home = resolve(controllerHome);
94
+ const root = resolve(bundle.root);
95
+ const expectedBundlesRoot = resolve(home, 'recovery', 'bundles', 'known-good');
96
+ const attestationId = requiredText(bundle.attestationId, 'KNOWN_GOOD_RECOVERY_BUNDLE_ID_INVALID');
97
+ if (basename(root) !== attestationId || !directChild(expectedBundlesRoot, root)) {
98
+ throw new Error('KNOWN_GOOD_RECOVERY_BUNDLE_OUTSIDE_AUTHORITY');
99
+ }
100
+ if (!/^[-a-zA-Z0-9_]{8,160}$/.test(attestationId)) throw new Error('KNOWN_GOOD_RECOVERY_BUNDLE_ID_INVALID');
101
+ if (!inside(root, bundle.database.path) || basename(resolve(bundle.database.path)) !== 'controller.sqlite') {
102
+ throw new Error('KNOWN_GOOD_RECOVERY_DATABASE_PATH_INVALID');
103
+ }
104
+ if (!inside(root, bundle.serviceContract.path) || basename(resolve(bundle.serviceContract.path)) !== 'service-contract.json') {
105
+ throw new Error('KNOWN_GOOD_RECOVERY_SERVICE_CONTRACT_PATH_INVALID');
106
+ }
107
+ requiredText(bundle.database.sha256, 'KNOWN_GOOD_RECOVERY_DATABASE_HASH_INVALID');
108
+ requiredText(bundle.serviceContract.sha256, 'KNOWN_GOOD_RECOVERY_SERVICE_CONTRACT_HASH_INVALID');
109
+ requiredPositiveInteger(bundle.database.schemaVersion, 'KNOWN_GOOD_RECOVERY_DATABASE_SCHEMA_INVALID');
110
+ return {
111
+ ...bundle,
112
+ attestationId,
113
+ root,
114
+ database: { ...bundle.database, path: resolve(bundle.database.path) },
115
+ serviceContract: { ...bundle.serviceContract, path: resolve(bundle.serviceContract.path) },
116
+ };
117
+ }
118
+
119
+ /**
120
+ * Validate the exact three-way restore invariant used by both Recovery and
121
+ * release retention. Legacy evidence without a Recovery bundle is historical
122
+ * audit data only: it must never be promoted to recoverable authority.
123
+ */
124
+ export function inspectKnownGoodRecoveryBundle(
125
+ controllerHome: string,
126
+ entry: KnownGoodReleaseIdentity,
127
+ ): InspectedKnownGoodRecoveryBundle {
128
+ const home = resolve(controllerHome);
129
+ if (entry.controllerHome && canonical(entry.controllerHome) !== canonical(home)) {
130
+ throw new Error('KNOWN_GOOD_RECOVERY_CONTROLLER_HOME_MISMATCH');
131
+ }
132
+ const manifestPath = resolve(requiredText(entry.path, 'KNOWN_GOOD_RELEASE_MANIFEST_PATH_INVALID'));
133
+ const releasesRoot = resolve(home, 'runtime', 'releases');
134
+ const releaseRoot = dirname(manifestPath);
135
+ if (
136
+ basename(manifestPath) !== 'manifest.json'
137
+ || basename(releaseRoot) !== entry.revision
138
+ || !directChild(releasesRoot, releaseRoot)
139
+ || !existsSync(manifestPath)
140
+ ) throw new Error('KNOWN_GOOD_RELEASE_OUTSIDE_AUTHORITY');
141
+ const manifest = loadRuntimeReleaseManifest(manifestPath, home);
142
+ if (
143
+ manifest.releaseId !== entry.revision
144
+ || manifest.artifactIdentity !== entry.artifactIdentity
145
+ || manifest.workerProtocolVersion !== entry.workerProtocolVersion
146
+ || sha256FileBounded(manifestPath) !== entry.manifestSha256
147
+ ) throw new Error('KNOWN_GOOD_RELEASE_IDENTITY_MISMATCH');
148
+
149
+ const bundle = validateRecoveryBundleShape(entry, home);
150
+ if (!existsSync(bundle.database.path)) throw new Error('KNOWN_GOOD_RECOVERY_DATABASE_MISSING');
151
+ if (sha256FileBounded(bundle.database.path) !== bundle.database.sha256) throw new Error('KNOWN_GOOD_RECOVERY_DATABASE_HASH_MISMATCH');
152
+ const database = inspectControlPlaneDatabaseFile(bundle.database.path);
153
+ if (
154
+ database.schemaVersion !== bundle.database.schemaVersion
155
+ || database.recordCount !== bundle.database.recordCount
156
+ || database.auditEventCount !== bundle.database.auditEventCount
157
+ ) throw new Error('KNOWN_GOOD_RECOVERY_DATABASE_INSPECTION_MISMATCH');
158
+
159
+ if (!existsSync(bundle.serviceContract.path)) throw new Error('KNOWN_GOOD_RECOVERY_SERVICE_CONTRACT_MISSING');
160
+ if (sha256FileBounded(bundle.serviceContract.path) !== bundle.serviceContract.sha256) {
161
+ throw new Error('KNOWN_GOOD_RECOVERY_SERVICE_CONTRACT_HASH_MISMATCH');
162
+ }
163
+ let rawContract: unknown;
164
+ try { rawContract = JSON.parse(readFileSync(bundle.serviceContract.path, 'utf8')); }
165
+ catch { throw new Error('KNOWN_GOOD_RECOVERY_SERVICE_CONTRACT_INVALID'); }
166
+ if (!rawContract || typeof rawContract !== 'object' || Array.isArray(rawContract)) {
167
+ throw new Error('KNOWN_GOOD_RECOVERY_SERVICE_CONTRACT_INVALID');
168
+ }
169
+ const contract = rawContract as Record<string, unknown>;
170
+ if (contract.schemaVersion !== 1 || !contract.serviceConfig || typeof contract.serviceConfig !== 'object' || Array.isArray(contract.serviceConfig)) {
171
+ throw new Error('KNOWN_GOOD_RECOVERY_SERVICE_CONTRACT_INVALID');
172
+ }
173
+ const serviceConfig = validateForgeRuntimeServiceConfig(contract.serviceConfig as ForgeRuntimeServiceConfig);
174
+ if (canonical(serviceConfig.controllerHome) !== canonical(home)) throw new Error('KNOWN_GOOD_RECOVERY_SERVICE_HOME_MISMATCH');
175
+ const expectedConfigPath = forgeRuntimeServicePaths(home).configPath;
176
+ if (canonical(requiredText(contract.configPath, 'KNOWN_GOOD_RECOVERY_SERVICE_PATH_INVALID')) !== canonical(expectedConfigPath)) {
177
+ throw new Error('KNOWN_GOOD_RECOVERY_SERVICE_PATH_INVALID');
178
+ }
179
+ return { releaseRoot, database, serviceConfig };
180
+ }
181
+
182
+ export function knownGoodRecoveryBundleRoot(controllerHome: string): string {
183
+ return join(resolve(controllerHome), 'recovery', 'bundles', 'known-good');
184
+ }
@@ -35,7 +35,6 @@ export async function startConfiguredRuntimeLocalBridge(input: {
35
35
  controllerHome: input.controllerHome,
36
36
  host: local.host ?? '127.0.0.1',
37
37
  port: local.port ?? 8766,
38
- openBrowser: local.autoOpen === true,
39
38
  mode: 'embedded',
40
39
  });
41
40
  const generation = readRuntimeGeneration(input.controllerHome)?.generation;
@@ -13,11 +13,19 @@ interface ManagedSession {
13
13
  activeStreams: number;
14
14
  }
15
15
 
16
+ type RuntimeMcpRequestId = string | number;
17
+ interface ActiveRuntimeMcpPost {
18
+ response: Response;
19
+ requestIds: RuntimeMcpRequestId[];
20
+ transport?: NodeStreamableHTTPServerTransport;
21
+ }
22
+
16
23
  export interface RuntimeMcpSessionSnapshot {
17
24
  active: number;
18
25
  maximum: number;
19
26
  initializing: number;
20
27
  protected: number;
28
+ activeRequests: number;
21
29
  capacityAvailable: number;
22
30
  capacityEvictions: number;
23
31
  }
@@ -47,6 +55,8 @@ export interface StartRuntimeMcpTransportOptions {
47
55
  onFatal?: (error: Error) => void;
48
56
  /** Internal Runtime sessions are bounded even if a Gateway dies without DELETE. */
49
57
  maximumSessions?: number;
58
+ /** Test/embedded override; production defaults to the bounded cutover grace. */
59
+ requestDrainTimeoutMs?: number;
50
60
  }
51
61
 
52
62
  function authorized(request: Request, configuredToken: string): boolean {
@@ -76,6 +86,15 @@ function observesToolSurface(body: unknown): boolean {
76
86
  });
77
87
  }
78
88
 
89
+ function runtimeMcpRequestIds(body: unknown): RuntimeMcpRequestId[] {
90
+ const values = Array.isArray(body) ? body : [body];
91
+ return values.flatMap((value) => {
92
+ if (!value || typeof value !== 'object') return [];
93
+ const id = (value as Record<string, unknown>).id;
94
+ return typeof id === 'string' || typeof id === 'number' ? [id] : [];
95
+ });
96
+ }
97
+
79
98
  function parseBody(body: unknown): unknown {
80
99
  if (!Buffer.isBuffer(body)) return body;
81
100
  try { return JSON.parse(body.toString('utf8')); } catch {
@@ -95,7 +114,16 @@ function authMiddleware(token: string) {
95
114
  }
96
115
 
97
116
  const SESSION_CLOSE_TIMEOUT_MS = 1_000;
98
- const REQUEST_DRAIN_TIMEOUT_MS = 250;
117
+ /**
118
+ * Cutover first withdraws admission, then gives already-admitted requests a
119
+ * bounded grace period that still fits inside the primary service stop budget.
120
+ * Requests that outlive it are explicitly settled as outcome-unknown before
121
+ * session/socket teardown, so an outer controller turn is never left waiting on
122
+ * a connection the Runtime is intentionally destroying.
123
+ */
124
+ export const RUNTIME_MCP_REQUEST_DRAIN_TIMEOUT_MS = 5_000;
125
+ const CUTOVER_SETTLEMENT_DRAIN_TIMEOUT_MS = 250;
126
+ export const RUNTIME_MCP_CUTOVER_OUTCOME_UNKNOWN = 'MCP_RUNTIME_CUTOVER_OUTCOME_UNKNOWN';
99
127
  export const DEFAULT_RUNTIME_MCP_MAX_SESSIONS = 64;
100
128
 
101
129
  function boundedRuntimeMcpMaximumSessions(value: number | undefined): number {
@@ -112,31 +140,41 @@ function closeServer(server: NodeHttpServer): Promise<void> {
112
140
  });
113
141
  }
114
142
 
115
- function boundedDrain(wait: Promise<void>, timeoutMs: number): Promise<void> {
116
- if (timeoutMs <= 0) return Promise.resolve();
117
- return Promise.race([
118
- wait.catch(() => undefined),
143
+ async function boundedDrain(wait: Promise<void>, timeoutMs: number): Promise<boolean> {
144
+ if (timeoutMs <= 0) return false;
145
+ let drained = false;
146
+ await Promise.race([
147
+ wait.then(() => { drained = true; }).catch(() => undefined),
119
148
  new Promise<void>((resolve) => setTimeout(resolve, timeoutMs)),
120
149
  ]);
150
+ return drained;
121
151
  }
122
152
 
123
153
  export async function closeRuntimeMcpTransportResources(input: {
124
154
  closeListener: () => Promise<void>;
125
155
  closeSessions: Array<() => Promise<void>>;
126
156
  waitForRequestDrain?: () => Promise<void>;
157
+ settleActiveRequests?: () => void | Promise<void>;
127
158
  forceCloseConnections?: () => void;
128
159
  requestDrainTimeoutMs?: number;
129
160
  sessionCloseTimeoutMs?: number;
130
161
  }): Promise<void> {
131
- // Withdraw the TCP listener first so no new request can enter. Allow ordinary
132
- // short MCP calls to finish before closing their session transport; long SSE
133
- // streams remain bounded and are force-closed after the drain window.
162
+ // Withdraw the listener first so no new request can enter. Existing calls get
163
+ // one bounded grace window. If that expires, settle still-open POST responses
164
+ // as explicit cutover/outcome-unknown before closing session transports. This
165
+ // preserves the no-blind-replay contract while preventing a controller turn
166
+ // from being stranded on a socket the Runtime is about to destroy.
134
167
  const listenerClose = input.closeListener();
135
168
  void listenerClose.catch(() => undefined);
136
- await boundedDrain(
137
- input.waitForRequestDrain?.() ?? Promise.resolve(),
138
- Math.max(0, input.requestDrainTimeoutMs ?? REQUEST_DRAIN_TIMEOUT_MS),
169
+ const requestDrain = input.waitForRequestDrain?.() ?? Promise.resolve();
170
+ const drained = await boundedDrain(
171
+ requestDrain,
172
+ Math.max(0, input.requestDrainTimeoutMs ?? RUNTIME_MCP_REQUEST_DRAIN_TIMEOUT_MS),
139
173
  );
174
+ if (!drained) {
175
+ await input.settleActiveRequests?.();
176
+ await boundedDrain(requestDrain, CUTOVER_SETTLEMENT_DRAIN_TIMEOUT_MS);
177
+ }
140
178
  const sessionDrain = Promise.allSettled(input.closeSessions.map(async (close) => await close()));
141
179
  await boundedDrain(sessionDrain.then(() => undefined), Math.max(0, input.sessionCloseTimeoutMs ?? SESSION_CLOSE_TIMEOUT_MS));
142
180
  input.forceCloseConnections?.();
@@ -152,12 +190,14 @@ export async function startRuntimeMcpTransport(
152
190
  let initializingSessions = 0;
153
191
  let capacityEvictions = 0;
154
192
  let activeRequests = 0;
193
+ const activePosts = new Map<Response, ActiveRuntimeMcpPost>();
155
194
 
156
195
  const sessionSnapshot = (): RuntimeMcpSessionSnapshot => ({
157
196
  active: sessions.size,
158
197
  maximum: maximumSessions,
159
198
  initializing: initializingSessions,
160
199
  protected: [...sessions.values()].filter((session) => session.activePosts > 0).length,
200
+ activeRequests,
161
201
  capacityAvailable: Math.max(0, maximumSessions - sessions.size - initializingSessions),
162
202
  capacityEvictions,
163
203
  });
@@ -192,7 +232,7 @@ export async function startRuntimeMcpTransport(
192
232
  managed.lastActivityAt = Date.now();
193
233
  }
194
234
  };
195
- const requestDrainWaiters = new Set<() => void>();
235
+ const postDrainWaiters = new Set<() => void>();
196
236
  const app = express();
197
237
  app.disable('x-powered-by');
198
238
  app.use((_req, res, next) => {
@@ -202,18 +242,17 @@ export async function startRuntimeMcpTransport(
202
242
  if (settled) return;
203
243
  settled = true;
204
244
  activeRequests = Math.max(0, activeRequests - 1);
205
- if (activeRequests === 0) {
206
- for (const resolve of requestDrainWaiters) resolve();
207
- requestDrainWaiters.clear();
208
- }
209
245
  };
210
246
  res.once('finish', settle);
211
247
  res.once('close', settle);
212
248
  next();
213
249
  });
214
- const waitForRequestDrain = (): Promise<void> => activeRequests === 0
250
+ // Only POST requests can represent an in-flight tool mutation/read result that
251
+ // must settle before cutover. Long-lived GET/SSE streams are transport-only and
252
+ // must not consume the cutover grace window.
253
+ const waitForRequestDrain = (): Promise<void> => activePosts.size === 0
215
254
  ? Promise.resolve()
216
- : new Promise<void>((resolve) => requestDrainWaiters.add(resolve));
255
+ : new Promise<void>((resolve) => postDrainWaiters.add(resolve));
217
256
  app.get('/ready', (_req, res) => {
218
257
  const readiness = options.readiness();
219
258
  res.status(readiness.ready ? 200 : 503).json(readiness);
@@ -221,12 +260,24 @@ export async function startRuntimeMcpTransport(
221
260
 
222
261
  const requireAuth = authMiddleware(options.authToken);
223
262
  app.post('/mcp', requireAuth, express.raw({ type: '*/*', limit: '1mb' }), (req, res) => {
263
+ const activePost: ActiveRuntimeMcpPost = { response: res, requestIds: [] };
264
+ activePosts.set(res, activePost);
265
+ const releasePostResponse = (): void => {
266
+ activePosts.delete(res);
267
+ if (activePosts.size === 0) {
268
+ for (const resolve of postDrainWaiters) resolve();
269
+ postDrainWaiters.clear();
270
+ }
271
+ };
272
+ res.once('finish', releasePostResponse);
273
+ res.once('close', releasePostResponse);
224
274
  void (async () => {
225
275
  let body: unknown;
226
276
  try { body = parseBody(req.body); } catch (error) {
227
277
  res.status(400).json({ error: error instanceof Error ? error.message : String(error) });
228
278
  return;
229
279
  }
280
+ activePost.requestIds = runtimeMcpRequestIds(body);
230
281
  if (observesToolSurface(body)) options.onToolSurfaceObservation?.();
231
282
  const requestedSessionId = req.headers['mcp-session-id'];
232
283
  const sessionId = typeof requestedSessionId === 'string' ? requestedSessionId : undefined;
@@ -265,6 +316,7 @@ export async function startRuntimeMcpTransport(
265
316
  });
266
317
  },
267
318
  });
319
+ activePost.transport = transport;
268
320
  transport.onclose = () => {
269
321
  if (transport.sessionId) sessions.delete(transport.sessionId);
270
322
  };
@@ -293,10 +345,15 @@ export async function startRuntimeMcpTransport(
293
345
  res.status(404).json({ error: 'mcp_session_not_found' });
294
346
  return;
295
347
  }
348
+ activePost.transport = managed.transport;
296
349
  await withManagedSessionRequest(managed, 'post', async () => await managed.transport.handleRequest(req, res, body));
297
350
  })().catch((error: unknown) => {
298
351
  if (!res.headersSent) res.status(500).json({ error: 'mcp_request_failed' });
299
352
  console.error('[forge-runtime mcp] request failed:', error);
353
+ }).finally(() => {
354
+ releasePostResponse();
355
+ res.off('finish', releasePostResponse);
356
+ res.off('close', releasePostResponse);
300
357
  });
301
358
  });
302
359
  app.get('/mcp', requireAuth, (req, res) => {
@@ -362,6 +419,7 @@ export async function startRuntimeMcpTransport(
362
419
  await closeRuntimeMcpTransportResources({
363
420
  closeListener: async () => await closeServer(httpServer),
364
421
  waitForRequestDrain,
422
+ requestDrainTimeoutMs: options.requestDrainTimeoutMs,
365
423
  // Snapshot sessions only after the request drain: an initialize request
366
424
  // already in flight may register its session while shutdown is starting.
367
425
  closeSessions: [async () => {
@@ -369,6 +427,41 @@ export async function startRuntimeMcpTransport(
369
427
  await Promise.allSettled(activeSessions.map(async ({ transport }) => await transport.close().catch(() => undefined)));
370
428
  sessions.clear();
371
429
  }],
430
+ settleActiveRequests: async () => {
431
+ for (const active of activePosts.values()) {
432
+ let protocolSettled = false;
433
+ if (active.transport && active.requestIds.length > 0) {
434
+ const outcomes = await Promise.allSettled(active.requestIds.map(async (id) => {
435
+ await active.transport!.send({
436
+ jsonrpc: '2.0',
437
+ id,
438
+ error: {
439
+ code: -32000,
440
+ message: RUNTIME_MCP_CUTOVER_OUTCOME_UNKNOWN,
441
+ data: {
442
+ outcome: 'unknown',
443
+ recoverable: true,
444
+ retryable: false,
445
+ action: 'reconcile',
446
+ },
447
+ },
448
+ });
449
+ }));
450
+ protocolSettled = outcomes.some((outcome) => outcome.status === 'fulfilled');
451
+ }
452
+ if (protocolSettled) continue;
453
+ const response = active.response;
454
+ if (response.destroyed || response.writableEnded || response.headersSent) continue;
455
+ response.status(409).json({
456
+ error: 'runtime_cutover_outcome_unknown',
457
+ code: RUNTIME_MCP_CUTOVER_OUTCOME_UNKNOWN,
458
+ message: 'Canonical Runtime entered cutover after this request was admitted. The request outcome is unknown; reconcile by request/effect identity before any retry.',
459
+ recoverable: true,
460
+ retryable: false,
461
+ action: 'reconcile',
462
+ });
463
+ }
464
+ },
372
465
  forceCloseConnections: () => httpServer.closeAllConnections?.(),
373
466
  });
374
467
  },