@moretea-labs/forge 1.7.2 → 1.8.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (900) hide show
  1. package/AGENTS.md +121 -62
  2. package/CHANGELOG.md +40 -0
  3. package/CLAUDE.md +57 -62
  4. package/CONTRIBUTING.md +3 -2
  5. package/README.md +2 -2
  6. package/SKILL.md +0 -1
  7. package/THIRD_PARTY_NOTICES.md +5 -2
  8. package/adapters/browser/index.ts +2 -0
  9. package/adapters/chatgpt/browser-delivery-host.ts +77 -0
  10. package/adapters/chatgpt/browser-delivery-runtime.ts +1256 -0
  11. package/adapters/chatgpt/controller-binding-store.ts +134 -0
  12. package/adapters/chatgpt/controller-round-host.ts +68 -0
  13. package/adapters/chatgpt/controller-round-settlement-store.ts +99 -0
  14. package/adapters/chatgpt/provider-delivery.ts +340 -0
  15. package/adapters/chatgpt/work-conversation-binding-store.ts +218 -0
  16. package/adapters/chatgpt/wsl-bridge-delivery-host.ts +63 -0
  17. package/adapters/computer/chatgpt-extension-target.ts +463 -0
  18. package/adapters/computer/chatgpt-target-router.ts +103 -0
  19. package/adapters/computer/chrome-extension/background.js +385 -0
  20. package/adapters/computer/chrome-extension/content.js +378 -0
  21. package/adapters/computer/chrome-extension/core.js +24 -0
  22. package/adapters/computer/chrome-extension/manifest.json +30 -0
  23. package/adapters/computer/desktop-operator-contract.ts +7 -0
  24. package/adapters/computer/desktop-operator-discovery.ts +181 -0
  25. package/adapters/computer/desktop-operator-negotiation.ts +174 -0
  26. package/adapters/computer/desktop-operator-provider.ts +312 -0
  27. package/adapters/computer/index.ts +1 -0
  28. package/adapters/computer/interaction-target-authority.ts +1068 -0
  29. package/adapters/controller-process/binding-store.ts +34 -0
  30. package/adapters/controller-process/controller-host.ts +26 -0
  31. package/adapters/mcp/access-mode.ts +132 -0
  32. package/adapters/mcp/audit.ts +32 -0
  33. package/adapters/mcp/auth.ts +406 -0
  34. package/adapters/mcp/instructions.ts +37 -0
  35. package/adapters/mcp/legacy-context.ts +18 -0
  36. package/adapters/mcp/multi-repository.ts +421 -0
  37. package/adapters/mcp/oauth.ts +464 -0
  38. package/adapters/mcp/paths.ts +143 -0
  39. package/adapters/mcp/policy.ts +232 -0
  40. package/adapters/mcp/proxy-env.ts +62 -0
  41. package/adapters/mcp/readiness-projection.ts +24 -0
  42. package/adapters/mcp/redaction.ts +21 -0
  43. package/adapters/mcp/repo.ts +24 -0
  44. package/adapters/mcp/runtime-gateway/artifact-adapter.ts +52 -0
  45. package/adapters/mcp/runtime-gateway/automation-receipt-adapter.ts +87 -0
  46. package/adapters/mcp/runtime-gateway/bounded-result-runtime.ts +62 -0
  47. package/adapters/mcp/runtime-gateway/cognition-settlement.ts +201 -0
  48. package/adapters/mcp/runtime-gateway/context-adapter.ts +1167 -0
  49. package/adapters/mcp/runtime-gateway/context-pack-sidecar.ts +91 -0
  50. package/adapters/mcp/runtime-gateway/controller-authority-adapter.ts +206 -0
  51. package/adapters/mcp/runtime-gateway/core-capability-adapter.ts +258 -0
  52. package/adapters/mcp/runtime-gateway/engineering-preconditions.ts +130 -0
  53. package/adapters/mcp/runtime-gateway/engineering-tool-contract.ts +15 -0
  54. package/adapters/mcp/runtime-gateway/execution-control-adapter.ts +28 -0
  55. package/adapters/mcp/runtime-gateway/execution-tools.ts +173 -0
  56. package/adapters/mcp/runtime-gateway/filesystem-adapter.ts +38 -0
  57. package/adapters/mcp/runtime-gateway/gateway-execution-adapter.ts +412 -0
  58. package/adapters/mcp/runtime-gateway/legacy-ios-tool-adapter.ts +105 -0
  59. package/adapters/mcp/runtime-gateway/maintenance-adapter.ts +44 -0
  60. package/adapters/mcp/runtime-gateway/model-adapter.ts +63 -0
  61. package/adapters/mcp/runtime-gateway/persisted-check-process.ts +3 -0
  62. package/adapters/mcp/runtime-gateway/plugin-adapter.ts +380 -0
  63. package/adapters/mcp/runtime-gateway/process-tools.ts +457 -0
  64. package/adapters/mcp/runtime-gateway/protected-computer-adapter.ts +88 -0
  65. package/adapters/mcp/runtime-gateway/recovery-adapter.ts +285 -0
  66. package/adapters/mcp/runtime-gateway/recovery-client-adapter.ts +70 -0
  67. package/adapters/mcp/runtime-gateway/recovery-tool-contract.ts +99 -0
  68. package/adapters/mcp/runtime-gateway/repository-compat-adapter.ts +79 -0
  69. package/adapters/mcp/runtime-gateway/result-adapter.ts +114 -0
  70. package/adapters/mcp/runtime-gateway/router.ts +242 -0
  71. package/adapters/mcp/runtime-gateway/routing-policy.ts +499 -0
  72. package/adapters/mcp/runtime-gateway/runtime-observation-adapter.ts +1200 -0
  73. package/adapters/mcp/runtime-gateway/runtime-readiness-observation.ts +218 -0
  74. package/adapters/mcp/runtime-gateway/runtime-tool-definitions.ts +574 -0
  75. package/adapters/mcp/runtime-gateway/runtime-tool-shared.ts +27 -0
  76. package/adapters/mcp/runtime-gateway/runtime-tools.ts +78 -0
  77. package/adapters/mcp/runtime-gateway/scheduler-adapter.ts +187 -0
  78. package/adapters/mcp/runtime-gateway/shared-adapter.ts +45 -0
  79. package/adapters/mcp/runtime-gateway/status-inbox-adapter.ts +962 -0
  80. package/adapters/mcp/runtime-gateway/typescript-navigation-sidecar.ts +136 -0
  81. package/adapters/mcp/runtime-gateway/work-adapter.ts +325 -0
  82. package/adapters/mcp/runtime-gateway/work-controller-operations.ts +257 -0
  83. package/adapters/mcp/runtime-gateway/work-detail-projection.ts +60 -0
  84. package/adapters/mcp/runtime-gateway/work-input-wire-migration.ts +246 -0
  85. package/adapters/mcp/runtime-gateway/work-learning-operations.ts +145 -0
  86. package/adapters/mcp/runtime-gateway/work-list-projection.ts +38 -0
  87. package/adapters/mcp/runtime-gateway/work-plan-operations.ts +382 -0
  88. package/adapters/mcp/runtime-gateway/work-repair-adapter.ts +308 -0
  89. package/adapters/mcp/runtime-gateway/work-requirement-operations.ts +148 -0
  90. package/adapters/mcp/runtime-gateway/work-semantic-operations.ts +263 -0
  91. package/adapters/mcp/runtime-gateway/work-validation-reconciler.ts +1 -0
  92. package/adapters/mcp/runtime-gateway/work-workflow-operations.ts +113 -0
  93. package/adapters/mcp/runtime-gateway/workflow-supervisor-adapter.ts +156 -0
  94. package/adapters/mcp/server.ts +1092 -0
  95. package/adapters/mcp/setup.ts +789 -0
  96. package/adapters/mcp/tool-capability-cache.ts +87 -0
  97. package/adapters/mcp/tool-mapping/access-tools.ts +387 -0
  98. package/adapters/mcp/tool-mapping/legacy-tool-service.ts +5139 -0
  99. package/adapters/mcp/tool-mapping/post-finalize-work-attribution.ts +145 -0
  100. package/adapters/mcp/tool-mapping/repository-tools.ts +1682 -0
  101. package/adapters/mcp/tool-mapping/tools.ts +9 -0
  102. package/adapters/mcp/tool-mapping/umbrella-tools.ts +117 -0
  103. package/adapters/mcp/toolset-names.ts +79 -0
  104. package/adapters/mcp/toolset-selection.ts +41 -0
  105. package/adapters/mcp/toolset.ts +337 -0
  106. package/adapters/mcp/transports/http-observation.ts +365 -0
  107. package/adapters/mcp/transports/http.ts +933 -0
  108. package/adapters/mcp/transports/oauth-http.ts +322 -0
  109. package/adapters/mcp/transports/session-registry.ts +519 -0
  110. package/adapters/mcp/transports/stdio.ts +8 -0
  111. package/adapters/mcp/tunnels/openai-secure-tunnel.ts +223 -0
  112. package/adapters/mcp/types.ts +41 -0
  113. package/assets/AGENTS.md +2 -16
  114. package/assets/CLAUDE.md +2 -16
  115. package/assets/hooks/AGENTS.md +3 -14
  116. package/assets/hooks/CLAUDE.md +3 -14
  117. package/assets/hooks/hook-input.sh +9 -2
  118. package/assets/hooks/lib/workflow-state.sh +28 -10
  119. package/assets/hooks/prompt-guard.sh +63 -37
  120. package/assets/hooks/security-sentinel.sh +2 -1
  121. package/assets/hooks/session-start-context.sh +7 -5
  122. package/assets/hooks/stop-orchestrator.sh +13 -3
  123. package/assets/initializer-question-pack.v4.json +11 -7
  124. package/assets/partials/05-workflow.partial.md +18 -73
  125. package/assets/partials/07-footer.partial.md +1 -1
  126. package/assets/partials-agents/02-operating-mode.partial.md +1 -2
  127. package/assets/partials-agents/04-task-protocol.partial.md +14 -59
  128. package/assets/partials-agents/06-quality-safety.partial.md +11 -16
  129. package/assets/partials-agents/08-deep-docs.partial.md +1 -2
  130. package/assets/plan-map.json +11 -11
  131. package/assets/plugin-registry.v1.json +11 -3
  132. package/assets/plugin-trust-policy.v1.json +6 -0
  133. package/assets/recovery/ForgeRecovery.ps1 +100 -0
  134. package/assets/recovery/forge-wsl-rescue +271 -0
  135. package/assets/reference-configs/agentic-development-flow.md +25 -0
  136. package/assets/reference-configs/development-protocol.md +11 -15
  137. package/assets/reference-configs/document-generation.md +1 -1
  138. package/assets/reference-configs/global-working-rules.md +28 -1
  139. package/assets/reference-configs/harness-overview.md +22 -112
  140. package/assets/reference-configs/hook-operations.md +1 -1
  141. package/assets/reference-configs/sprint-contracts.md +2 -2
  142. package/assets/skill-version.json +2 -2
  143. package/assets/templates/helpers/architecture-event.ts +3 -34
  144. package/assets/templates/helpers/architecture-queue.sh +61 -10
  145. package/assets/templates/helpers/archive-workflow.sh +90 -180
  146. package/assets/templates/helpers/capability-config.ts +8 -11
  147. package/assets/templates/helpers/capability-resolver.ts +37 -19
  148. package/assets/templates/helpers/capture-plan.sh +2 -2
  149. package/assets/templates/helpers/check-architecture-sync.sh +1 -9
  150. package/assets/templates/helpers/check-task-sync.sh +82 -11
  151. package/assets/templates/helpers/check-task-workflow.sh +1 -3
  152. package/assets/templates/helpers/context-contract-sync.sh +1 -12
  153. package/assets/templates/helpers/contract-worktree.sh +26 -24
  154. package/assets/templates/helpers/ensure-task-workflow.sh +6 -8
  155. package/assets/templates/helpers/inspect-project-state.ts +1 -1
  156. package/assets/templates/helpers/migrate-project-template.sh +1 -1
  157. package/assets/templates/helpers/migrate-workflow-docs.ts +53 -239
  158. package/assets/templates/helpers/new-plan.sh +2 -2
  159. package/assets/templates/helpers/plan-to-todo.sh +3 -31
  160. package/assets/templates/helpers/sprint-backlog.sh +1 -1
  161. package/assets/templates/helpers/switch-plan.sh +1 -1
  162. package/assets/templates/helpers/workflow-contract.ts +1 -0
  163. package/assets/workflow-contract.v1.json +63 -171
  164. package/assets/workflows/xiaohongshu/xiaohongshu.collect-metrics.v1.draft.json +118 -0
  165. package/assets/workflows/xiaohongshu/xiaohongshu.publish-image-note.v1.draft.json +316 -0
  166. package/assets/workflows/xiaohongshu/xiaohongshu.publish-long-text.v1.draft.json +324 -0
  167. package/docs/architecture/CURRENT.md +233 -28
  168. package/docs/architecture/EVOLUTION.md +13 -0
  169. package/docs/architecture/decisions/20260801-controller-home-sqlite-state.md +2 -1
  170. package/docs/architecture/decisions/20260803-release-identity-binding-and-exit-policy.md +14 -5
  171. package/docs/architecture/decisions/20260823-immediate-controller-relay.md +6 -3
  172. package/docs/architecture/decisions/20260831-independent-windows-wsl-host-rescue.md +59 -0
  173. package/docs/architecture/decisions/20260904-ios-device-migration-baseline.md +120 -0
  174. package/docs/architecture/decisions/20260904-repository-runtime-data-boundary.md +42 -0
  175. package/docs/architecture/decisions/20260907-assistant-learning-loop.md +37 -0
  176. package/docs/architecture/decisions/20260907-controller-round-transition-policy.md +311 -0
  177. package/docs/architecture/decisions/20260907-maintenance-diagnosis-bounded-read.md +39 -0
  178. package/docs/architecture/decisions/20260916-workflow-supervisor-authority.md +249 -0
  179. package/docs/architecture/decisions/20260917-cognitive-memory-foundation.md +82 -0
  180. package/docs/architecture/decisions/20260918-stable-candidate-release-lifecycle.md +221 -0
  181. package/docs/architecture/decisions/20260919-autonomous-work-liveness.md +62 -0
  182. package/docs/architecture/decisions/20260924-thin-semantic-working-context.md +72 -0
  183. package/docs/architecture/decisions/20261001-supervisor-turn-authority.md +237 -0
  184. package/docs/architecture/decisions/20261005-forge-v3-desktop-client-boundary.md +77 -0
  185. package/docs/architecture/domains/verification.md +8 -0
  186. package/docs/architecture/domains/workflow-engine.md +7 -1
  187. package/docs/architecture/index.md +3 -3
  188. package/docs/architecture/modules/controller-runtime/transport-lifecycle.md +19 -8
  189. package/docs/architecture/requests/2026-09-04-computer-plugin-workflow-taxonomy.md +124 -0
  190. package/docs/forge-chatgpt-mcp-setup.md +5 -3
  191. package/docs/forge-plugin-management.md +20 -4
  192. package/docs/forge-runtime-self-healing-loop.md +2 -0
  193. package/docs/operations/benchmark-cross-version-freeze.md +38 -0
  194. package/docs/operations/controller-browser-plugin.md +3 -1
  195. package/docs/operations/controller-performance-and-502.md +17 -0
  196. package/docs/operations/controller-reliability-runbook.md +2 -2
  197. package/docs/operations/features.md +1 -1
  198. package/docs/operations/features.zh-CN.md +1 -1
  199. package/docs/operations/homebrew.md +2 -2
  200. package/docs/operations/mcp-tool-exposure.md +2 -0
  201. package/docs/operations/platform-support.md +16 -8
  202. package/docs/operations/platform-support.zh-CN.md +2 -2
  203. package/docs/operations/releasing.md +2 -0
  204. package/docs/operations/standalone-disaster-recovery.md +38 -5
  205. package/docs/operations/uu-remote-rescue.md +41 -0
  206. package/docs/operations/windows-wsl-host-rescue.md +133 -0
  207. package/docs/public-usage-guide.md +1 -1
  208. package/docs/public-usage-guide.zh-CN.md +1 -1
  209. package/docs/tutorials/01-install-and-start.md +1 -1
  210. package/docs/tutorials/01-install-and-start.zh-CN.md +1 -1
  211. package/docs/tutorials/02-connect-chatgpt.md +4 -4
  212. package/docs/tutorials/02-connect-chatgpt.zh-CN.md +4 -4
  213. package/docs/wiki/Implementation.md +1 -1
  214. package/package.json +46 -26
  215. package/packages/kernel/cognition/api/index.ts +6 -0
  216. package/packages/kernel/cognition/application/activation-service.ts +451 -0
  217. package/packages/kernel/cognition/application/consolidation-service.ts +185 -0
  218. package/packages/kernel/cognition/application/legacy-experience-adapter.ts +38 -0
  219. package/packages/kernel/cognition/application/memory-service.ts +64 -0
  220. package/packages/kernel/cognition/domain/learning.ts +106 -0
  221. package/packages/kernel/cognition/domain/memory.ts +254 -0
  222. package/packages/kernel/controller/api/index.ts +3 -0
  223. package/packages/kernel/controller/application/continuation-service.ts +281 -0
  224. package/packages/kernel/controller/application/controller-round-service.ts +41 -0
  225. package/packages/kernel/controller/application/controller-service.ts +30 -0
  226. package/packages/kernel/controller/domain/controller-round-transition-policy.ts +529 -0
  227. package/packages/kernel/controller/domain/controller-round.ts +110 -0
  228. package/packages/kernel/controller/domain/execution-quality.ts +135 -0
  229. package/packages/kernel/controller/domain/types.ts +56 -0
  230. package/packages/kernel/controller/index.ts +1 -0
  231. package/packages/kernel/controller/infrastructure/controller-binding-store.ts +84 -0
  232. package/packages/kernel/controller/infrastructure/controller-round-store.ts +1970 -0
  233. package/packages/kernel/controller/infrastructure/controller-session-store.ts +804 -0
  234. package/packages/kernel/controller/ports/controller-host.ts +18 -0
  235. package/packages/kernel/goal/api/index.ts +1 -0
  236. package/packages/kernel/goal/domain/types.ts +40 -0
  237. package/packages/kernel/goal/index.ts +1 -0
  238. package/packages/kernel/identity/api/index.ts +15 -0
  239. package/packages/kernel/identity/application/identity-service.ts +67 -0
  240. package/packages/kernel/identity/domain/activity-projection.ts +43 -0
  241. package/packages/kernel/identity/domain/capability-broker.ts +60 -0
  242. package/packages/kernel/identity/domain/grant.ts +72 -0
  243. package/packages/kernel/identity/domain/owned-resource.ts +116 -0
  244. package/packages/kernel/identity/domain/scope.ts +63 -0
  245. package/packages/kernel/identity/domain/semantic-sync.ts +81 -0
  246. package/packages/kernel/identity/domain/types.ts +44 -0
  247. package/packages/kernel/identity/domain/user-request.ts +93 -0
  248. package/packages/kernel/identity/domain/workspace.ts +56 -0
  249. package/packages/kernel/identity/index.ts +1 -0
  250. package/packages/kernel/identity/infrastructure/activity-projection-store.ts +77 -0
  251. package/packages/kernel/identity/infrastructure/capability-broker.ts +81 -0
  252. package/packages/kernel/identity/infrastructure/grant-store.ts +284 -0
  253. package/packages/kernel/identity/infrastructure/identity-store.ts +75 -0
  254. package/packages/kernel/identity/infrastructure/owned-resource-store.ts +259 -0
  255. package/packages/kernel/identity/infrastructure/user-request-store.ts +182 -0
  256. package/packages/kernel/memory/api/index.ts +5 -0
  257. package/packages/kernel/memory/application/experience-service.ts +118 -0
  258. package/packages/kernel/memory/application/outcome-service.ts +77 -0
  259. package/packages/kernel/memory/domain/experience.ts +103 -0
  260. package/packages/kernel/memory/domain/operational-prior.ts +92 -0
  261. package/packages/kernel/memory/index.ts +1 -0
  262. package/packages/kernel/scheduler/api/index.ts +4 -0
  263. package/packages/kernel/scheduler/application/eligibility.ts +252 -0
  264. package/packages/kernel/scheduler/application/schedule-service.ts +27 -0
  265. package/packages/kernel/scheduler/application/settlement.ts +182 -0
  266. package/packages/kernel/scheduler/domain/schedule.ts +236 -0
  267. package/packages/kernel/scheduler/index.ts +1 -0
  268. package/packages/kernel/scheduler/infrastructure/schedule-store.ts +805 -0
  269. package/packages/kernel/work/api/index.ts +16 -0
  270. package/packages/kernel/work/application/work-service.ts +123 -0
  271. package/packages/kernel/work/domain/check-receipt.ts +43 -0
  272. package/packages/kernel/work/domain/context-closure-receipt.ts +32 -0
  273. package/packages/kernel/work/domain/current-task-lineage.ts +104 -0
  274. package/packages/kernel/work/domain/engineering-contracts.ts +157 -0
  275. package/packages/kernel/work/domain/engineering-design.ts +286 -0
  276. package/packages/kernel/work/domain/engineering-profile.ts +238 -0
  277. package/packages/kernel/work/domain/evaluation-promotion-receipt.ts +186 -0
  278. package/packages/kernel/work/domain/execution-concurrency.ts +247 -0
  279. package/packages/kernel/work/domain/execution-snapshot.ts +2 -0
  280. package/packages/kernel/work/domain/implementation-review.ts +193 -0
  281. package/packages/kernel/work/domain/objective-graph.ts +119 -0
  282. package/packages/kernel/work/domain/project-engineering-contract.ts +224 -0
  283. package/packages/kernel/work/domain/repository-completion-receipt.ts +73 -0
  284. package/{src/runtime/control-plane/facade/work-state-machine.ts → packages/kernel/work/domain/state-machine.ts} +37 -66
  285. package/packages/kernel/work/domain/types.ts +534 -0
  286. package/packages/kernel/work/index.ts +1 -0
  287. package/packages/kernel/work/infrastructure/work-contract-store.ts +1967 -0
  288. package/packages/kernel/work/ports/work-contract-store.ts +21 -0
  289. package/packages/plugin-runtime/browser/index.ts +3 -0
  290. package/packages/plugin-runtime/browser/provider-registry.ts +110 -0
  291. package/packages/plugin-runtime/browser/runtime-contract.ts +150 -0
  292. package/packages/plugin-runtime/browser/session-authority.ts +62 -0
  293. package/packages/plugin-runtime/computer/chatgpt-identity.ts +24 -0
  294. package/packages/plugin-runtime/computer/conversation-target.ts +143 -0
  295. package/packages/plugin-runtime/computer/index.ts +8 -0
  296. package/packages/plugin-runtime/computer/provider-error.ts +26 -0
  297. package/packages/plugin-runtime/computer/provider-registration.ts +52 -0
  298. package/packages/plugin-runtime/computer/provider-registry.ts +63 -0
  299. package/packages/plugin-runtime/computer/provider.ts +19 -0
  300. package/packages/plugin-runtime/computer/target-authority.ts +215 -0
  301. package/packages/plugin-runtime/computer/target-persistence.ts +54 -0
  302. package/packages/plugin-runtime/external/index.ts +1 -0
  303. package/packages/plugin-runtime/external/unix-jsonl-transport.ts +581 -0
  304. package/packages/plugin-runtime/index.ts +3 -0
  305. package/packages/protocols/browser/index.ts +1 -0
  306. package/packages/protocols/browser/session.ts +98 -0
  307. package/packages/protocols/computer/contract.ts +225 -0
  308. package/packages/protocols/computer/index.ts +1 -0
  309. package/packages/protocols/failure/contract.ts +158 -0
  310. package/packages/protocols/failure/index.ts +1 -0
  311. package/packages/protocols/handoff/index.ts +1 -0
  312. package/packages/protocols/handoff/status.ts +22 -0
  313. package/packages/protocols/mcp/execution-context.ts +11 -0
  314. package/packages/protocols/mcp/index.ts +2 -0
  315. package/packages/protocols/mcp/tool-contract.ts +42 -0
  316. package/packages/workflow-runtime/api/index.ts +2 -0
  317. package/packages/workflow-runtime/application/interpreter.ts +342 -0
  318. package/packages/workflow-runtime/domain/workflow-asset.ts +223 -0
  319. package/packages/workflow-runtime/index.ts +1 -0
  320. package/scripts/activate-source-baseline.ts +7 -9
  321. package/scripts/assemble-template.ts +1 -1
  322. package/scripts/bootstrap-runtime-maintenance-recovery.sh +4 -1
  323. package/scripts/canary-chatgpt-provider-delivery.ts +97 -0
  324. package/scripts/canary-controller-semantic-wait.ts +183 -0
  325. package/scripts/canary-global-hook.sh +2 -2
  326. package/scripts/check-mcp-compatibility.ts +85 -7
  327. package/scripts/check-platform-support.mjs +28 -2
  328. package/scripts/check-public-docs.sh +1 -1
  329. package/scripts/check-repository-hygiene.mjs +92 -0
  330. package/scripts/check-runtime-architecture.mjs +1643 -127
  331. package/scripts/check-source-duplication.mjs +9 -1
  332. package/scripts/controller-ngrok-rotation.sh +5 -4
  333. package/scripts/create-project-dirs.sh +10 -74
  334. package/scripts/forge-local-recovery-helper.mjs +282 -0
  335. package/scripts/forge-uu-remote-rescue-helper.d.mts +31 -0
  336. package/scripts/forge-uu-remote-rescue-helper.mjs +409 -0
  337. package/scripts/forge-windows-host-recovery-helper.mjs +136 -0
  338. package/scripts/hook-shim.sh +2 -2
  339. package/scripts/init-project.sh +12 -70
  340. package/scripts/install-desktop-operator-registration.ts +4 -2
  341. package/scripts/install-independent-windows-wsl-recovery.ts +125 -0
  342. package/scripts/install-standalone-recovery.ts +122 -10
  343. package/scripts/install-uu-remote-rescue-registration.ts +74 -0
  344. package/scripts/install-windows-host-recovery-registration.ts +22 -0
  345. package/scripts/lib/controller-home-env.sh +6 -3
  346. package/scripts/lib/project-init-lib.sh +42 -582
  347. package/scripts/migrate-chatgpt-automation-schedules.ts +2 -2
  348. package/scripts/migrate-windows-wsl-controller-home.ts +306 -0
  349. package/scripts/open-source-audit-allowlist.txt +11 -1
  350. package/scripts/portability-bindings.mjs +70 -0
  351. package/scripts/run-bounded-command.mjs +60 -0
  352. package/scripts/run-bun-test-file.ts +22 -6
  353. package/scripts/run-governed-gate.ts +4 -2
  354. package/scripts/run-mobile-monitor-bridge.ts +0 -1
  355. package/scripts/smoke-control-plane-failure-domain.ts +94 -0
  356. package/scripts/smoke-mcp-http-runtime.ts +6 -1
  357. package/scripts/smoke-runtime-recovery.ts +13 -11
  358. package/scripts/smoke-schedule-engine.ts +24 -16
  359. package/scripts/smoke-unattended-transport-recovery.ts +223 -0
  360. package/scripts/smoke-user-request-continuation-restart.ts +232 -0
  361. package/scripts/smoke-workflow-supervisor-chrome-adapter.ts +92 -0
  362. package/scripts/smoke-workflow-supervisor-process-restart.ts +276 -0
  363. package/scripts/smoke-workflow-supervisor-restart-recovery.ts +150 -0
  364. package/scripts/smoke-workflow-supervisor.ts +103 -0
  365. package/scripts/test-governance.ts +51 -2
  366. package/scripts/verify-forge-runtime.sh +2 -1
  367. package/src/cli/agent-jobs/executor-health.ts +11 -34
  368. package/src/cli/agent-jobs/integration.ts +18 -49
  369. package/src/cli/agent-jobs/job-manager.ts +17 -4
  370. package/src/cli/chatgpt-browser/bind-server.ts +2 -1
  371. package/src/cli/chatgpt-browser/binding.ts +20 -10
  372. package/src/cli/chatgpt-browser/bridge-extension.ts +75 -0
  373. package/src/cli/chatgpt-browser/bridge-provider.ts +376 -11
  374. package/src/cli/chatgpt-browser/engine.ts +10 -11
  375. package/src/cli/chatgpt-browser/native-provider.ts +24 -83
  376. package/src/cli/chatgpt-browser/oracle-provider.ts +5 -3
  377. package/src/cli/chatgpt-browser/types.ts +1 -0
  378. package/src/cli/commands/bootstrap-control.ts +334 -0
  379. package/src/cli/commands/brain-assistant.ts +52 -0
  380. package/src/cli/commands/brain.ts +191 -40
  381. package/src/cli/commands/chatgpt.ts +32 -67
  382. package/src/cli/commands/computer.ts +437 -0
  383. package/src/cli/commands/doctor.ts +18 -1
  384. package/src/cli/commands/init-hook.ts +71 -61
  385. package/src/cli/commands/init.ts +3 -1
  386. package/src/cli/commands/mcp.ts +16 -10
  387. package/src/cli/commands/plugin.ts +38 -12
  388. package/src/cli/commands/recovery.ts +507 -80
  389. package/src/cli/commands/runtime.ts +12 -7
  390. package/src/cli/commands/setup-profile.ts +97 -39
  391. package/src/cli/commands/status.ts +2 -1
  392. package/src/cli/controller/check-runner.ts +500 -100
  393. package/src/cli/controller/completion-backlog.ts +3 -3
  394. package/src/cli/controller/completion-orchestrator.ts +4 -43
  395. package/src/cli/controller/completion-target.ts +3 -72
  396. package/src/cli/controller/context/source-materializer.ts +81 -100
  397. package/src/cli/controller/context/types.ts +7 -1
  398. package/src/cli/controller/context-pack.ts +28 -6
  399. package/src/cli/controller/execution-completion.ts +4 -7
  400. package/src/cli/controller/execution-policy.ts +36 -153
  401. package/src/cli/controller/governance.ts +2 -3
  402. package/src/cli/controller/issue-store.ts +4 -99
  403. package/src/cli/controller/launch-agents.ts +59 -18
  404. package/src/cli/controller/operational-plan.ts +24 -51
  405. package/src/cli/controller/runtime-config.ts +5 -1
  406. package/src/cli/controller/stuck-state-migration.ts +2 -3
  407. package/src/cli/controller/systemd-user.ts +148 -0
  408. package/src/cli/controller/types.ts +10 -70
  409. package/src/cli/controller/worklog.ts +67 -13
  410. package/src/cli/editing/edit-operation-contract.ts +92 -0
  411. package/src/cli/editing/edit-session.ts +290 -20
  412. package/src/cli/github/plugin.ts +17 -12
  413. package/src/cli/hook/route-registry.ts +3 -5
  414. package/src/cli/hook/runtime.ts +49 -3
  415. package/src/cli/index.ts +3 -0
  416. package/src/cli/local-bridge/connector-freshness.ts +2 -2
  417. package/src/cli/local-bridge/console-automations.ts +20 -15
  418. package/src/cli/local-bridge/console-view-models.ts +3 -12
  419. package/src/cli/local-bridge/facade-api.ts +105 -205
  420. package/src/cli/local-bridge/job-store.ts +1 -1
  421. package/src/cli/local-bridge/server.ts +48 -174
  422. package/src/cli/local-bridge/types.ts +0 -1
  423. package/src/cli/mcp/access-mode.ts +2 -132
  424. package/src/cli/mcp/access-tools.ts +2 -387
  425. package/src/cli/mcp/audit.ts +2 -32
  426. package/src/cli/mcp/auth.ts +2 -404
  427. package/src/cli/mcp/instructions.ts +2 -34
  428. package/src/cli/mcp/legacy-context.ts +2 -16
  429. package/src/cli/mcp/legacy-tool-service.ts +2 -5308
  430. package/src/cli/mcp/multi-repository.ts +2 -436
  431. package/src/cli/mcp/oauth-client-retirement.ts +74 -0
  432. package/src/cli/mcp/oauth.ts +2 -375
  433. package/src/cli/mcp/openai-secure-tunnel.ts +2 -0
  434. package/src/cli/mcp/paths.ts +2 -140
  435. package/src/cli/mcp/policy.ts +2 -232
  436. package/src/cli/mcp/post-finalize-work-attribution.ts +2 -150
  437. package/src/cli/mcp/proxy-env.ts +2 -62
  438. package/src/cli/mcp/readiness-projection.ts +2 -24
  439. package/src/cli/mcp/redaction.ts +2 -21
  440. package/src/cli/mcp/repo.ts +2 -24
  441. package/src/cli/mcp/repository-tools.ts +2 -1613
  442. package/src/cli/mcp/server.ts +2 -951
  443. package/src/cli/mcp/setup.ts +2 -737
  444. package/src/cli/mcp/tool-capability-cache.ts +2 -87
  445. package/src/cli/mcp/tool-contract.ts +2 -14
  446. package/src/cli/mcp/tools.ts +2 -9
  447. package/src/cli/mcp/toolset-names.ts +2 -70
  448. package/src/cli/mcp/toolset-selection.ts +2 -41
  449. package/src/cli/mcp/toolset.ts +2 -336
  450. package/src/cli/mcp/transports/AGENTS.md +1 -10
  451. package/src/cli/mcp/transports/CLAUDE.md +1 -10
  452. package/src/cli/mcp/transports/http.ts +2 -1414
  453. package/src/cli/mcp/transports/session-registry.ts +2 -490
  454. package/src/cli/mcp/transports/stdio.ts +2 -8
  455. package/src/cli/mcp/types.ts +2 -41
  456. package/src/cli/mcp/umbrella-tools.ts +2 -117
  457. package/src/cli/repositories/command-executor.ts +91 -39
  458. package/src/cli/repositories/command-scope.ts +139 -4
  459. package/src/cli/repositories/controller-home.ts +167 -1
  460. package/src/cli/repositories/ephemeral-workspace.ts +20 -30
  461. package/src/cli/repositories/git-command-executor.ts +2 -2
  462. package/src/cli/repositories/identity.ts +13 -0
  463. package/src/cli/repositories/registry.ts +145 -60
  464. package/src/cli/repositories/repository-snapshot.ts +53 -7
  465. package/src/cli/repositories/runtime-storage.ts +27 -2
  466. package/src/cli/repositories/safe-patch.ts +34 -38
  467. package/src/cli/repositories/selected-path-actions.ts +22 -2
  468. package/src/cli/repositories/structured-git.ts +167 -27
  469. package/src/cli/repository/session-cache.ts +92 -6
  470. package/src/cli/runtime/helper-runner.ts +7 -0
  471. package/src/cli/runtime-invocation.ts +8 -1
  472. package/src/cli/tools/codegraph.ts +44 -25
  473. package/src/core/adoption/manifest-templates.ts +1 -1
  474. package/src/core/adoption/plan.ts +3 -26
  475. package/src/core/adoption/workflow-contract-plan.ts +17 -9
  476. package/src/effects/process-runner.ts +8 -14
  477. package/src/runtime/context/assistant-context.ts +167 -0
  478. package/src/runtime/context/assistant-work-context.ts +209 -0
  479. package/src/runtime/context/automatic-learning.ts +565 -0
  480. package/src/runtime/context/codegraph-cache-boundary.ts +255 -0
  481. package/src/runtime/context/codegraph-read-provider.ts +55 -22
  482. package/src/runtime/context/codegraph-sidecar.cjs +8 -1
  483. package/src/runtime/context/cognitive-attention.ts +173 -0
  484. package/src/runtime/context/cognitive-skill-canary.ts +158 -0
  485. package/src/runtime/context/context-closure.ts +305 -0
  486. package/src/runtime/context/context-pack-process.ts +103 -0
  487. package/src/runtime/context/context-plane.ts +203 -0
  488. package/src/runtime/context/direct-controller-learning.ts +298 -0
  489. package/src/runtime/context/project-engineering-contract.ts +60 -0
  490. package/src/runtime/context/semantic-navigation-contract.ts +9 -0
  491. package/src/runtime/context/semantic-navigation.ts +6 -34
  492. package/src/runtime/context/typescript-navigation-process.ts +145 -0
  493. package/src/runtime/context/typescript-navigation.ts +89 -3
  494. package/src/runtime/control-plane/bootstrap/capability-provider.ts +74 -0
  495. package/src/runtime/control-plane/bootstrap/control-api.ts +57 -0
  496. package/src/runtime/control-plane/bootstrap/index.ts +5 -0
  497. package/src/runtime/control-plane/bootstrap/state-machine.ts +141 -0
  498. package/src/runtime/control-plane/bootstrap/store.ts +21 -0
  499. package/src/runtime/control-plane/bootstrap/types.ts +87 -0
  500. package/src/runtime/control-plane/cleanup-artifact-retention.ts +531 -0
  501. package/src/runtime/control-plane/codegraph-cache-retention.ts +164 -0
  502. package/src/runtime/control-plane/concurrency/work-execution-concurrency.ts +282 -0
  503. package/src/runtime/control-plane/execution/controller-authority-recovery.ts +380 -0
  504. package/src/runtime/control-plane/execution/edit-validation-coordinator.ts +113 -16
  505. package/src/runtime/control-plane/execution/execution-identity.ts +23 -3
  506. package/src/runtime/control-plane/execution/implementation-review-content.ts +95 -0
  507. package/src/runtime/control-plane/execution/repository-work-attribution.ts +7 -30
  508. package/src/runtime/control-plane/execution/retained-work-resume.ts +439 -102
  509. package/src/runtime/control-plane/execution/session-store.ts +31 -1
  510. package/src/runtime/control-plane/execution/validation.ts +34 -11
  511. package/src/runtime/control-plane/execution/work-authority-reconciler.ts +87 -0
  512. package/src/runtime/control-plane/execution/work-check-evidence.ts +137 -0
  513. package/src/runtime/control-plane/execution/work-completion-authority.ts +31 -44
  514. package/src/runtime/control-plane/execution/work-delivery-service.ts +497 -0
  515. package/src/runtime/control-plane/execution/work-evidence-policy.ts +46 -53
  516. package/src/runtime/control-plane/execution/work-execution-support.ts +85 -164
  517. package/src/runtime/control-plane/execution/work-handle-authority.ts +349 -73
  518. package/src/runtime/control-plane/execution/work-handle-store.ts +55 -2
  519. package/src/runtime/control-plane/execution/work-head-settlement.ts +108 -0
  520. package/src/runtime/control-plane/execution/work-lifecycle-audit.ts +173 -28
  521. package/src/runtime/control-plane/execution/work-operation-service.ts +92 -40
  522. package/src/runtime/control-plane/execution/work-preparation-service.ts +145 -269
  523. package/src/runtime/control-plane/execution/work-remote-delivery.ts +2 -3
  524. package/src/runtime/control-plane/execution/work-revision-diff.ts +39 -0
  525. package/src/runtime/control-plane/execution/work-terminal-cleanup.ts +543 -225
  526. package/src/runtime/control-plane/execution/work-validation-reconciler.ts +59 -45
  527. package/src/runtime/control-plane/execution/work-verification-context.ts +1 -1
  528. package/src/runtime/control-plane/execution/work-verification-service.ts +662 -52
  529. package/src/runtime/control-plane/execution/work-verification-snapshot.ts +205 -16
  530. package/src/runtime/control-plane/facade/capability-registry.ts +380 -44
  531. package/src/runtime/control-plane/facade/check-normalization.ts +3 -9
  532. package/src/runtime/control-plane/facade/codex-delegation.ts +10 -11
  533. package/src/runtime/control-plane/facade/controller-connection.ts +135 -0
  534. package/src/runtime/control-plane/facade/controller-session-store.ts +2 -488
  535. package/src/runtime/control-plane/facade/goal-workloop-access.ts +6 -22
  536. package/src/runtime/control-plane/facade/goal-workloop.ts +565 -1202
  537. package/src/runtime/control-plane/facade/handoff-inbox-application.ts +145 -0
  538. package/src/runtime/control-plane/facade/handoff-inbox-store.ts +266 -52
  539. package/src/runtime/control-plane/facade/index.ts +4 -3
  540. package/src/runtime/control-plane/facade/operation-digest.ts +34 -73
  541. package/src/runtime/control-plane/facade/plan-contract-store.ts +671 -245
  542. package/src/runtime/control-plane/facade/policy-gate.ts +0 -23
  543. package/src/runtime/control-plane/facade/repository-work-admission.ts +31 -23
  544. package/src/runtime/control-plane/facade/requirement-authority.ts +121 -0
  545. package/src/runtime/control-plane/facade/requirement-board.ts +9 -4
  546. package/src/runtime/control-plane/facade/rh-work-operation-contract.ts +85 -0
  547. package/src/runtime/control-plane/facade/self-healing-loop.ts +18 -53
  548. package/src/runtime/control-plane/facade/semantic-admission.ts +8 -16
  549. package/src/runtime/control-plane/facade/suggested-actions.ts +15 -15
  550. package/src/runtime/control-plane/facade/types.ts +218 -620
  551. package/src/runtime/control-plane/facade/work-continuation.ts +8 -8
  552. package/src/runtime/control-plane/facade/work-contract-store.ts +2 -1043
  553. package/src/runtime/control-plane/generated-cache-retention.ts +336 -19
  554. package/src/runtime/control-plane/global-scheduler/autonomous-continuation.ts +248 -0
  555. package/src/runtime/control-plane/global-scheduler/durable-admission.ts +13 -2
  556. package/src/runtime/control-plane/global-scheduler/maintenance.ts +274 -84
  557. package/src/runtime/control-plane/global-scheduler/periodic-cleanup-entry.ts +55 -0
  558. package/src/runtime/control-plane/global-scheduler/periodic-cleanup-process.ts +98 -0
  559. package/src/runtime/control-plane/global-scheduler/reconciliation.ts +3 -2
  560. package/src/runtime/control-plane/global-scheduler/scheduler-worker-entry.ts +10 -0
  561. package/src/runtime/control-plane/global-scheduler/scheduler.ts +227 -109
  562. package/src/runtime/control-plane/global-scheduler/wake-signal.ts +42 -2
  563. package/src/runtime/control-plane/global-scheduler/worker-launch.ts +18 -6
  564. package/src/runtime/control-plane/governance/access-policy.ts +19 -2
  565. package/src/runtime/control-plane/governance/authorization.ts +20 -3
  566. package/src/runtime/control-plane/launcher/chatgpt-round-continuation.ts +160 -0
  567. package/src/runtime/control-plane/launcher/chatgpt-work-binding-store.ts +2 -177
  568. package/src/runtime/control-plane/launcher/chatgpt-work-continuation.ts +139 -670
  569. package/src/runtime/control-plane/launcher/local-conversation-controller.ts +238 -0
  570. package/src/runtime/control-plane/launcher/provider-mcp-bootstrap.ts +25 -6
  571. package/src/runtime/control-plane/launcher/thin-launcher.ts +96 -194
  572. package/src/runtime/control-plane/lifecycle-retention-metrics.ts +60 -0
  573. package/src/runtime/control-plane/persistence/cognition-store.ts +820 -0
  574. package/src/runtime/control-plane/persistence/experience-store.ts +302 -0
  575. package/src/runtime/control-plane/persistence/operational-prior-store.ts +348 -0
  576. package/src/runtime/control-plane/persistence/requirement-store.ts +230 -80
  577. package/src/runtime/control-plane/persistence/sqlite-store.ts +654 -78
  578. package/src/runtime/control-plane/persistence/workflow-content-store.ts +98 -0
  579. package/src/runtime/control-plane/persistence/workflow-registry-store.ts +186 -0
  580. package/src/runtime/control-plane/persistence/workflow-run-store.ts +123 -0
  581. package/src/runtime/control-plane/release-retention.ts +154 -26
  582. package/src/runtime/control-plane/repository-namespace-retention.ts +208 -0
  583. package/src/runtime/control-plane/runtime-cleanup.ts +844 -38
  584. package/src/runtime/control-plane/runtime-generation.ts +6 -0
  585. package/src/runtime/control-plane/workspace/project-onboarding.ts +80 -0
  586. package/src/runtime/control-plane/workspace/semantic-sync-service.ts +479 -0
  587. package/src/runtime/control-plane/workspace/workspace-store.ts +249 -0
  588. package/src/runtime/diagnostics/incident-repair.ts +573 -0
  589. package/src/runtime/diagnostics/mcp-timing.ts +239 -6
  590. package/src/runtime/diagnostics/performance.ts +6 -14
  591. package/src/runtime/diagnostics/read-only-tool.ts +1 -1
  592. package/src/runtime/evidence/artifact-store.ts +216 -35
  593. package/src/runtime/evidence/evidence-store.ts +112 -8
  594. package/src/runtime/evidence/operational-shadow.ts +38 -0
  595. package/src/runtime/evidence/output-handle-index.ts +225 -0
  596. package/src/runtime/evidence/process-check-receipt.ts +5 -43
  597. package/src/runtime/evidence/result-store.ts +158 -44
  598. package/src/runtime/evidence/sensitive-output.ts +4 -4
  599. package/src/runtime/execution/jobs/receipt-recovery.ts +1 -1
  600. package/src/runtime/execution/jobs/store.ts +124 -6
  601. package/src/runtime/execution/managed-workspace.ts +112 -5
  602. package/src/runtime/execution/process-runtime/canary.ts +19 -5
  603. package/src/runtime/execution/process-runtime/check-classification.ts +48 -0
  604. package/src/runtime/execution/process-runtime/check-facade.ts +24 -10
  605. package/src/runtime/execution/process-runtime/check-receipt.ts +1 -1
  606. package/src/runtime/execution/process-runtime/check-result-retention.ts +132 -0
  607. package/src/runtime/execution/process-runtime/check-result.ts +177 -2
  608. package/src/runtime/execution/process-runtime/check-runner-sidecar.ts +58 -9
  609. package/src/runtime/execution/process-runtime/check-storage.ts +187 -0
  610. package/src/runtime/execution/process-runtime/command-facade.ts +117 -114
  611. package/src/runtime/execution/process-runtime/gc.ts +15 -2
  612. package/src/runtime/execution/process-runtime/handle-index.ts +176 -0
  613. package/src/runtime/execution/process-runtime/host-command-lane.ts +139 -0
  614. package/src/runtime/execution/process-runtime/index.ts +4 -0
  615. package/src/runtime/execution/process-runtime/interactive-admission.ts +2 -1
  616. package/src/runtime/execution/process-runtime/lightweight-managed.ts +283 -73
  617. package/src/runtime/execution/process-runtime/persisted-check.ts +130 -23
  618. package/src/runtime/execution/process-runtime/process-runner-entry.ts +47 -5
  619. package/src/runtime/execution/process-runtime/process-scope.ts +160 -0
  620. package/src/runtime/execution/process-runtime/resource-claims.ts +125 -64
  621. package/src/runtime/execution/process-runtime/runtime.ts +167 -17
  622. package/src/runtime/execution/process-runtime/store.ts +30 -2
  623. package/src/runtime/execution/process-runtime/types.ts +27 -0
  624. package/src/runtime/execution/workers/executor.ts +18 -19
  625. package/src/runtime/execution/workers/worker-entry.ts +1 -1
  626. package/src/runtime/gateway/mcp/execution-tools.ts +2 -207
  627. package/src/runtime/gateway/mcp/legacy-ios-tool-adapter.ts +2 -61
  628. package/src/runtime/gateway/mcp/persisted-check-process.ts +2 -3
  629. package/src/runtime/gateway/mcp/process-tools.ts +2 -289
  630. package/src/runtime/gateway/mcp/router.ts +2 -1125
  631. package/src/runtime/gateway/mcp/runtime-tool-definitions.ts +2 -565
  632. package/src/runtime/gateway/mcp/runtime-tools.ts +2 -6655
  633. package/src/runtime/gateway/mcp/work-validation-reconciler.ts +2 -1
  634. package/src/runtime/maintenance/cleanup.ts +38 -24
  635. package/src/runtime/platform/browser-product-discovery.ts +174 -0
  636. package/src/runtime/platform/computer-platform.ts +14 -0
  637. package/src/runtime/platform/executable-discovery.ts +54 -0
  638. package/src/runtime/platform/fetch-http-server.ts +90 -0
  639. package/src/runtime/platform/service-inventory.ts +130 -0
  640. package/src/runtime/platform/service-manager.ts +146 -0
  641. package/src/runtime/platform/windows-host-discovery.ts +118 -0
  642. package/src/runtime/platform/windows-recovery-deployment.ts +67 -0
  643. package/src/runtime/plugins/action-application.ts +192 -0
  644. package/src/runtime/plugins/app-store-connect-adapter.ts +47 -35
  645. package/src/runtime/plugins/browser-adapter.ts +898 -135
  646. package/src/runtime/plugins/browser-automation-service.ts +33 -34
  647. package/src/runtime/plugins/browser-macos-bridge.ts +386 -46
  648. package/src/runtime/plugins/browser-manifest-surface.ts +75 -17
  649. package/src/runtime/plugins/browser-native-session-service.ts +64 -14
  650. package/src/runtime/plugins/browser-provider-registry.ts +2 -109
  651. package/src/runtime/plugins/browser-registration.ts +32 -0
  652. package/src/runtime/plugins/browser-runtime-contract.ts +2 -154
  653. package/src/runtime/plugins/browser-runtime.ts +55 -10
  654. package/src/runtime/plugins/browser-session-authority.ts +101 -291
  655. package/src/runtime/plugins/browser-session-legacy-migration.ts +203 -0
  656. package/src/runtime/plugins/browser-session-store.ts +243 -80
  657. package/src/runtime/plugins/browser-session-types.ts +2 -98
  658. package/src/runtime/plugins/capability-authorization-grants.ts +272 -59
  659. package/src/runtime/plugins/catalog-trust.ts +82 -0
  660. package/src/runtime/plugins/computer-chatgpt-browser-adapter-installer.ts +219 -0
  661. package/src/runtime/plugins/computer-chatgpt-macos-target.ts +891 -0
  662. package/src/runtime/plugins/computer-registration.ts +1050 -0
  663. package/src/runtime/plugins/config-store.ts +119 -0
  664. package/src/runtime/plugins/desktop-operator-external-policy.ts +964 -0
  665. package/src/runtime/plugins/desktop-operator-registration.ts +123 -12
  666. package/src/runtime/plugins/errors.ts +8 -1
  667. package/src/runtime/plugins/external-adapter.ts +82 -323
  668. package/src/runtime/plugins/external-provider-policy.ts +48 -0
  669. package/src/runtime/plugins/external-registration.ts +30 -2
  670. package/src/runtime/plugins/external-unix-socket-probe.cjs +9 -3
  671. package/src/runtime/plugins/external-unix-socket.ts +64 -193
  672. package/src/runtime/plugins/first-party-external-registration.ts +163 -0
  673. package/src/runtime/plugins/first-party-registry.ts +3 -1
  674. package/src/runtime/plugins/github-adapter.ts +1 -2
  675. package/src/runtime/plugins/gmail-adapter.ts +29 -8
  676. package/src/runtime/plugins/google-calendar-adapter.ts +8 -8
  677. package/src/runtime/plugins/google-shared.ts +45 -53
  678. package/src/runtime/plugins/google-tasks-adapter.ts +8 -8
  679. package/src/runtime/plugins/ios-adapter.ts +2 -3
  680. package/src/runtime/plugins/lightweight-action.ts +208 -2
  681. package/src/runtime/plugins/local-system-adapter.ts +192 -2
  682. package/src/runtime/plugins/macos-capability-broker.ts +15 -105
  683. package/src/runtime/plugins/managed-process-adapter.ts +12 -5
  684. package/src/runtime/plugins/plugin-action-sidecar.ts +17 -13
  685. package/src/runtime/plugins/plugin-management-adapter.ts +1 -1
  686. package/src/runtime/plugins/resend-adapter.ts +15 -24
  687. package/src/runtime/plugins/store.ts +1003 -387
  688. package/src/runtime/plugins/types.ts +28 -1
  689. package/src/runtime/plugins/uu-remote-rescue-registration.ts +155 -0
  690. package/src/runtime/plugins/windows-host-recovery-install.ts +68 -0
  691. package/src/runtime/plugins/windows-host-recovery-registration.ts +85 -0
  692. package/src/runtime/plugins/xiaohongshu-publish.ts +102 -430
  693. package/src/runtime/projections/controller-context.ts +12 -6
  694. package/src/runtime/projections/git-status-sampler.ts +73 -22
  695. package/src/runtime/projections/invalidation.ts +7 -3
  696. package/src/runtime/projections/materialized-view.ts +93 -43
  697. package/src/runtime/recovery/actions.ts +3 -3
  698. package/src/runtime/recovery/capability-action-application.ts +229 -0
  699. package/src/runtime/recovery/index.ts +3 -0
  700. package/src/runtime/recovery/lifecycle-inventory.ts +338 -0
  701. package/src/runtime/recovery/local-jobs-repair.ts +14 -14
  702. package/src/runtime/recovery/maintenance-executor.ts +701 -168
  703. package/src/runtime/recovery/quarantine-retention.ts +256 -0
  704. package/src/runtime/recovery/store.ts +29 -11
  705. package/src/runtime/release/identity.ts +6 -0
  706. package/src/runtime/release/release-coordinator.ts +296 -0
  707. package/src/runtime/release/release-session.ts +716 -0
  708. package/src/runtime/release/release-state-migration.ts +25 -0
  709. package/src/runtime/resources/leases/store.ts +56 -25
  710. package/src/runtime/root/active-execution-power-assertion.ts +139 -0
  711. package/src/runtime/root/assistant-learning-loop.ts +45 -0
  712. package/src/runtime/root/browser-session-composition.ts +59 -0
  713. package/src/runtime/root/computer-composition.ts +376 -0
  714. package/src/runtime/root/computer-target-composition.ts +16 -0
  715. package/src/runtime/root/computer-target-persistence.ts +39 -0
  716. package/src/runtime/root/controller-progression-composition.ts +192 -0
  717. package/src/runtime/root/controller-round-composition.ts +126 -0
  718. package/src/runtime/root/controller-services.ts +2 -0
  719. package/src/runtime/root/deployment-topology.ts +106 -0
  720. package/src/runtime/root/entry.ts +8 -6
  721. package/src/runtime/root/gateway-adapter.ts +3 -3
  722. package/src/runtime/root/known-good-recovery.ts +184 -0
  723. package/src/runtime/root/local-bridge.ts +5 -3
  724. package/src/runtime/root/mcp-transport.ts +116 -23
  725. package/src/runtime/root/ownership.ts +261 -9
  726. package/src/runtime/root/package-connector-service.ts +212 -74
  727. package/src/runtime/root/package-runtime-release.ts +199 -33
  728. package/src/runtime/root/package-runtime-service.ts +77 -108
  729. package/src/runtime/root/release-execution-canary.ts +103 -0
  730. package/src/runtime/root/release-loader.ts +150 -0
  731. package/src/runtime/root/release-manifest.ts +185 -7
  732. package/src/runtime/root/release-materialize.ts +474 -31
  733. package/src/runtime/root/release-store.ts +425 -37
  734. package/src/runtime/root/runtime-lane.ts +191 -0
  735. package/src/runtime/root/runtime.ts +379 -32
  736. package/src/runtime/root/scheduled-controller-composition.ts +76 -0
  737. package/src/runtime/root/scheduler.ts +12 -4
  738. package/src/runtime/root/service-runner.ts +3 -3
  739. package/src/runtime/root/service.ts +73 -45
  740. package/src/runtime/root/status.ts +49 -0
  741. package/src/runtime/root/types.ts +55 -3
  742. package/src/runtime/root/workflow-supervisor-composition.ts +493 -0
  743. package/src/runtime/root/workflow-supervisor-runtime.ts +209 -0
  744. package/src/runtime/root/write-fence.ts +50 -2
  745. package/src/runtime/safe-tooling/google-credential-store.ts +76 -21
  746. package/src/runtime/safe-tooling/google-oauth-broker.ts +25 -7
  747. package/src/runtime/safe-tooling/workspace-auth.ts +1 -1
  748. package/src/runtime/shared/bounded-child-supervisor.ts +9 -1
  749. package/src/runtime/shared/local-bridge-surface.ts +1 -1
  750. package/src/runtime/shared/process-environment.ts +36 -10
  751. package/src/runtime/shared/response-budget.ts +1 -3
  752. package/src/runtime/shared/storage-capacity.ts +68 -0
  753. package/src/runtime/standalone-recovery/controller-home-migration.ts +1108 -0
  754. package/src/runtime/standalone-recovery/core.ts +4609 -495
  755. package/src/runtime/standalone-recovery/entry.ts +642 -81
  756. package/src/runtime/standalone-recovery/independent-host-rescue.ts +172 -0
  757. package/src/runtime/standalone-recovery/installer.ts +399 -177
  758. package/src/runtime/standalone-recovery/mcp-server.ts +79 -0
  759. package/src/runtime/standalone-recovery/mutation-identity-contract.ts +21 -0
  760. package/src/runtime/standalone-recovery/operation-lock.ts +160 -0
  761. package/src/runtime/standalone-recovery/performance.ts +173 -0
  762. package/src/runtime/standalone-recovery/release.ts +58 -5
  763. package/src/runtime/standalone-recovery/service-labels.ts +5 -2
  764. package/src/runtime/standalone-recovery/watchdog-heartbeat.ts +5 -2
  765. package/src/runtime/watchdog/workflow-watchdog.ts +1 -1
  766. package/src/runtime/workflow/schedules/browser-probe.ts +17 -6
  767. package/src/runtime/workflow/schedules/chatgpt-automation-migration.ts +11 -4
  768. package/src/runtime/workflow/schedules/engine.ts +298 -484
  769. package/src/runtime/workflow/schedules/pending-activation.ts +1 -1
  770. package/src/runtime/workflow/schedules/settlement.ts +2 -191
  771. package/src/runtime/workflow/schedules/store.ts +2 -607
  772. package/src/runtime/workflow/schedules/types.ts +2 -127
  773. package/src/runtime/workflow/schedules/work-continuation.ts +220 -16
  774. package/src/runtime/workflows/first-party/xiaohongshu.ts +122 -0
  775. package/src/runtime/workflows/runtime.ts +482 -0
  776. package/src/testing/test-governance.ts +95 -30
  777. package/supervisor/chatgpt-conversation.ts +23 -0
  778. package/supervisor/client.ts +201 -0
  779. package/supervisor/control-plane.ts +868 -0
  780. package/supervisor/entry.ts +15 -0
  781. package/supervisor/forge-validators.ts +80 -0
  782. package/supervisor/index.ts +5 -0
  783. package/supervisor/native-browser-adapter.ts +786 -0
  784. package/supervisor/native-messaging/host.ts +39 -0
  785. package/supervisor/native-messaging/manifest.ts +26 -0
  786. package/supervisor/native-messaging/protocol.ts +27 -0
  787. package/supervisor/paths.ts +18 -0
  788. package/supervisor/protocol.ts +202 -0
  789. package/supervisor/server.ts +404 -0
  790. package/supervisor/store.ts +1451 -0
  791. package/supervisor/tsconfig.json +8 -0
  792. package/supervisor/types.ts +255 -0
  793. package/assets/templates/helpers/archive-architecture-request.sh +0 -244
  794. package/docs/architecture/history/README.md +0 -7
  795. package/docs/architecture/history/chatgpt-handoff-facade.md +0 -397
  796. package/docs/architecture/history/global-hook-runtime.md +0 -166
  797. package/docs/architecture/history/ios-semantic-automation-provider-v2.md +0 -170
  798. package/docs/architecture/requests/archive/2026/20260528-154740-ai-hooks-ai-hooks-hook-input-sh.md +0 -59
  799. package/docs/architecture/requests/archive/2026/20260528-154816-assets-hooks-assets-hooks-hook-input-sh.md +0 -59
  800. package/docs/architecture/requests/archive/2026/20260528-161851-ai-harness-workflow-contract-json-ai-harness-workflow-contract-json.md +0 -59
  801. package/docs/architecture/requests/archive/2026/20260528-161853-scripts-check-task-workflow-sh-scripts-check-task-workflow-sh.md +0 -59
  802. package/docs/architecture/requests/archive/2026/20260528-161911-assets-workflow-contract-v1-json-assets-workflow-contract-v1-json.md +0 -59
  803. package/docs/architecture/requests/archive/2026/20260528-222416-ai-hooks-ai-hooks-hook-input-sh.md +0 -59
  804. package/docs/architecture/requests/archive/2026/20260528-222444-ai-hooks-ai-hooks-pre-edit-guard-sh.md +0 -59
  805. package/docs/architecture/requests/archive/2026/20260528-222457-ai-hooks-ai-hooks-pre-edit-guard-sh.md +0 -59
  806. package/docs/architecture/requests/archive/2026/20260528-222648-ai-hooks-ai-hooks-pre-edit-guard-sh.md +0 -59
  807. package/docs/architecture/requests/archive/2026/20260528-222705-ai-hooks-ai-hooks-worktree-guard-sh.md +0 -59
  808. package/docs/architecture/requests/archive/2026/20260528-222726-ai-hooks-ai-hooks-prompt-guard-sh.md +0 -59
  809. package/docs/architecture/requests/archive/2026/20260528-222727-ai-hooks-ai-hooks-prompt-guard-sh.md +0 -59
  810. package/docs/architecture/requests/archive/2026/20260528-224736-ai-hooks-ai-hooks-hook-input-sh.md +0 -59
  811. package/docs/architecture/requests/archive/2026/20260528-233259-ai-hooks-ai-hooks-prompt-guard-sh.md +0 -59
  812. package/docs/architecture/requests/archive/2026/20260528-233335-assets-hooks-assets-hooks-prompt-guard-sh.md +0 -59
  813. package/docs/architecture/requests/archive/2026/20260528-233456-ai-hooks-ai-hooks-prompt-guard-sh.md +0 -59
  814. package/docs/architecture/requests/archive/2026/20260528-233457-assets-hooks-assets-hooks-prompt-guard-sh.md +0 -59
  815. package/docs/architecture/requests/archive/2026/20260528-233637-ai-hooks-ai-hooks-prompt-guard-sh.md +0 -59
  816. package/docs/architecture/requests/archive/2026/20260528-233638-assets-hooks-assets-hooks-prompt-guard-sh.md +0 -59
  817. package/docs/architecture/requests/archive/2026/20260529-000322-root-package-json.md +0 -59
  818. package/docs/architecture/requests/archive/2026/20260529-004238-ai-hooks-ai-hooks-lib-workflow-state-sh.md +0 -59
  819. package/docs/architecture/requests/archive/2026/20260529-020654-ai-harness-policy-json-ai-harness-policy-json.md +0 -63
  820. package/docs/architecture/requests/archive/2026/20260529-094236-ai-hooks-ai-hooks-prompt-guard-sh.md +0 -60
  821. package/docs/architecture/requests/archive/2026/20260529-094323-assets-hooks-assets-hooks-prompt-guard-sh.md +0 -60
  822. package/docs/architecture/requests/archive/2026/20260529-094331-ai-hooks-ai-hooks-prompt-guard-sh.md +0 -60
  823. package/docs/architecture/requests/archive/2026/20260529-094339-assets-hooks-assets-hooks-prompt-guard-sh.md +0 -60
  824. package/docs/architecture/requests/archive/2026/20260529-094430-assets-hooks-assets-hooks-session-start-context-sh.md +0 -60
  825. package/docs/architecture/requests/archive/2026/20260529-094446-ai-hooks-ai-hooks-session-start-context-sh.md +0 -60
  826. package/docs/architecture/requests/archive/2026/20260613-002040-runtime-harness-hook-adapters.md +0 -68
  827. package/docs/architecture/requests/archive/2026/root.md +0 -68
  828. package/docs/architecture/requests/archive/2026/runtime-harness-hook-adapters.md +0 -76
  829. package/docs/architecture/requests/archive/2026/verification-evals-checks.md +0 -68
  830. package/docs/architecture/requests/archive/2026/workflow-engine-contract-assets.md +0 -69
  831. package/scripts/archive-architecture-request.sh +0 -4
  832. package/scripts/benchmark-background-check-overlap.ts +0 -228
  833. package/scripts/benchmark-controller-hotpath.ts +0 -212
  834. package/scripts/benchmark-controller-round2.ts +0 -139
  835. package/scripts/benchmark-ios-agent-device.ts +0 -514
  836. package/scripts/benchmark-mcp-host.sh +0 -117
  837. package/scripts/benchmark-mcp-transport.ts +0 -170
  838. package/scripts/benchmark-quality-harness.ts +0 -146
  839. package/scripts/benchmark-route-session-concurrency.ts +0 -915
  840. package/scripts/benchmark-thin-harness-gateway-ab.ts +0 -632
  841. package/scripts/benchmark-thin-harness-mcp-e2e.ts +0 -498
  842. package/scripts/benchmark-thin-harness.ts +0 -251
  843. package/scripts/benchmark-typescript-navigation.ts +0 -186
  844. package/scripts/benchmark-work-efficiency.ts +0 -334
  845. package/scripts/build-controller-ui.ts +0 -28
  846. package/scripts/check-npm-release.sh +0 -32
  847. package/scripts/check-public-release-surface.sh +0 -19
  848. package/scripts/check-release-published.sh +0 -57
  849. package/scripts/check-release-readiness.sh +0 -37
  850. package/scripts/check-release-version.mjs +0 -74
  851. package/scripts/check-tarball-install-smoke.sh +0 -67
  852. package/scripts/package-source-archive.sh +0 -147
  853. package/scripts/public-release-files.txt +0 -39
  854. package/scripts/public-release.ts +0 -174
  855. package/scripts/publish-release-tarball.sh +0 -27
  856. package/scripts/route-nl-vs-ts-eval.ts +0 -679
  857. package/scripts/run-skill-evals.ts +0 -1022
  858. package/scripts/stage-runtime-release.ts +0 -39
  859. package/src/cli/controller/progress.ts +0 -656
  860. package/src/cli/controller/work-mode.ts +0 -181
  861. package/src/cli/local-bridge/console-assets.ts +0 -17
  862. package/src/cli/local-bridge/dashboard.ts +0 -17
  863. package/src/cli/local-bridge/frontend/src/App.tsx +0 -10
  864. package/src/cli/local-bridge/frontend/src/components/Button.tsx +0 -1
  865. package/src/cli/local-bridge/frontend/src/components/DetailPane.tsx +0 -3
  866. package/src/cli/local-bridge/frontend/src/components/SearchField.tsx +0 -1
  867. package/src/cli/local-bridge/frontend/src/components/SectionHeader.tsx +0 -1
  868. package/src/cli/local-bridge/frontend/src/components/Segmented.tsx +0 -1
  869. package/src/cli/local-bridge/frontend/src/components/StatusText.tsx +0 -3
  870. package/src/cli/local-bridge/frontend/src/design/icons.tsx +0 -11
  871. package/src/cli/local-bridge/frontend/src/design/tokens.css +0 -8
  872. package/src/cli/local-bridge/frontend/src/features/automations/AutomationsView.tsx +0 -153
  873. package/src/cli/local-bridge/frontend/src/features/capabilities/CapabilitiesView.tsx +0 -37
  874. package/src/cli/local-bridge/frontend/src/features/overview/OverviewView.tsx +0 -183
  875. package/src/cli/local-bridge/frontend/src/features/repositories/RepositoriesView.tsx +0 -2
  876. package/src/cli/local-bridge/frontend/src/features/system/SystemView.tsx +0 -2
  877. package/src/cli/local-bridge/frontend/src/features/work/WorkView.tsx +0 -4
  878. package/src/cli/local-bridge/frontend/src/lib/api.ts +0 -30
  879. package/src/cli/local-bridge/frontend/src/lib/format.ts +0 -4
  880. package/src/cli/local-bridge/frontend/src/lib/routes.ts +0 -7
  881. package/src/cli/local-bridge/frontend/src/main.tsx +0 -1
  882. package/src/cli/local-bridge/frontend/src/shell/AppShell.tsx +0 -1
  883. package/src/cli/local-bridge/frontend/src/shell/CommandBar.tsx +0 -2
  884. package/src/cli/local-bridge/frontend/src/shell/Sidebar.tsx +0 -4
  885. package/src/cli/local-bridge/frontend/src/styles.css +0 -28
  886. package/src/cli/local-bridge/frontend/src/types.ts +0 -15
  887. package/src/cli/local-bridge/frontend/src/vite-env.d.ts +0 -1
  888. package/src/cli/local-bridge/frontend/vite.config.ts +0 -27
  889. package/src/cli/local-bridge/ui-dist/app.css +0 -1
  890. package/src/cli/local-bridge/ui-dist/app.js +0 -11228
  891. package/src/runtime/control-plane/execution/direct-edit-work-completion.ts +0 -385
  892. package/src/runtime/control-plane/execution/work-finalization-service.ts +0 -1913
  893. package/src/runtime/control-plane/execution/work-path-scope.ts +0 -37
  894. package/src/runtime/control-plane/execution/work-task-receipt.ts +0 -449
  895. package/src/runtime/control-plane/facade/controller-round-relay.ts +0 -1118
  896. package/src/runtime/control-plane/facade/work-admission-policy.ts +0 -93
  897. package/src/runtime/control-plane/facade/work-task-projection.ts +0 -66
  898. package/src/runtime/control-plane/routing/index.ts +0 -1
  899. package/src/runtime/control-plane/routing/route-policy.ts +0 -382
  900. package/src/runtime/control-plane/routing/workspace-admission.ts +0 -70
@@ -0,0 +1,804 @@
1
+ import { createHash, randomUUID, timingSafeEqual } from 'crypto';
2
+ import { join } from 'path';
3
+ import { FORGE_INSTANCE_SCOPE_KEY, repositoryControllerRoot } from '../../../../src/cli/repositories/controller-home';
4
+ import { withControllerLock } from '../../../../src/cli/repositories/locks';
5
+ import {
6
+ peekExecutionSession,
7
+ peekExecutionSessionWithinTransaction,
8
+ } from '../../../../src/runtime/control-plane/execution/session-store';
9
+ import { readJsonFile } from '../../../../src/runtime/shared/json-files';
10
+ import {
11
+ readControlPlaneRecord,
12
+ readControlPlaneRecordWithinTransaction,
13
+ writeControlPlaneRecord,
14
+ writeControlPlaneRecordWithinTransaction,
15
+ type SqliteDatabase,
16
+ } from '../../../../src/runtime/control-plane/persistence/sqlite-store';
17
+ import { type ControllerSession, type ControllerSessionStore, type ControllerType } from '../domain/types';
18
+ import { getWorkContract, semanticWorkState } from '../../work/api/index';
19
+
20
+ export interface ControllerSessionStoreOptions {
21
+ controllerHome: string;
22
+ /** Legacy repository provenance/migration hint only; canonical ControllerSession state is ForgeInstance-scoped. */
23
+ repoId: string;
24
+ now?: () => string;
25
+ }
26
+
27
+ const SESSION_STORE_NAMESPACE = 'controller_session_claim_store';
28
+ const SESSION_STORE_KEY = 'index';
29
+ const SESSION_STORE_SCHEMA_VERSION = 1;
30
+
31
+ function assertControllerWorkClaimable(options: ControllerSessionStoreOptions, workId: string): void {
32
+ const work = getWorkContract({ controllerHome: options.controllerHome, repoId: options.repoId }, workId);
33
+ if (!work) return;
34
+ const state = semanticWorkState(work);
35
+ if (state !== 'open') throw new Error(`WORK_CONTROLLER_CLAIM_TERMINAL: ${workId}:${state}`);
36
+ }
37
+
38
+ export type ClaimedControllerSession = ControllerSession & { claimGeneration: number };
39
+
40
+ export interface ControllerSessionClaimInput {
41
+ workId: string;
42
+ controllerId: string;
43
+ controllerType: ControllerType;
44
+ sessionId: string;
45
+ /** Optional digest of the Work-bound controller capability. Plaintext is never persisted in ControllerSession. */
46
+ authorityDigest?: string;
47
+ principalId?: string;
48
+ controllerInstanceId?: string;
49
+ /** Optional compare-and-swap fence supplied by a recovering caller. */
50
+ expectedClaimGeneration?: number;
51
+ /**
52
+ * Permit a different authenticated controller epoch to recover this Work only
53
+ * after the canonical execution/activity grace has elapsed. Callers must pair
54
+ * this with expectedClaimGeneration from the owner they observed.
55
+ */
56
+ allowStaleRecovery?: boolean;
57
+ leaseMs?: number;
58
+ }
59
+
60
+ function path(options: ControllerSessionStoreOptions): string {
61
+ return join(repositoryControllerRoot(options.controllerHome, options.repoId), 'controller-sessions.json');
62
+ }
63
+
64
+ function now(options: ControllerSessionStoreOptions): string { return options.now?.() ?? new Date().toISOString(); }
65
+
66
+ function legacyStore(options: ControllerSessionStoreOptions): ControllerSessionStore {
67
+ const sqlite = readControlPlaneRecord<ControllerSessionStore>(
68
+ options.controllerHome,
69
+ SESSION_STORE_NAMESPACE,
70
+ options.repoId,
71
+ SESSION_STORE_KEY,
72
+ )?.value;
73
+ if (sqlite) return sqlite;
74
+ return readJsonFile<ControllerSessionStore>(path(options), {
75
+ schemaVersion: 1,
76
+ updatedAt: now(options),
77
+ sessions: [],
78
+ });
79
+ }
80
+
81
+ function mergeSessionStores(
82
+ canonical: ControllerSessionStore,
83
+ legacy: ControllerSessionStore,
84
+ ): ControllerSessionStore {
85
+ const sessions = new Map(canonical.sessions.map((session) => [session.workId, session]));
86
+ for (const candidate of legacy.sessions) {
87
+ const existing = sessions.get(candidate.workId);
88
+ if (!existing) {
89
+ sessions.set(candidate.workId, candidate);
90
+ continue;
91
+ }
92
+ if (JSON.stringify(existing) === JSON.stringify(candidate)) continue;
93
+ const existingGeneration = existing.claimGeneration ?? 0;
94
+ const candidateGeneration = candidate.claimGeneration ?? 0;
95
+ const existingClaimedAt = Date.parse(existing.claimedAt);
96
+ const candidateClaimedAt = Date.parse(candidate.claimedAt);
97
+ if (existingGeneration > candidateGeneration
98
+ || (existingGeneration === candidateGeneration
99
+ && Number.isFinite(existingClaimedAt)
100
+ && Number.isFinite(candidateClaimedAt)
101
+ && existingClaimedAt > candidateClaimedAt)) {
102
+ // Canonical state has advanced since the read-only legacy snapshot.
103
+ continue;
104
+ }
105
+ throw new Error(`CONTROLLER_SESSION_ID_COLLISION: ${candidate.workId}`);
106
+ }
107
+ return {
108
+ schemaVersion: 1,
109
+ updatedAt: canonical.updatedAt >= legacy.updatedAt ? canonical.updatedAt : legacy.updatedAt,
110
+ sessions: [...sessions.values()],
111
+ };
112
+ }
113
+
114
+ function read(options: ControllerSessionStoreOptions): ControllerSessionStore {
115
+ const canonical = readControlPlaneRecord<ControllerSessionStore>(
116
+ options.controllerHome,
117
+ SESSION_STORE_NAMESPACE,
118
+ FORGE_INSTANCE_SCOPE_KEY,
119
+ SESSION_STORE_KEY,
120
+ )?.value ?? { schemaVersion: 1 as const, updatedAt: now(options), sessions: [] };
121
+ return mergeSessionStores(canonical, legacyStore(options));
122
+ }
123
+
124
+ function write(options: ControllerSessionStoreOptions, store: ControllerSessionStore): void {
125
+ writeControlPlaneRecord(options.controllerHome, {
126
+ namespace: SESSION_STORE_NAMESPACE,
127
+ scope: FORGE_INSTANCE_SCOPE_KEY,
128
+ key: SESSION_STORE_KEY,
129
+ schemaVersion: SESSION_STORE_SCHEMA_VERSION,
130
+ value: store,
131
+ action: 'controller_session_claim_write',
132
+ });
133
+ }
134
+
135
+ const RETAINED_SESSION_NAMESPACE = 'controller_session_identity';
136
+
137
+ interface RetainedControllerSessionRecord {
138
+ schemaVersion: 1;
139
+ session: ControllerSession;
140
+ retainedAt: string;
141
+ releasedAt?: string;
142
+ }
143
+
144
+ function retainedControllerSessionRecord(
145
+ options: ControllerSessionStoreOptions,
146
+ session: ControllerSession,
147
+ releasedAt?: string,
148
+ ): RetainedControllerSessionRecord {
149
+ const retainedAt = now(options);
150
+ return { schemaVersion: 1, session, retainedAt, ...(releasedAt ? { releasedAt } : {}) };
151
+ }
152
+
153
+ function persistRetainedControllerSession(
154
+ options: ControllerSessionStoreOptions,
155
+ session: ControllerSession,
156
+ releasedAt?: string,
157
+ ): void {
158
+ writeControlPlaneRecord(options.controllerHome, {
159
+ namespace: RETAINED_SESSION_NAMESPACE,
160
+ scope: FORGE_INSTANCE_SCOPE_KEY,
161
+ key: session.workId,
162
+ schemaVersion: 1,
163
+ value: retainedControllerSessionRecord(options, session, releasedAt),
164
+ action: releasedAt ? 'controller_session_identity_released' : 'controller_session_identity_retained',
165
+ });
166
+ }
167
+
168
+ function persistRetainedControllerSessionWithinTransaction(
169
+ database: SqliteDatabase,
170
+ options: ControllerSessionStoreOptions,
171
+ session: ControllerSession,
172
+ releasedAt?: string,
173
+ ): void {
174
+ writeControlPlaneRecordWithinTransaction(database, {
175
+ namespace: RETAINED_SESSION_NAMESPACE,
176
+ scope: FORGE_INSTANCE_SCOPE_KEY,
177
+ key: session.workId,
178
+ schemaVersion: 1,
179
+ value: retainedControllerSessionRecord(options, session, releasedAt),
180
+ action: releasedAt ? 'controller_session_identity_released' : 'controller_session_identity_retained',
181
+ });
182
+ }
183
+
184
+ /** Durable session identity survives transport/lease release; it is not an ownership lease. */
185
+ export function getRetainedControllerSession(
186
+ options: ControllerSessionStoreOptions,
187
+ workId: string,
188
+ ): ControllerSession | undefined {
189
+ const canonical = readControlPlaneRecord<RetainedControllerSessionRecord>(
190
+ options.controllerHome,
191
+ RETAINED_SESSION_NAMESPACE,
192
+ FORGE_INSTANCE_SCOPE_KEY,
193
+ workId,
194
+ )?.value.session;
195
+ const legacy = readControlPlaneRecord<RetainedControllerSessionRecord>(
196
+ options.controllerHome,
197
+ RETAINED_SESSION_NAMESPACE,
198
+ options.repoId,
199
+ workId,
200
+ )?.value.session;
201
+ if (canonical && legacy && JSON.stringify(canonical) !== JSON.stringify(legacy)) {
202
+ const canonicalGeneration = canonical.claimGeneration ?? 0;
203
+ const legacyGeneration = legacy.claimGeneration ?? 0;
204
+ const canonicalClaimedAt = Date.parse(canonical.claimedAt);
205
+ const legacyClaimedAt = Date.parse(legacy.claimedAt);
206
+ if (!(canonicalGeneration > legacyGeneration
207
+ || (canonicalGeneration === legacyGeneration
208
+ && Number.isFinite(canonicalClaimedAt)
209
+ && Number.isFinite(legacyClaimedAt)
210
+ && canonicalClaimedAt > legacyClaimedAt))) {
211
+ throw new Error(`CONTROLLER_SESSION_ID_COLLISION: ${workId}`);
212
+ }
213
+ }
214
+ return canonical ?? legacy ?? read(options).sessions.find((entry) => entry.workId === workId);
215
+ }
216
+
217
+ const DEFAULT_CONTROLLER_RECOVERY_GRACE_MS = 5 * 60_000;
218
+ const MAX_CONTROLLER_RECOVERY_GRACE_MS = 60 * 60_000;
219
+ const DEFAULT_CONTROLLER_LEASE_MS = 60 * 60_000;
220
+ const MAX_CONTROLLER_LEASE_MS = 60 * 60_000;
221
+
222
+ function optionsNowMs(options: ControllerSessionStoreOptions): number {
223
+ const parsed = Date.parse(now(options));
224
+ return Number.isFinite(parsed) ? parsed : Date.now();
225
+ }
226
+
227
+ function activeSession(store: ControllerSessionStore, workId: string, atMs: number = Date.now()): ControllerSession | undefined {
228
+ return store.sessions.find((session) => session.workId === workId && Date.parse(session.leaseExpiresAt) > atMs);
229
+ }
230
+
231
+ function sessionBlocksRecovery(
232
+ options: ControllerSessionStoreOptions,
233
+ owner: ControllerSession,
234
+ input: { nowMs: number; graceMs?: number },
235
+ ): boolean {
236
+ const execution = peekExecutionSession(options.controllerHome, owner.sessionId);
237
+ const graceMs = Math.max(60_000, Math.min(input.graceMs ?? DEFAULT_CONTROLLER_RECOVERY_GRACE_MS, MAX_CONTROLLER_RECOVERY_GRACE_MS));
238
+ if (execution?.invalidatedAt) {
239
+ const invalidatedAtMs = Date.parse(execution.invalidatedAt);
240
+ if (!Number.isFinite(invalidatedAtMs)) return true;
241
+ return input.nowMs - invalidatedAtMs < graceMs;
242
+ }
243
+ if (execution?.activeWorkId && execution.activeWorkId !== owner.workId) return false;
244
+ const activityMs = [execution?.lastValidatedAt, execution?.updatedAt, owner.claimedAt]
245
+ .map((value) => value ? Date.parse(value) : Number.NaN)
246
+ .filter(Number.isFinite)
247
+ .reduce((latest, value) => Math.max(latest, value), Number.NEGATIVE_INFINITY);
248
+ if (!Number.isFinite(activityMs)) return false;
249
+ return input.nowMs - activityMs < graceMs;
250
+ }
251
+
252
+ export function controllerSessionBlocksRecovery(
253
+ options: ControllerSessionStoreOptions,
254
+ workId: string,
255
+ input: { nowMs?: number; graceMs?: number } = {},
256
+ ): boolean {
257
+ const nowMs = input.nowMs ?? Date.now();
258
+ const owner = activeSession(read(options), workId, nowMs);
259
+ if (!owner) return false;
260
+ return sessionBlocksRecovery(options, owner, { nowMs, graceMs: input.graceMs });
261
+ }
262
+
263
+ function assertIdentity(input: ControllerSessionClaimInput): void {
264
+ if (!input.workId.trim() || !input.controllerId.trim() || !input.sessionId.trim()) {
265
+ throw new Error('CONTROLLER_SESSION_IDENTITY_REQUIRED');
266
+ }
267
+ }
268
+
269
+ /**
270
+ * Compatibility no-op. ControllerSession is mechanical dispatch/reattachment
271
+ * state and does not decide whether semantic Work is open or terminal.
272
+ */
273
+ export function assertControllerSessionWorkClaimable(_options: ControllerSessionStoreOptions, _workId: string): void {}
274
+
275
+ function claimedSession(
276
+ options: ControllerSessionStoreOptions,
277
+ input: ControllerSessionClaimInput,
278
+ claimedAt: string,
279
+ previous?: ControllerSession,
280
+ ): ClaimedControllerSession {
281
+ const leaseExpiresAt = new Date(
282
+ Date.parse(claimedAt) + Math.max(1_000, Math.min(input.leaseMs ?? DEFAULT_CONTROLLER_LEASE_MS, MAX_CONTROLLER_LEASE_MS)),
283
+ ).toISOString();
284
+ const previousPrincipal = previous?.principalId?.trim() || previous?.controllerId;
285
+ const inputPrincipal = input.principalId?.trim() || input.controllerId;
286
+ const sameOwner = previous?.controllerId === input.controllerId
287
+ && previous?.controllerType === input.controllerType
288
+ && previousPrincipal === inputPrincipal
289
+ && (previous.controllerInstanceId ?? '') === (input.controllerInstanceId?.trim() ?? '');
290
+ const claimGeneration = sameOwner
291
+ ? Math.max(1, previous?.claimGeneration ?? 1)
292
+ : Math.max(0, previous?.claimGeneration ?? 0) + 1;
293
+ const authorityDigest = input.authorityDigest?.trim() || (sameOwner ? previous?.authorityDigest?.trim() : '') || '';
294
+ return {
295
+ schemaVersion: 1,
296
+ workId: input.workId,
297
+ controllerId: input.controllerId,
298
+ controllerType: input.controllerType,
299
+ sessionId: input.sessionId,
300
+ ...(authorityDigest ? { authorityDigest } : {}),
301
+ ...(input.principalId?.trim() ? { principalId: input.principalId.trim() } : {}),
302
+ ...(input.controllerInstanceId?.trim() ? { controllerInstanceId: input.controllerInstanceId.trim() } : {}),
303
+ claimGeneration,
304
+ claimedAt,
305
+ leaseExpiresAt,
306
+ };
307
+ }
308
+
309
+ function assertExpectedGeneration(input: ControllerSessionClaimInput, current: ControllerSession | undefined): void {
310
+ if (input.expectedClaimGeneration === undefined) return;
311
+ const actual = current?.claimGeneration ?? 0;
312
+ if (actual !== input.expectedClaimGeneration) {
313
+ throw new Error(`WORK_CLAIM_GENERATION_MISMATCH: ${input.workId} expected=${input.expectedClaimGeneration} actual=${actual}`);
314
+ }
315
+ }
316
+
317
+ function preparedClaim(
318
+ options: ControllerSessionStoreOptions,
319
+ store: ControllerSessionStore,
320
+ input: ControllerSessionClaimInput,
321
+ previous?: ControllerSession,
322
+ ): { claimedAt: string; session: ClaimedControllerSession; nextStore: ControllerSessionStore } {
323
+ const claimedAt = now(options);
324
+ const claimedAtMs = Date.parse(claimedAt);
325
+ const session = claimedSession(options, input, claimedAt, previous);
326
+ const sessions = [
327
+ ...store.sessions.filter((entry) => entry.workId !== input.workId && Date.parse(entry.leaseExpiresAt) > claimedAtMs),
328
+ session,
329
+ ];
330
+ return { claimedAt, session, nextStore: { schemaVersion: 1, updatedAt: claimedAt, sessions } };
331
+ }
332
+
333
+ function persistClaim(
334
+ options: ControllerSessionStoreOptions,
335
+ store: ControllerSessionStore,
336
+ input: ControllerSessionClaimInput,
337
+ previous?: ControllerSession,
338
+ ): ClaimedControllerSession {
339
+ const prepared = preparedClaim(options, store, input, previous);
340
+ write(options, prepared.nextStore);
341
+ persistRetainedControllerSession(options, prepared.session);
342
+ return prepared.session;
343
+ }
344
+
345
+ function readSessionStoreWithinTransaction(
346
+ database: SqliteDatabase,
347
+ options: ControllerSessionStoreOptions,
348
+ ) {
349
+ let current = readControlPlaneRecordWithinTransaction<ControllerSessionStore>(
350
+ database, SESSION_STORE_NAMESPACE, FORGE_INSTANCE_SCOPE_KEY, SESSION_STORE_KEY,
351
+ );
352
+ const legacySqlite = readControlPlaneRecordWithinTransaction<ControllerSessionStore>(
353
+ database, SESSION_STORE_NAMESPACE, options.repoId, SESSION_STORE_KEY,
354
+ )?.value;
355
+ const legacy = legacySqlite ?? readJsonFile<ControllerSessionStore>(path(options), {
356
+ schemaVersion: 1,
357
+ updatedAt: now(options),
358
+ sessions: [],
359
+ });
360
+ if (current) return { ...current, value: mergeSessionStores(current.value, legacy) };
361
+ current = writeControlPlaneRecordWithinTransaction(database, {
362
+ namespace: SESSION_STORE_NAMESPACE,
363
+ scope: FORGE_INSTANCE_SCOPE_KEY,
364
+ key: SESSION_STORE_KEY,
365
+ schemaVersion: SESSION_STORE_SCHEMA_VERSION,
366
+ value: legacy,
367
+ action: 'legacy_controller_session_import',
368
+ expectedRevision: null,
369
+ });
370
+ return current;
371
+ }
372
+
373
+ function persistClaimWithinTransaction(
374
+ database: SqliteDatabase,
375
+ options: ControllerSessionStoreOptions,
376
+ storeRecord: ReturnType<typeof readSessionStoreWithinTransaction>,
377
+ input: ControllerSessionClaimInput,
378
+ previous?: ControllerSession,
379
+ ): ClaimedControllerSession {
380
+ const prepared = preparedClaim(options, storeRecord.value, input, previous);
381
+ writeControlPlaneRecordWithinTransaction(database, {
382
+ namespace: SESSION_STORE_NAMESPACE,
383
+ scope: FORGE_INSTANCE_SCOPE_KEY,
384
+ key: SESSION_STORE_KEY,
385
+ schemaVersion: SESSION_STORE_SCHEMA_VERSION,
386
+ value: prepared.nextStore,
387
+ action: 'controller_session_claim_write',
388
+ expectedRevision: storeRecord.revision,
389
+ });
390
+ persistRetainedControllerSessionWithinTransaction(database, options, prepared.session);
391
+ return prepared.session;
392
+ }
393
+
394
+ export function getControllerSession(options: ControllerSessionStoreOptions, workId: string): ControllerSession | undefined {
395
+ return activeSession(read(options), workId, optionsNowMs(options));
396
+ }
397
+
398
+ export function listControllerSessions(options: ControllerSessionStoreOptions): ControllerSession[] {
399
+ const at = optionsNowMs(options);
400
+ return read(options).sessions.filter((session) => Date.parse(session.leaseExpiresAt) > at);
401
+ }
402
+
403
+ export interface ControllerOwnershipAuthority {
404
+ controllerId: string;
405
+ controllerType: ControllerType;
406
+ principalId: string;
407
+ controllerInstanceId: string;
408
+ claimGeneration: number;
409
+ }
410
+
411
+ export type ControllerTerminalizationAuthority = ControllerOwnershipAuthority;
412
+
413
+ export function controllerSessionPrincipalId(
414
+ owner: Pick<ControllerSession, 'principalId' | 'controllerId'>,
415
+ ): string {
416
+ return owner.principalId?.trim() || owner.controllerId;
417
+ }
418
+
419
+ function digestControllerAuthority(authorityId: string): string {
420
+ return createHash('sha256').update(authorityId).digest('hex');
421
+ }
422
+
423
+ /** Mint a non-relay Work-bound capability. Only the digest belongs in durable ControllerSession state. */
424
+ export function mintControllerSessionAuthority(): { authorityId: string; authorityDigest: string } {
425
+ const authorityId = `ctrl_${randomUUID().replace(/-/g, '')}`;
426
+ return { authorityId, authorityDigest: digestControllerAuthority(authorityId) };
427
+ }
428
+
429
+ /** Bind an already-authorized opaque capability without persisting its plaintext value. */
430
+ export function controllerSessionAuthorityDigest(authorityId: string): string {
431
+ const normalized = authorityId.trim();
432
+ if (!normalized) throw new Error('WORK_CONTROLLER_AUTHORITY_REQUIRED');
433
+ return digestControllerAuthority(normalized);
434
+ }
435
+
436
+ /** Verify an opaque capability without exposing or persisting its plaintext value. */
437
+ export function controllerSessionAuthorityMatches(owner: ControllerSession, authorityId: string | undefined): boolean {
438
+ const expected = owner.authorityDigest?.trim() || '';
439
+ const candidate = authorityId?.trim() || '';
440
+ if (!expected || !candidate) return false;
441
+ const actual = digestControllerAuthority(candidate);
442
+ if (expected.length !== actual.length) return false;
443
+ return timingSafeEqual(Buffer.from(expected, 'hex'), Buffer.from(actual, 'hex'));
444
+ }
445
+
446
+ export function requireControllerOwnershipAuthority(
447
+ owner: ControllerSession,
448
+ workId: string = owner.workId,
449
+ ): ControllerOwnershipAuthority {
450
+ const principalId = controllerSessionPrincipalId(owner);
451
+ const controllerInstanceId = owner.controllerInstanceId?.trim() || '';
452
+ if (!controllerInstanceId) throw new Error(`WORK_CONTROLLER_INSTANCE_MISMATCH: ${workId}`);
453
+ if (typeof owner.claimGeneration !== 'number' || owner.claimGeneration < 1) {
454
+ throw new Error(`WORK_CONTROLLER_CLAIM_GENERATION_REQUIRED: ${workId}`);
455
+ }
456
+ return {
457
+ controllerId: owner.controllerId,
458
+ controllerType: owner.controllerType,
459
+ principalId,
460
+ controllerInstanceId,
461
+ claimGeneration: owner.claimGeneration,
462
+ };
463
+ }
464
+
465
+ export function assertControllerOwnershipAuthority(
466
+ owner: ControllerSession,
467
+ expected: {
468
+ workId?: string;
469
+ controllerId: string;
470
+ principalId: string;
471
+ controllerInstanceId?: string;
472
+ controllerType?: ControllerType;
473
+ },
474
+ ): ControllerOwnershipAuthority {
475
+ const workId = expected.workId ?? owner.workId;
476
+ const authority = requireControllerOwnershipAuthority(owner, workId);
477
+ if (authority.controllerId !== expected.controllerId.trim()) {
478
+ throw new Error(`WORK_CONTROLLER_OWNER_MISMATCH: ${workId} is owned by ${owner.controllerId}`);
479
+ }
480
+ if (expected.controllerType && authority.controllerType !== expected.controllerType) {
481
+ throw new Error(`WORK_CONTROLLER_TYPE_MISMATCH: ${workId} is owned by ${owner.controllerType}`);
482
+ }
483
+ if (authority.principalId !== expected.principalId.trim()) {
484
+ throw new Error(`WORK_CONTROLLER_PRINCIPAL_MISMATCH: ${workId}`);
485
+ }
486
+ if (expected.controllerInstanceId !== undefined
487
+ && authority.controllerInstanceId !== expected.controllerInstanceId.trim()) {
488
+ throw new Error(`WORK_CONTROLLER_INSTANCE_MISMATCH: ${workId}`);
489
+ }
490
+ return authority;
491
+ }
492
+
493
+ export type ControllerTerminalizationFenceReason =
494
+ | 'active_controller_claim'
495
+ | 'stale_controller_authority'
496
+ | 'controller_claim_missing';
497
+
498
+ export type ControllerTerminalizationFenceResult<T> =
499
+ | { allowed: true; value: T; owner?: ControllerSession }
500
+ | { allowed: false; reason: ControllerTerminalizationFenceReason; owner?: ControllerSession };
501
+
502
+ export function controllerTerminalizationAuthorityFromSession(
503
+ owner: ControllerSession,
504
+ ): ControllerTerminalizationAuthority | undefined {
505
+ try {
506
+ return requireControllerOwnershipAuthority(owner);
507
+ } catch {
508
+ return undefined;
509
+ }
510
+ }
511
+
512
+ function controllerTerminalizationAuthorityMatches(
513
+ owner: ControllerSession,
514
+ authority: ControllerTerminalizationAuthority,
515
+ ): boolean {
516
+ const ownerPrincipal = controllerSessionPrincipalId(owner);
517
+ const ownerInstanceId = owner.controllerInstanceId?.trim() || '';
518
+ return owner.controllerId === authority.controllerId
519
+ && owner.controllerType === authority.controllerType
520
+ && ownerPrincipal === authority.principalId.trim()
521
+ && ownerInstanceId === authority.controllerInstanceId.trim()
522
+ && owner.claimGeneration === authority.claimGeneration;
523
+ }
524
+
525
+ /**
526
+ * Serialize control-path Work terminalization against the same canonical
527
+ * ControllerSession task lock used by claim/resume/release. This is a fence,
528
+ * not a second lifecycle authority: WorkContract remains the terminal state
529
+ * authority and ControllerSession remains the ownership authority.
530
+ *
531
+ * A caller without Controller authority may terminalize only while the Work is
532
+ * unclaimed. A caller that observed a live owner must present that exact durable
533
+ * owner epoch. Transport session ids are intentionally not compared because MCP
534
+ * transports may rotate without moving Work ownership; controller instance plus
535
+ * claim generation fence stale controller epochs while preserving that rotation.
536
+ */
537
+ export function withControllerSessionTerminalizationFence<T>(
538
+ options: ControllerSessionStoreOptions,
539
+ input: {
540
+ workId: string;
541
+ actor: string;
542
+ authority?: ControllerTerminalizationAuthority;
543
+ },
544
+ operation: () => T,
545
+ ): ControllerTerminalizationFenceResult<T> {
546
+ return withControllerLock(
547
+ options.controllerHome,
548
+ { scope: 'global', resource: 'controller-session-store' },
549
+ input.actor,
550
+ () => {
551
+ const owner = activeSession(read(options), input.workId, optionsNowMs(options));
552
+ if (!owner) {
553
+ if (input.authority) return { allowed: false, reason: 'controller_claim_missing' };
554
+ return { allowed: true, value: operation() };
555
+ }
556
+ if (!input.authority) return { allowed: false, reason: 'active_controller_claim', owner };
557
+
558
+ if (!controllerTerminalizationAuthorityMatches(owner, input.authority)) {
559
+ return { allowed: false, reason: 'stale_controller_authority', owner };
560
+ }
561
+ return { allowed: true, value: operation(), owner };
562
+ },
563
+ );
564
+ }
565
+
566
+ /**
567
+ * Release a live ControllerSession only when the caller still owns the exact
568
+ * durable controller epoch it observed. This closes the release-then-terminalize
569
+ * race without changing WorkContract lifecycle authority.
570
+ */
571
+ export function releaseControllerSessionWithAuthority(
572
+ options: ControllerSessionStoreOptions,
573
+ input: {
574
+ workId: string;
575
+ actor: string;
576
+ authority: ControllerTerminalizationAuthority;
577
+ },
578
+ ): ControllerTerminalizationFenceResult<void> {
579
+ return withControllerLock(
580
+ options.controllerHome,
581
+ { scope: 'global', resource: 'controller-session-store' },
582
+ input.actor,
583
+ () => {
584
+ const store = read(options);
585
+ const owner = activeSession(store, input.workId, optionsNowMs(options));
586
+ if (!owner) return { allowed: false, reason: 'controller_claim_missing' };
587
+ if (!controllerTerminalizationAuthorityMatches(owner, input.authority)) {
588
+ return { allowed: false, reason: 'stale_controller_authority', owner };
589
+ }
590
+ const releasedAt = now(options);
591
+ persistRetainedControllerSession(options, owner, releasedAt);
592
+ const sessions = store.sessions.filter((entry) => entry.workId !== input.workId);
593
+ write(options, { schemaVersion: 1, updatedAt: releasedAt, sessions });
594
+ return { allowed: true, value: undefined, owner };
595
+ },
596
+ );
597
+ }
598
+
599
+ export function releaseObservedControllerSession(
600
+ options: ControllerSessionStoreOptions,
601
+ input: { workId: string; actor: string; owner: ControllerSession },
602
+ ): ControllerTerminalizationFenceResult<void> {
603
+ const authority = controllerTerminalizationAuthorityFromSession(input.owner);
604
+ if (!authority) return { allowed: false, reason: 'stale_controller_authority', owner: input.owner };
605
+ return releaseControllerSessionWithAuthority(options, {
606
+ workId: input.workId,
607
+ actor: input.actor,
608
+ authority,
609
+ });
610
+ }
611
+
612
+ /**
613
+ * Strict claim used for first ownership acquisition and explicit release/reclaim flows.
614
+ * A live claim with any different controller or transport session remains fenced.
615
+ */
616
+ export function claimControllerSession(
617
+ options: ControllerSessionStoreOptions,
618
+ input: ControllerSessionClaimInput,
619
+ ): ClaimedControllerSession {
620
+ assertIdentity(input);
621
+ return withControllerLock(
622
+ options.controllerHome,
623
+ { scope: 'global', resource: 'controller-session-store' },
624
+ `controller-claim:${input.controllerId}:${input.sessionId}`,
625
+ () => {
626
+ assertControllerWorkClaimable(options, input.workId);
627
+ const store = read(options);
628
+ const current = activeSession(store, input.workId, optionsNowMs(options));
629
+ const previous = current ?? store.sessions
630
+ .filter((entry) => entry.workId === input.workId)
631
+ .sort((left, right) => (right.claimGeneration ?? 0) - (left.claimGeneration ?? 0))[0];
632
+ assertExpectedGeneration(input, current);
633
+ if (current && (current.controllerId !== input.controllerId || current.sessionId !== input.sessionId)) {
634
+ throw new Error(`WORK_ALREADY_CLAIMED: ${input.workId} is owned by ${current.controllerId}`);
635
+ }
636
+ return persistClaim(options, store, input, previous);
637
+ },
638
+ );
639
+ }
640
+
641
+ /**
642
+ * Resume a claim after transport replacement. Durable Work ownership belongs to
643
+ * the authenticated principal/controller epoch, not to one MCP transport session.
644
+ * A same-principal session rotation therefore preserves ownership generation;
645
+ * a controller-epoch change is recovery and advances the generation fence.
646
+ */
647
+ function resumableControllerSessionPrevious(
648
+ options: ControllerSessionStoreOptions,
649
+ store: ControllerSessionStore,
650
+ input: ControllerSessionClaimInput & { principalId: string; controllerInstanceId: string },
651
+ database?: SqliteDatabase,
652
+ ): ControllerSession | undefined {
653
+ assertControllerWorkClaimable(options, input.workId);
654
+ const currentNowMs = optionsNowMs(options);
655
+ const current = activeSession(store, input.workId, currentNowMs);
656
+ assertExpectedGeneration(input, current);
657
+ if (!current) {
658
+ return store.sessions
659
+ .filter((entry) => entry.workId === input.workId)
660
+ .sort((left, right) => (right.claimGeneration ?? 0) - (left.claimGeneration ?? 0))[0];
661
+ }
662
+ const explicitPrincipal = current.principalId?.trim();
663
+ const priorExecution = explicitPrincipal
664
+ ? undefined
665
+ : database
666
+ ? peekExecutionSessionWithinTransaction(database, options.controllerHome, current.sessionId)
667
+ : peekExecutionSession(options.controllerHome, current.sessionId);
668
+ const currentPrincipal = explicitPrincipal || priorExecution?.principalId?.trim() || current.controllerId;
669
+ const staleRecoveryAllowed = input.allowStaleRecovery === true
670
+ && input.expectedClaimGeneration !== undefined
671
+ && !sessionBlocksRecovery(options, current, { nowMs: currentNowMs });
672
+ if (currentPrincipal !== input.principalId.trim() && !staleRecoveryAllowed) {
673
+ throw new Error(`WORK_CONTROLLER_PRINCIPAL_MISMATCH: ${input.workId} is owned by another authenticated principal`);
674
+ }
675
+ if (current.controllerId !== input.controllerId && !staleRecoveryAllowed) {
676
+ throw new Error(`WORK_ALREADY_CLAIMED: ${input.workId} is owned by ${current.controllerId}`);
677
+ }
678
+ if (current.controllerType !== input.controllerType && !staleRecoveryAllowed) {
679
+ throw new Error(`WORK_CONTROLLER_TYPE_MISMATCH: ${input.workId} is owned by ${current.controllerType}`);
680
+ }
681
+ return current;
682
+ }
683
+
684
+ export function withControllerSessionMutationLock<T>(
685
+ options: ControllerSessionStoreOptions,
686
+ workId: string,
687
+ actor: string,
688
+ operation: () => T,
689
+ ): T {
690
+ return withControllerLock(
691
+ options.controllerHome,
692
+ { scope: 'global', resource: 'controller-session-store' },
693
+ actor,
694
+ operation,
695
+ );
696
+ }
697
+
698
+ /** Transaction-aware resume used only by higher-level Controller claim orchestration while the canonical session lock is held. */
699
+ export function resumeControllerSessionWithinTransaction(
700
+ database: SqliteDatabase,
701
+ options: ControllerSessionStoreOptions,
702
+ input: ControllerSessionClaimInput & { principalId: string; controllerInstanceId: string },
703
+ ): ClaimedControllerSession {
704
+ assertIdentity(input);
705
+ if (!input.principalId.trim() || !input.controllerInstanceId.trim()) throw new Error('CONTROLLER_RESUME_AUTHORITY_REQUIRED');
706
+ const storeRecord = readSessionStoreWithinTransaction(database, options);
707
+ const previous = resumableControllerSessionPrevious(options, storeRecord.value, input, database);
708
+ return persistClaimWithinTransaction(database, options, storeRecord, input, previous);
709
+ }
710
+
711
+ export function resumeControllerSession(
712
+ options: ControllerSessionStoreOptions,
713
+ input: ControllerSessionClaimInput & { principalId: string; controllerInstanceId: string },
714
+ ): ClaimedControllerSession {
715
+ assertIdentity(input);
716
+ if (!input.principalId.trim() || !input.controllerInstanceId.trim()) {
717
+ throw new Error('CONTROLLER_RESUME_AUTHORITY_REQUIRED');
718
+ }
719
+ return withControllerSessionMutationLock(
720
+ options,
721
+ input.workId,
722
+ `controller-resume:${input.controllerId}:${input.sessionId}`,
723
+ () => {
724
+ const store = read(options);
725
+ const previous = resumableControllerSessionPrevious(options, store, input);
726
+ return persistClaim(options, store, input, previous);
727
+ },
728
+ );
729
+ }
730
+
731
+ /**
732
+ * Rebind one active Work to the authenticated Controller transport/Runtime that
733
+ * is serving the current request. Same-instance transport rollover needs only
734
+ * principal/controller proof. A Runtime-instance change additionally requires
735
+ * positive proof that the requested instance is the live canonical Runtime;
736
+ * this prevents a stale old Runtime request from migrating ownership backwards.
737
+ * The observed claim generation is always supplied as a CAS fence.
738
+ */
739
+ export function bindControllerSessionToCurrentRuntime(
740
+ options: ControllerSessionStoreOptions,
741
+ input: ControllerSessionClaimInput & {
742
+ principalId: string;
743
+ controllerInstanceId: string;
744
+ currentRuntimeInstanceId?: string;
745
+ allowClaimIfMissing?: boolean;
746
+ },
747
+ ): ControllerSession {
748
+ assertIdentity(input);
749
+ const current = getControllerSession(options, input.workId);
750
+ if (!current) {
751
+ if (input.allowClaimIfMissing !== true) throw new Error(`WORK_CONTROLLER_OWNER_REQUIRED: ${input.workId}`);
752
+ return claimControllerSession(options, { ...input, expectedClaimGeneration: 0 });
753
+ }
754
+ const currentPrincipal = controllerSessionPrincipalId(current);
755
+ if (current.controllerId !== input.controllerId) {
756
+ throw new Error(`WORK_CONTROLLER_OWNER_MISMATCH: ${input.workId} is owned by ${current.controllerId}`);
757
+ }
758
+ if (current.controllerType !== input.controllerType) {
759
+ throw new Error(`WORK_CONTROLLER_TYPE_MISMATCH: ${input.workId} is owned by ${current.controllerType}`);
760
+ }
761
+ if (currentPrincipal !== input.principalId.trim()) {
762
+ throw new Error(`WORK_CONTROLLER_PRINCIPAL_MISMATCH: ${input.workId}`);
763
+ }
764
+ const ownerInstanceId = current.controllerInstanceId?.trim() || '';
765
+ const requestedInstanceId = input.controllerInstanceId.trim();
766
+ if (ownerInstanceId !== requestedInstanceId) {
767
+ const currentRuntimeInstanceId = input.currentRuntimeInstanceId?.trim() || '';
768
+ if (!currentRuntimeInstanceId || currentRuntimeInstanceId !== requestedInstanceId) {
769
+ throw new Error(`WORK_CONTROLLER_INSTANCE_MISMATCH: ${input.workId}`);
770
+ }
771
+ }
772
+ const requestedAuthorityDigest = input.authorityDigest?.trim() || '';
773
+ const currentAuthorityDigest = current.authorityDigest?.trim() || '';
774
+ if (
775
+ ownerInstanceId === requestedInstanceId
776
+ && current.sessionId === input.sessionId
777
+ && (!requestedAuthorityDigest || requestedAuthorityDigest === currentAuthorityDigest)
778
+ ) return current;
779
+ // The opaque Work capability belongs to durable ownership, not to one
780
+ // transport or Runtime process. A positively-current Runtime migration keeps
781
+ // the same digest while claim generation fences the new controller epoch.
782
+ const preservedAuthorityDigest = input.authorityDigest?.trim() || current.authorityDigest?.trim() || undefined;
783
+ return resumeControllerSession(options, {
784
+ ...input,
785
+ ...(preservedAuthorityDigest ? { authorityDigest: preservedAuthorityDigest } : {}),
786
+ expectedClaimGeneration: current.claimGeneration,
787
+ });
788
+ }
789
+
790
+ export function releaseControllerSession(options: ControllerSessionStoreOptions, workId: string, controllerId: string): void {
791
+ withControllerLock(
792
+ options.controllerHome,
793
+ { scope: 'global', resource: 'controller-session-store' },
794
+ `controller-release:${controllerId}`,
795
+ () => {
796
+ const store = read(options);
797
+ const owner = store.sessions.find((entry) => entry.workId === workId && entry.controllerId === controllerId);
798
+ const releasedAt = now(options);
799
+ if (owner) persistRetainedControllerSession(options, owner, releasedAt);
800
+ const sessions = store.sessions.filter((entry) => entry.workId !== workId || entry.controllerId !== controllerId);
801
+ write(options, { schemaVersion: 1, updatedAt: releasedAt, sessions });
802
+ },
803
+ );
804
+ }