@moretea-labs/forge 1.8.0 → 1.8.2

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 (695) hide show
  1. package/AGENTS.md +73 -7
  2. package/CHANGELOG.md +34 -0
  3. package/CLAUDE.md +17 -2
  4. package/CONTRIBUTING.md +3 -2
  5. package/README.en.md +24 -3
  6. package/README.md +10 -6
  7. package/README.zh-CN.md +5 -3
  8. package/THIRD_PARTY_NOTICES.md +1 -2
  9. package/adapters/chatgpt/browser-delivery-host.ts +7 -1
  10. package/adapters/chatgpt/browser-delivery-runtime.ts +531 -56
  11. package/adapters/chatgpt/controller-binding-store.ts +101 -22
  12. package/adapters/chatgpt/controller-round-host.ts +15 -25
  13. package/adapters/chatgpt/controller-round-settlement-store.ts +58 -4
  14. package/adapters/chatgpt/provider-delivery.ts +229 -2
  15. package/adapters/chatgpt/work-conversation-binding-store.ts +99 -54
  16. package/adapters/computer/chatgpt-extension-target.ts +708 -0
  17. package/adapters/computer/chrome-extension/background.js +541 -0
  18. package/adapters/computer/chrome-extension/content.js +402 -0
  19. package/adapters/computer/chrome-extension/core.js +24 -0
  20. package/adapters/computer/chrome-extension/manifest.json +32 -0
  21. package/adapters/computer/desktop-operator-discovery.ts +11 -31
  22. package/adapters/computer/desktop-operator-provider.ts +18 -6
  23. package/adapters/computer/interaction-target-authority.ts +178 -24
  24. package/adapters/mcp/access-mode.ts +18 -39
  25. package/adapters/mcp/auth.ts +2 -7
  26. package/adapters/mcp/instructions.ts +6 -5
  27. package/adapters/mcp/multi-repository.ts +10 -47
  28. package/adapters/mcp/oauth.ts +73 -0
  29. package/adapters/mcp/paths.ts +4 -1
  30. package/adapters/mcp/runtime-gateway/bounded-result-runtime.ts +62 -0
  31. package/adapters/mcp/runtime-gateway/cognition-settlement.ts +201 -0
  32. package/adapters/mcp/runtime-gateway/context-adapter.ts +490 -113
  33. package/adapters/mcp/runtime-gateway/context-pack-sidecar.ts +83 -0
  34. package/adapters/mcp/runtime-gateway/controller-authority-adapter.ts +20 -5
  35. package/adapters/mcp/runtime-gateway/core-capability-adapter.ts +258 -0
  36. package/adapters/mcp/runtime-gateway/engineering-preconditions.ts +10 -27
  37. package/adapters/mcp/runtime-gateway/engineering-tool-contract.ts +15 -0
  38. package/adapters/mcp/runtime-gateway/execution-tools.ts +14 -54
  39. package/adapters/mcp/runtime-gateway/gateway-execution-adapter.ts +2 -1
  40. package/adapters/mcp/runtime-gateway/plugin-adapter.ts +132 -47
  41. package/adapters/mcp/runtime-gateway/process-tools.ts +173 -23
  42. package/adapters/mcp/runtime-gateway/protected-computer-adapter.ts +16 -4
  43. package/adapters/mcp/runtime-gateway/recovery-adapter.ts +69 -52
  44. package/adapters/mcp/runtime-gateway/repository-compat-adapter.ts +4 -35
  45. package/adapters/mcp/runtime-gateway/result-adapter.ts +10 -4
  46. package/adapters/mcp/runtime-gateway/router.ts +19 -507
  47. package/adapters/mcp/runtime-gateway/routing-policy.ts +506 -0
  48. package/adapters/mcp/runtime-gateway/runtime-observation-adapter.ts +15 -66
  49. package/adapters/mcp/runtime-gateway/runtime-readiness-observation.ts +218 -0
  50. package/adapters/mcp/runtime-gateway/runtime-tool-definitions.ts +123 -178
  51. package/adapters/mcp/runtime-gateway/runtime-tools.ts +11 -5
  52. package/adapters/mcp/runtime-gateway/scheduler-adapter.ts +37 -1
  53. package/adapters/mcp/runtime-gateway/shared-adapter.ts +20 -0
  54. package/adapters/mcp/runtime-gateway/status-inbox-adapter.ts +416 -270
  55. package/adapters/mcp/runtime-gateway/typescript-navigation-sidecar.ts +140 -0
  56. package/adapters/mcp/runtime-gateway/work-adapter.ts +262 -3123
  57. package/adapters/mcp/runtime-gateway/work-controller-operations.ts +257 -0
  58. package/adapters/mcp/runtime-gateway/work-detail-projection.ts +60 -0
  59. package/adapters/mcp/runtime-gateway/work-input-wire-migration.ts +229 -0
  60. package/adapters/mcp/runtime-gateway/work-learning-operations.ts +145 -0
  61. package/adapters/mcp/runtime-gateway/work-list-projection.ts +38 -0
  62. package/adapters/mcp/runtime-gateway/work-plan-operations.ts +382 -0
  63. package/adapters/mcp/runtime-gateway/work-repair-adapter.ts +308 -0
  64. package/adapters/mcp/runtime-gateway/work-requirement-operations.ts +148 -0
  65. package/adapters/mcp/runtime-gateway/work-semantic-operations.ts +320 -0
  66. package/adapters/mcp/runtime-gateway/work-workflow-operations.ts +113 -0
  67. package/adapters/mcp/runtime-gateway/workflow-supervisor-adapter.ts +180 -0
  68. package/adapters/mcp/server.ts +91 -26
  69. package/adapters/mcp/setup.ts +5 -13
  70. package/adapters/mcp/tool-mapping/access-tools.ts +0 -6
  71. package/adapters/mcp/tool-mapping/legacy-tool-service.ts +703 -3092
  72. package/adapters/mcp/tool-mapping/post-finalize-work-attribution.ts +5 -10
  73. package/adapters/mcp/tool-mapping/repository-tools.ts +170 -213
  74. package/adapters/mcp/toolset-names.ts +11 -37
  75. package/adapters/mcp/toolset.ts +19 -92
  76. package/{src/cli → adapters}/mcp/transports/AGENTS.md +5 -5
  77. package/{src/cli → adapters}/mcp/transports/CLAUDE.md +5 -5
  78. package/adapters/mcp/transports/http-observation.ts +377 -0
  79. package/adapters/mcp/transports/http-post-lifecycle.ts +19 -0
  80. package/adapters/mcp/transports/http.ts +200 -683
  81. package/adapters/mcp/transports/oauth-http.ts +322 -0
  82. package/adapters/mcp/transports/session-registry.ts +6 -0
  83. package/adapters/mcp/tunnels/openai-secure-tunnel.ts +89 -5
  84. package/adapters/mcp/types.ts +0 -6
  85. package/assets/hooks/lib/session-state.sh +0 -38
  86. package/assets/hooks/post-bash.sh +1 -1
  87. package/assets/hooks/post-tool-observer.sh +0 -5
  88. package/assets/hooks/prompt-guard.sh +0 -55
  89. package/assets/partials/04-project-structure.partial.md +1 -1
  90. package/assets/partials/07-footer.partial.md +1 -1
  91. package/assets/partials-agents/02-operating-mode.partial.md +1 -1
  92. package/assets/partials-agents/08-deep-docs.partial.md +1 -1
  93. package/assets/plugin-registry.v1.json +6 -4
  94. package/assets/reference-configs/agentic-development-flow.md +26 -1
  95. package/assets/reference-configs/external-tooling.md +0 -76
  96. package/assets/reference-configs/global-working-rules.md +19 -0
  97. package/assets/reference-configs/release-deploy.md +1 -1
  98. package/assets/templates/helpers/architecture-queue.sh +1 -1
  99. package/assets/templates/helpers/check-agent-tooling.sh +1 -327
  100. package/assets/templates/helpers/check-task-workflow.sh +1 -1
  101. package/assets/templates/helpers/ensure-task-workflow.sh +0 -14
  102. package/assets/templates/helpers/migrate-project-template.sh +2 -2
  103. package/assets/workflow-contract.v1.json +0 -2
  104. package/docs/README.md +5 -2
  105. package/docs/architecture/CURRENT.md +205 -51
  106. package/docs/architecture/decisions/20260803-release-identity-binding-and-exit-policy.md +14 -5
  107. package/docs/architecture/decisions/20260823-immediate-controller-relay.md +6 -3
  108. package/docs/architecture/decisions/20260904-ios-device-migration-baseline.md +42 -0
  109. package/docs/architecture/decisions/20260907-assistant-learning-loop.md +2 -0
  110. package/docs/architecture/decisions/20260907-controller-round-transition-policy.md +19 -4
  111. package/docs/architecture/decisions/20260916-workflow-supervisor-authority.md +249 -0
  112. package/docs/architecture/decisions/20260917-cognitive-memory-foundation.md +82 -0
  113. package/docs/architecture/decisions/20260918-stable-candidate-release-lifecycle.md +234 -0
  114. package/docs/architecture/decisions/20260919-autonomous-work-liveness.md +62 -0
  115. package/docs/architecture/decisions/20260924-thin-semantic-working-context.md +74 -0
  116. package/docs/architecture/decisions/20261001-supervisor-turn-authority.md +342 -0
  117. package/docs/architecture/decisions/20261005-forge-v3-desktop-client-boundary.md +77 -0
  118. package/docs/architecture/decisions/20261009-exact-code-context-discovery.md +19 -0
  119. package/docs/architecture/decisions/20261009-generated-xcode-cache-retention.md +37 -0
  120. package/docs/architecture/decisions/20261011-autonomous-continuation-convergence.md +597 -0
  121. package/docs/architecture/decisions/20261017-edit-session-finalization-reconciliation.md +17 -0
  122. package/docs/architecture/decisions/20261019-retire-host-skills.md +16 -0
  123. package/docs/architecture/diagrams/agentic-dev-plugin-architecture.html +1 -1
  124. package/docs/architecture/domains/public-surface.md +3 -5
  125. package/docs/architecture/domains/verification.md +6 -5
  126. package/docs/architecture/domains/workflow-engine.md +6 -0
  127. package/docs/architecture/modules/controller-runtime/transport-lifecycle.md +3 -3
  128. package/docs/architecture/requests/2026-09-04-computer-plugin-workflow-taxonomy.md +4 -4
  129. package/docs/architecture/reviews/20261015-code-search-runtime-acceptance.md +75 -0
  130. package/docs/forge-plugin-management.md +16 -4
  131. package/docs/operations/controller-browser-plugin.md +23 -0
  132. package/docs/operations/controller-performance-and-502.md +17 -0
  133. package/docs/operations/controller-reliability-runbook.md +2 -2
  134. package/docs/operations/features.md +6 -7
  135. package/docs/operations/features.zh-CN.md +1 -1
  136. package/docs/operations/github-repository.md +4 -4
  137. package/docs/operations/github-semantic-release-projection.md +20 -0
  138. package/docs/operations/homebrew.md +2 -2
  139. package/docs/operations/mcp-tool-exposure.md +13 -52
  140. package/docs/operations/releasing.md +2 -0
  141. package/docs/operations/runtime-performance-diagnostics.md +8 -0
  142. package/docs/operations/standalone-disaster-recovery.md +15 -7
  143. package/docs/tutorials/01-install-and-start.zh-CN.md +1 -1
  144. package/docs/tutorials/03-first-repository-task.md +2 -0
  145. package/docs/wiki/Computer-and-Plugins.md +78 -0
  146. package/docs/wiki/Computer-and-Plugins.zh-CN.md +88 -0
  147. package/docs/wiki/Home.md +16 -2
  148. package/docs/wiki/Implementation.md +25 -13
  149. package/docs/wiki/Installation.md +28 -32
  150. package/docs/wiki/Integrations.md +4 -0
  151. package/docs/wiki/Quick-Start.md +35 -22
  152. package/docs/wiki/Releases-and-Upgrades.md +15 -25
  153. package/docs/wiki/_Sidebar.md +5 -1
  154. package/package.json +25 -25
  155. package/packages/kernel/cognition/api/index.ts +6 -0
  156. package/packages/kernel/cognition/application/activation-service.ts +451 -0
  157. package/packages/kernel/cognition/application/consolidation-service.ts +185 -0
  158. package/packages/kernel/cognition/application/legacy-experience-adapter.ts +38 -0
  159. package/packages/kernel/cognition/application/memory-service.ts +64 -0
  160. package/packages/kernel/cognition/domain/learning.ts +106 -0
  161. package/packages/kernel/cognition/domain/memory.ts +254 -0
  162. package/packages/kernel/controller/api/index.ts +1 -0
  163. package/packages/kernel/controller/application/continuation-service.ts +281 -0
  164. package/packages/kernel/controller/application/controller-round-service.ts +12 -0
  165. package/packages/kernel/controller/domain/controller-round-transition-policy.ts +242 -21
  166. package/packages/kernel/controller/domain/controller-round.ts +4 -1
  167. package/packages/kernel/controller/domain/execution-quality.ts +3 -1
  168. package/packages/kernel/controller/infrastructure/controller-round-store.ts +689 -103
  169. package/packages/kernel/controller/infrastructure/controller-session-store.ts +348 -97
  170. package/packages/kernel/controller/ports/controller-host.ts +2 -0
  171. package/packages/kernel/identity/api/index.ts +10 -0
  172. package/packages/kernel/identity/domain/activity-projection.ts +43 -0
  173. package/packages/kernel/identity/domain/capability-broker.ts +60 -0
  174. package/packages/kernel/identity/domain/grant.ts +72 -0
  175. package/packages/kernel/identity/domain/owned-resource.ts +116 -0
  176. package/packages/kernel/identity/domain/user-request.ts +93 -0
  177. package/packages/kernel/identity/infrastructure/activity-projection-store.ts +87 -0
  178. package/packages/kernel/identity/infrastructure/capability-broker.ts +81 -0
  179. package/packages/kernel/identity/infrastructure/grant-store.ts +284 -0
  180. package/packages/kernel/identity/infrastructure/owned-resource-store.ts +259 -0
  181. package/packages/kernel/identity/infrastructure/user-request-store.ts +182 -0
  182. package/packages/kernel/scheduler/api/index.ts +0 -2
  183. package/packages/kernel/scheduler/application/eligibility.ts +4 -1
  184. package/packages/kernel/scheduler/application/schedule-service.ts +3 -0
  185. package/packages/kernel/scheduler/application/settlement.ts +0 -15
  186. package/packages/kernel/scheduler/domain/schedule.ts +87 -0
  187. package/packages/kernel/scheduler/infrastructure/schedule-store.ts +166 -143
  188. package/packages/kernel/work/api/index.ts +3 -2
  189. package/packages/kernel/work/application/work-service.ts +18 -42
  190. package/packages/kernel/work/domain/current-task-lineage.ts +104 -0
  191. package/packages/kernel/work/domain/engineering-design.ts +10 -5
  192. package/packages/kernel/work/domain/engineering-profile.ts +8 -12
  193. package/packages/kernel/work/domain/evaluation-promotion-receipt.ts +186 -0
  194. package/packages/kernel/work/domain/execution-concurrency.ts +19 -26
  195. package/packages/kernel/work/domain/execution-snapshot.ts +0 -31
  196. package/packages/kernel/work/domain/implementation-review.ts +14 -331
  197. package/packages/kernel/work/domain/objective-graph.ts +119 -0
  198. package/packages/kernel/work/domain/project-engineering-contract.ts +23 -1
  199. package/packages/kernel/work/domain/repository-completion-receipt.ts +1 -1
  200. package/packages/kernel/work/domain/state-machine.ts +34 -65
  201. package/packages/kernel/work/domain/types.ts +57 -51
  202. package/packages/kernel/work/infrastructure/work-contract-store.ts +847 -729
  203. package/packages/kernel/work/ports/work-contract-store.ts +5 -2
  204. package/packages/plugin-runtime/browser/provider-registry.ts +12 -36
  205. package/packages/plugin-runtime/browser/session-authority.ts +2 -1
  206. package/packages/plugin-runtime/computer/chatgpt-identity.ts +24 -0
  207. package/packages/plugin-runtime/computer/conversation-target.ts +153 -0
  208. package/packages/plugin-runtime/computer/index.ts +2 -0
  209. package/packages/plugin-runtime/computer/target-authority.ts +26 -1
  210. package/packages/plugin-runtime/external/unix-jsonl-transport.ts +142 -18
  211. package/packages/protocols/computer/contract.ts +27 -1
  212. package/scripts/activate-source-baseline.ts +7 -9
  213. package/scripts/assemble-template.ts +11 -72
  214. package/scripts/canary-controller-semantic-wait.ts +12 -24
  215. package/scripts/check-mcp-compatibility.ts +94 -201
  216. package/scripts/check-package-identity.mjs +0 -5
  217. package/scripts/check-runtime-architecture.mjs +921 -239
  218. package/scripts/forge-local-recovery-helper.mjs +93 -15
  219. package/scripts/init-project.sh +0 -46
  220. package/scripts/install-ios-hid-toolchain.sh +60 -0
  221. package/scripts/install-standalone-recovery.ts +1 -1
  222. package/scripts/lib/project-init-lib.sh +6 -3
  223. package/scripts/migrate-windows-wsl-controller-home.ts +2 -0
  224. package/scripts/open-source-audit-allowlist.txt +1 -3
  225. package/scripts/run-bounded-command.mjs +5 -0
  226. package/scripts/run-governed-gate.ts +2 -1
  227. package/scripts/run-mobile-monitor-bridge.ts +0 -1
  228. package/scripts/smoke-control-plane-failure-domain.ts +94 -0
  229. package/scripts/smoke-ios-physical-device.ts +38 -10
  230. package/scripts/smoke-mcp-http-runtime.ts +12 -8
  231. package/scripts/smoke-mcp-tool-surface.ts +27 -41
  232. package/scripts/smoke-runtime-recovery.ts +12 -43
  233. package/scripts/smoke-schedule-engine.ts +23 -15
  234. package/scripts/smoke-unattended-transport-recovery.ts +223 -0
  235. package/scripts/smoke-user-request-continuation-restart.ts +232 -0
  236. package/scripts/smoke-workflow-supervisor-chrome-adapter.ts +95 -0
  237. package/scripts/smoke-workflow-supervisor-process-restart.ts +276 -0
  238. package/scripts/smoke-workflow-supervisor-restart-recovery.ts +150 -0
  239. package/scripts/smoke-workflow-supervisor.ts +103 -0
  240. package/scripts/sync-generated-authority.mjs +0 -1
  241. package/scripts/verify-forge-runtime.sh +2 -1
  242. package/src/cli/agent-jobs/executor-health.ts +12 -35
  243. package/src/cli/agent-jobs/integration.ts +20 -51
  244. package/src/cli/agent-jobs/job-manager.ts +7 -3
  245. package/src/cli/chatgpt-browser/file-policy.ts +2 -2
  246. package/src/cli/commands/brain-assistant.ts +27 -13
  247. package/src/cli/commands/brain.ts +13 -15
  248. package/src/cli/commands/chatgpt.ts +1 -163
  249. package/src/cli/commands/doctor.ts +1 -143
  250. package/src/cli/commands/global-runtime.ts +3 -196
  251. package/src/cli/commands/init-hook.ts +6 -23
  252. package/src/cli/commands/init.ts +3 -252
  253. package/src/cli/commands/mcp.ts +0 -5
  254. package/src/cli/commands/prompt-guard-decision.ts +0 -2
  255. package/src/cli/commands/recovery.ts +137 -135
  256. package/src/cli/commands/repository.ts +17 -1
  257. package/src/cli/commands/runtime.ts +3 -3
  258. package/src/cli/commands/setup-execution.ts +41 -0
  259. package/src/cli/commands/setup-profile.ts +8 -0
  260. package/src/cli/controller/check-runner.ts +13 -2
  261. package/src/cli/controller/completion-backlog.ts +3 -3
  262. package/src/cli/controller/completion-orchestrator.ts +5 -44
  263. package/src/cli/controller/completion-target.ts +3 -72
  264. package/src/cli/controller/composite-operations.ts +1 -1
  265. package/src/cli/controller/context/instruction-context.ts +1 -1
  266. package/src/cli/controller/context/known-paths.ts +2 -2
  267. package/src/cli/controller/context/query-planning.ts +11 -4
  268. package/src/cli/controller/context/rule-resolution.ts +2 -2
  269. package/src/cli/controller/context/source-materializer.ts +83 -102
  270. package/src/cli/controller/context/structural-provider.ts +84 -0
  271. package/src/cli/controller/context/structural.ts +6 -6
  272. package/src/cli/controller/context/types.ts +8 -9
  273. package/src/cli/controller/context-pack.ts +107 -84
  274. package/src/cli/controller/execution-completion.ts +4 -7
  275. package/src/cli/controller/execution-policy.ts +36 -153
  276. package/src/cli/controller/governance.ts +2 -3
  277. package/src/cli/controller/issue-store.ts +4 -99
  278. package/src/cli/controller/launch-agents.ts +59 -18
  279. package/src/cli/controller/operational-plan.ts +25 -52
  280. package/src/cli/controller/runtime-config.ts +5 -1
  281. package/src/cli/controller/stuck-state-migration.ts +2 -3
  282. package/src/cli/controller/systemd-user.ts +42 -10
  283. package/src/cli/editing/edit-session.ts +18 -12
  284. package/src/cli/github/github.ts +4 -4
  285. package/src/cli/github/semantic-projection.ts +174 -0
  286. package/src/cli/hook/prompt-intents.ts +0 -9
  287. package/src/cli/index.ts +1 -43
  288. package/src/cli/local-bridge/connector-freshness.ts +1 -12
  289. package/src/cli/local-bridge/console-automations.ts +19 -14
  290. package/src/cli/local-bridge/console-view-models.ts +4 -13
  291. package/src/cli/local-bridge/facade-api.ts +64 -193
  292. package/src/cli/local-bridge/server.ts +24 -147
  293. package/src/cli/local-bridge/types.ts +0 -1
  294. package/src/cli/mcp/oauth-client-retirement.ts +74 -0
  295. package/src/cli/repositories/command-classifier.ts +0 -9
  296. package/src/cli/repositories/command-executor.ts +29 -23
  297. package/src/cli/repositories/command-scope.ts +37 -18
  298. package/src/cli/repositories/controller-home.ts +48 -0
  299. package/src/cli/repositories/ephemeral-workspace.ts +20 -30
  300. package/src/cli/repositories/git-command-executor.ts +2 -2
  301. package/src/cli/repositories/locks.ts +20 -0
  302. package/src/cli/repositories/registry.ts +79 -12
  303. package/src/cli/repositories/safe-patch.ts +2 -12
  304. package/src/cli/repositories/structured-git.ts +101 -5
  305. package/src/cli/repository/inspector.ts +185 -343
  306. package/src/cli/repository/session-cache.ts +92 -6
  307. package/src/effects/process-runner.ts +17 -1
  308. package/src/runtime/context/assistant-context.ts +20 -7
  309. package/src/runtime/context/assistant-work-context.ts +89 -27
  310. package/src/runtime/context/automatic-learning.ts +565 -0
  311. package/src/runtime/context/cognitive-attention.ts +173 -0
  312. package/src/runtime/context/cognitive-skill-canary.ts +158 -0
  313. package/src/runtime/context/context-closure.ts +46 -9
  314. package/src/runtime/context/context-pack-process.ts +103 -0
  315. package/src/runtime/context/context-plane.ts +1 -9
  316. package/src/runtime/context/direct-controller-learning.ts +298 -0
  317. package/src/runtime/context/generic-lsp-provider.ts +1 -1
  318. package/src/runtime/context/semantic-navigation-contract.ts +16 -0
  319. package/src/runtime/context/semantic-navigation.ts +7 -35
  320. package/src/runtime/context/typescript-navigation-process.ts +145 -0
  321. package/src/runtime/context/typescript-navigation.ts +89 -3
  322. package/src/runtime/control-plane/cleanup-artifact-retention.ts +215 -12
  323. package/src/runtime/control-plane/concurrency/work-execution-concurrency.ts +9 -47
  324. package/src/runtime/control-plane/execution/controller-authority-recovery.ts +34 -4
  325. package/src/runtime/control-plane/execution/edit-validation-coordinator.ts +29 -20
  326. package/src/runtime/control-plane/execution/execution-identity.ts +23 -3
  327. package/src/runtime/control-plane/execution/repository-work-attribution.ts +7 -30
  328. package/src/runtime/control-plane/execution/retained-work-resume.ts +206 -199
  329. package/src/runtime/control-plane/execution/session-store.ts +31 -1
  330. package/src/runtime/control-plane/execution/validation.ts +6 -8
  331. package/src/runtime/control-plane/execution/work-authority-reconciler.ts +13 -42
  332. package/src/runtime/control-plane/execution/work-check-evidence.ts +137 -0
  333. package/src/runtime/control-plane/execution/work-completion-authority.ts +30 -85
  334. package/src/runtime/control-plane/execution/work-delivery-service.ts +616 -0
  335. package/src/runtime/control-plane/execution/work-evidence-policy.ts +12 -50
  336. package/src/runtime/control-plane/execution/work-execution-support.ts +50 -149
  337. package/src/runtime/control-plane/execution/work-handle-authority.ts +197 -110
  338. package/src/runtime/control-plane/execution/work-handle-store.ts +72 -44
  339. package/src/runtime/control-plane/execution/work-head-settlement.ts +53 -20
  340. package/src/runtime/control-plane/execution/work-lifecycle-audit.ts +52 -29
  341. package/src/runtime/control-plane/execution/work-operation-service.ts +60 -34
  342. package/src/runtime/control-plane/execution/work-preparation-service.ts +231 -267
  343. package/src/runtime/control-plane/execution/work-process-evidence.ts +2 -2
  344. package/src/runtime/control-plane/execution/work-remote-delivery.ts +2 -3
  345. package/src/runtime/control-plane/execution/work-revision-diff.ts +39 -0
  346. package/src/runtime/control-plane/execution/work-terminal-cleanup.ts +201 -199
  347. package/src/runtime/control-plane/execution/work-validation-reconciler.ts +33 -85
  348. package/src/runtime/control-plane/execution/work-verification-service.ts +406 -50
  349. package/src/runtime/control-plane/execution/work-verification-snapshot.ts +6 -2
  350. package/src/runtime/control-plane/facade/capability-registry.ts +364 -37
  351. package/src/runtime/control-plane/facade/check-normalization.ts +3 -9
  352. package/src/runtime/control-plane/facade/codex-delegation.ts +10 -11
  353. package/src/runtime/control-plane/facade/controller-connection.ts +135 -0
  354. package/src/runtime/control-plane/facade/goal-workloop-access.ts +1 -20
  355. package/src/runtime/control-plane/facade/goal-workloop.ts +281 -1753
  356. package/src/runtime/control-plane/facade/handoff-inbox-application.ts +12 -25
  357. package/src/runtime/control-plane/facade/handoff-inbox-store.ts +256 -52
  358. package/src/runtime/control-plane/facade/index.ts +0 -1
  359. package/src/runtime/control-plane/facade/operation-digest.ts +12 -15
  360. package/src/runtime/control-plane/facade/plan-contract-store.ts +451 -991
  361. package/src/runtime/control-plane/facade/policy-gate.ts +0 -23
  362. package/src/runtime/control-plane/facade/repository-work-admission.ts +12 -22
  363. package/src/runtime/control-plane/facade/requirement-authority.ts +102 -199
  364. package/src/runtime/control-plane/facade/requirement-board.ts +3 -3
  365. package/src/runtime/control-plane/facade/rh-work-operation-contract.ts +51 -14
  366. package/src/runtime/control-plane/facade/self-healing-loop.ts +18 -53
  367. package/src/runtime/control-plane/facade/suggested-actions.ts +15 -18
  368. package/src/runtime/control-plane/facade/types.ts +49 -108
  369. package/src/runtime/control-plane/facade/work-continuation.ts +9 -9
  370. package/src/runtime/control-plane/generated-cache-retention.ts +206 -59
  371. package/src/runtime/control-plane/global-scheduler/autonomous-continuation.ts +248 -0
  372. package/src/runtime/control-plane/global-scheduler/durable-admission.ts +1 -1
  373. package/src/runtime/control-plane/global-scheduler/maintenance.ts +256 -117
  374. package/src/runtime/control-plane/global-scheduler/reconciliation.ts +3 -12
  375. package/src/runtime/control-plane/global-scheduler/scheduler.ts +66 -40
  376. package/src/runtime/control-plane/global-scheduler/wake-signal.ts +42 -2
  377. package/src/runtime/control-plane/governance/access-policy.ts +19 -2
  378. package/src/runtime/control-plane/governance/authorization.ts +20 -3
  379. package/src/runtime/control-plane/governance/external-effects.ts +1 -1
  380. package/src/runtime/control-plane/launcher/chatgpt-round-continuation.ts +63 -300
  381. package/src/runtime/control-plane/launcher/chatgpt-work-continuation.ts +29 -300
  382. package/src/runtime/control-plane/launcher/local-conversation-controller.ts +238 -0
  383. package/src/runtime/control-plane/launcher/provider-mcp-bootstrap.ts +5 -2
  384. package/src/runtime/control-plane/launcher/thin-launcher.ts +96 -240
  385. package/src/runtime/control-plane/persistence/cognition-store.ts +820 -0
  386. package/src/runtime/control-plane/persistence/experience-store.ts +162 -29
  387. package/src/runtime/control-plane/persistence/requirement-store.ts +216 -74
  388. package/src/runtime/control-plane/persistence/sqlite-store.ts +113 -6
  389. package/src/runtime/control-plane/release-retention.ts +135 -47
  390. package/src/runtime/control-plane/repository-namespace-retention.ts +2 -2
  391. package/src/runtime/control-plane/runtime-cleanup.ts +295 -107
  392. package/src/runtime/control-plane/workspace/project-onboarding.ts +80 -0
  393. package/src/runtime/control-plane/workspace/semantic-sync-service.ts +19 -5
  394. package/src/runtime/control-plane/workspace/workspace-store.ts +169 -0
  395. package/src/runtime/diagnostics/incident-repair.ts +313 -146
  396. package/src/runtime/diagnostics/mcp-timing.ts +114 -0
  397. package/src/runtime/evidence/artifact-store.ts +158 -40
  398. package/src/runtime/evidence/evidence-store.ts +112 -8
  399. package/src/runtime/evidence/output-handle-index.ts +225 -0
  400. package/src/runtime/evidence/result-store.ts +158 -44
  401. package/src/runtime/evidence/sensitive-output.ts +22 -2
  402. package/src/runtime/execution/jobs/child-reference.ts +11 -0
  403. package/src/runtime/execution/jobs/receipt-recovery.ts +1 -11
  404. package/src/runtime/execution/jobs/store.ts +3 -4
  405. package/src/runtime/execution/managed-workspace.ts +57 -0
  406. package/src/runtime/execution/process-runtime/check-facade.ts +1 -1
  407. package/src/runtime/execution/process-runtime/check-result-retention.ts +2 -2
  408. package/src/runtime/execution/process-runtime/check-result.ts +105 -1
  409. package/src/runtime/execution/process-runtime/check-runner-sidecar.ts +18 -8
  410. package/src/runtime/execution/process-runtime/command-facade.ts +82 -30
  411. package/src/runtime/execution/process-runtime/gc.ts +15 -2
  412. package/src/runtime/execution/process-runtime/handle-index.ts +176 -0
  413. package/src/runtime/execution/process-runtime/host-command-lane.ts +139 -0
  414. package/src/runtime/execution/process-runtime/index.ts +3 -0
  415. package/src/runtime/execution/process-runtime/lightweight-managed.ts +251 -72
  416. package/src/runtime/execution/process-runtime/persisted-check.ts +3 -3
  417. package/src/runtime/execution/process-runtime/process-runner-entry.ts +47 -5
  418. package/src/runtime/execution/process-runtime/process-scope.ts +160 -0
  419. package/src/runtime/execution/process-runtime/resource-claims.ts +65 -61
  420. package/src/runtime/execution/process-runtime/runtime.ts +55 -18
  421. package/src/runtime/execution/process-runtime/store.ts +30 -2
  422. package/src/runtime/execution/process-runtime/types.ts +6 -1
  423. package/src/runtime/execution/thin-harness/execution-router.ts +16 -16
  424. package/src/runtime/execution/thin-harness/fast-executor.ts +2 -2
  425. package/src/runtime/execution/thin-harness/search-worker.ts +2 -2
  426. package/src/runtime/execution/workers/executor.ts +3 -8
  427. package/src/runtime/maintenance/cleanup.ts +41 -5
  428. package/src/runtime/platform/service-inventory.ts +130 -0
  429. package/src/runtime/platform/service-manager.ts +8 -0
  430. package/src/runtime/plugins/action-application.ts +97 -29
  431. package/src/runtime/plugins/app-store-connect-adapter.ts +290 -18
  432. package/src/runtime/plugins/browser-adapter.ts +1124 -333
  433. package/src/runtime/plugins/browser-automation-service.ts +23 -3
  434. package/src/runtime/plugins/browser-macos-bridge.ts +431 -137
  435. package/src/runtime/plugins/browser-manifest-surface.ts +47 -12
  436. package/src/runtime/plugins/browser-native-session-service.ts +63 -13
  437. package/src/runtime/plugins/browser-registration.ts +18 -0
  438. package/src/runtime/plugins/browser-runtime.ts +40 -36
  439. package/src/runtime/plugins/browser-session-authority.ts +2 -2
  440. package/src/runtime/plugins/browser-session-store.ts +46 -76
  441. package/src/runtime/plugins/capability-authorization-grants.ts +258 -62
  442. package/src/runtime/plugins/computer-chatgpt-browser-adapter-installer.ts +228 -0
  443. package/src/runtime/plugins/computer-registration.ts +298 -20
  444. package/src/runtime/plugins/desktop-operator-external-policy.ts +36 -4
  445. package/src/runtime/plugins/desktop-operator-registration.ts +12 -4
  446. package/src/runtime/plugins/external-adapter.ts +42 -6
  447. package/src/runtime/plugins/external-registration.ts +21 -1
  448. package/src/runtime/plugins/github-adapter.ts +30 -3
  449. package/src/runtime/plugins/gmail-adapter.ts +189 -3
  450. package/src/runtime/plugins/google-calendar-adapter.ts +2 -2
  451. package/src/runtime/plugins/google-shared.ts +24 -12
  452. package/src/runtime/plugins/google-tasks-adapter.ts +2 -2
  453. package/src/runtime/plugins/ios/remote-xpc-hid.ts +70 -30
  454. package/src/runtime/plugins/ios-adapter.ts +46 -41
  455. package/src/runtime/plugins/ios-agent-device.ts +54 -4
  456. package/src/runtime/plugins/ios-device-ownership.ts +103 -0
  457. package/src/runtime/plugins/ios-physical-device.ts +497 -79
  458. package/src/runtime/plugins/lightweight-action.ts +208 -2
  459. package/src/runtime/plugins/local-system-adapter.ts +12 -100
  460. package/src/runtime/plugins/managed-process-adapter.ts +12 -5
  461. package/src/runtime/plugins/plugin-action-sidecar.ts +17 -13
  462. package/src/runtime/plugins/plugin-management-adapter.ts +1 -1
  463. package/src/runtime/plugins/store.ts +682 -435
  464. package/src/runtime/plugins/types.ts +24 -0
  465. package/src/runtime/plugins/xiaohongshu-publish.ts +16 -0
  466. package/src/runtime/projections/git-status-sampler.ts +2 -19
  467. package/src/runtime/projections/invalidation.ts +7 -3
  468. package/src/runtime/projections/materialized-view.ts +80 -36
  469. package/src/runtime/recovery/actions.ts +4 -4
  470. package/src/runtime/recovery/capability-action-application.ts +46 -45
  471. package/src/runtime/recovery/lifecycle-inventory.ts +30 -40
  472. package/src/runtime/recovery/maintenance-executor.ts +374 -123
  473. package/src/runtime/recovery/probe.ts +2 -2
  474. package/src/runtime/recovery/store.ts +29 -11
  475. package/src/runtime/release/release-coordinator.ts +312 -0
  476. package/src/runtime/release/release-session.ts +716 -0
  477. package/src/runtime/release/release-state-migration.ts +25 -0
  478. package/src/runtime/resources/leases/store.ts +56 -25
  479. package/src/runtime/root/computer-composition.ts +191 -6
  480. package/src/runtime/root/controller-progression-composition.ts +254 -0
  481. package/src/runtime/root/controller-round-composition.ts +20 -1
  482. package/src/runtime/root/deployment-topology.ts +106 -0
  483. package/src/runtime/root/entry.ts +4 -3
  484. package/src/runtime/root/known-good-recovery.ts +184 -0
  485. package/src/runtime/root/local-bridge.ts +0 -1
  486. package/src/runtime/root/mcp-transport.ts +111 -18
  487. package/src/runtime/root/ownership.ts +261 -9
  488. package/src/runtime/root/package-connector-service.ts +227 -29
  489. package/src/runtime/root/package-runtime-release.ts +117 -30
  490. package/src/runtime/root/package-runtime-service.ts +24 -24
  491. package/src/runtime/root/release-execution-canary.ts +57 -12
  492. package/src/runtime/root/release-loader.ts +90 -8
  493. package/src/runtime/root/release-manifest.ts +80 -40
  494. package/src/runtime/root/release-materialize.ts +372 -106
  495. package/src/runtime/root/release-store.ts +395 -36
  496. package/src/runtime/root/runtime-lane.ts +191 -0
  497. package/src/runtime/root/runtime.ts +160 -29
  498. package/src/runtime/root/scheduled-controller-composition.ts +29 -3
  499. package/src/runtime/root/service-runner.ts +2 -2
  500. package/src/runtime/root/service.ts +126 -44
  501. package/src/runtime/root/status.ts +48 -0
  502. package/src/runtime/root/types.ts +32 -9
  503. package/src/runtime/root/workflow-supervisor-composition.ts +681 -0
  504. package/src/runtime/root/workflow-supervisor-runtime.ts +564 -0
  505. package/src/runtime/root/write-fence.ts +50 -2
  506. package/src/runtime/safe-tooling/google-credential-store.ts +67 -22
  507. package/src/runtime/safe-tooling/google-oauth-broker.ts +25 -7
  508. package/src/runtime/safe-tooling/ios-development.ts +22 -8
  509. package/src/runtime/safe-tooling/job-summary.ts +1 -1
  510. package/src/runtime/safe-tooling/workspace-auth.ts +5 -2
  511. package/src/runtime/shared/atomic-text-file.ts +21 -0
  512. package/src/runtime/shared/bounded-child-supervisor.ts +9 -1
  513. package/src/runtime/shared/json-files.ts +8 -3
  514. package/src/runtime/shared/process-environment.ts +20 -9
  515. package/src/runtime/shared/response-budget.ts +1 -3
  516. package/src/runtime/standalone-recovery/controller-home-migration.ts +16 -24
  517. package/src/runtime/standalone-recovery/core.ts +3792 -417
  518. package/src/runtime/standalone-recovery/entry.ts +507 -45
  519. package/src/runtime/standalone-recovery/installer.ts +262 -148
  520. package/src/runtime/standalone-recovery/mcp-server.ts +29 -193
  521. package/src/runtime/standalone-recovery/operation-lock.ts +12 -2
  522. package/src/runtime/standalone-recovery/performance.ts +54 -16
  523. package/src/runtime/standalone-recovery/release.ts +53 -5
  524. package/src/runtime/standalone-recovery/service-labels.ts +5 -2
  525. package/src/runtime/standalone-recovery/watchdog-heartbeat.ts +5 -2
  526. package/src/runtime/workflow/schedules/browser-probe.ts +17 -6
  527. package/src/runtime/workflow/schedules/chatgpt-automation-migration.ts +11 -3
  528. package/src/runtime/workflow/schedules/engine.ts +166 -178
  529. package/src/runtime/workflow/schedules/pending-activation.ts +11 -4
  530. package/src/runtime/workflow/schedules/work-continuation.ts +95 -11
  531. package/src/runtime/workflows/runtime.ts +15 -19
  532. package/src/testing/test-governance.ts +5 -1
  533. package/supervisor/chatgpt-conversation.ts +23 -0
  534. package/supervisor/client.ts +218 -0
  535. package/supervisor/control-plane.ts +963 -0
  536. package/supervisor/entry.ts +15 -0
  537. package/supervisor/forge-validators.ts +147 -0
  538. package/supervisor/index.ts +5 -0
  539. package/supervisor/native-browser-adapter.ts +1151 -0
  540. package/supervisor/native-messaging/host.ts +58 -0
  541. package/supervisor/native-messaging/manifest.ts +26 -0
  542. package/supervisor/native-messaging/protocol.ts +27 -0
  543. package/supervisor/paths.ts +18 -0
  544. package/supervisor/protocol.ts +250 -0
  545. package/supervisor/server.ts +412 -0
  546. package/supervisor/store.ts +1870 -0
  547. package/supervisor/tsconfig.json +8 -0
  548. package/supervisor/types.ts +261 -0
  549. package/SKILL.md +0 -427
  550. package/adapters/chatgpt/controller-host.ts +0 -119
  551. package/adapters/mcp/controller-round-compatibility.ts +0 -184
  552. package/adapters/mcp/frozen-client-semantic-compatibility.ts +0 -292
  553. package/adapters/mcp/runtime-gateway/work-compat-adapter.ts +0 -502
  554. package/adapters/mcp/runtime-gateway/work-validation-reconciler.ts +0 -1
  555. package/adapters/mcp/toolset-selection.ts +0 -41
  556. package/agents/openai.yaml +0 -4
  557. package/assets/skill-hooks.json +0 -41
  558. package/assets/skill-version.json +0 -189
  559. package/assets/skills/claude-review/SKILL.md +0 -231
  560. package/assets/skills/codex-review/SKILL.md +0 -103
  561. package/assets/templates/helpers/check-skill-version.ts +0 -193
  562. package/packages/kernel/progression/api/index.ts +0 -2
  563. package/packages/kernel/progression/application/projector.ts +0 -211
  564. package/packages/kernel/progression/domain/types.ts +0 -116
  565. package/packages/kernel/progression/index.ts +0 -1
  566. package/packages/kernel/scheduler/application/continuation-service.ts +0 -212
  567. package/packages/kernel/scheduler/domain/continuation.ts +0 -38
  568. package/packages/kernel/scheduler/infrastructure/continuation-dispatch-store.ts +0 -38
  569. package/packages/kernel/work/domain/admission-policy.ts +0 -34
  570. package/scripts/benchmark-background-check-overlap.ts +0 -228
  571. package/scripts/benchmark-computer-hotpath.ts +0 -255
  572. package/scripts/benchmark-controller-hotpath.ts +0 -212
  573. package/scripts/benchmark-controller-round2.ts +0 -191
  574. package/scripts/benchmark-ios-agent-device.ts +0 -511
  575. package/scripts/benchmark-mcp-host.sh +0 -117
  576. package/scripts/benchmark-mcp-transport.ts +0 -169
  577. package/scripts/benchmark-operational-memory-activation.ts +0 -235
  578. package/scripts/benchmark-operational-shadow.ts +0 -28
  579. package/scripts/benchmark-quality-harness.ts +0 -146
  580. package/scripts/benchmark-route-session-concurrency.ts +0 -915
  581. package/scripts/benchmark-thin-harness-gateway-ab.ts +0 -632
  582. package/scripts/benchmark-thin-harness-mcp-e2e.ts +0 -498
  583. package/scripts/benchmark-thin-harness.ts +0 -251
  584. package/scripts/benchmark-typescript-navigation.ts +0 -186
  585. package/scripts/benchmark-work-efficiency.ts +0 -334
  586. package/scripts/build-controller-ui.ts +0 -28
  587. package/scripts/check-npm-release.sh +0 -32
  588. package/scripts/check-public-release-surface.sh +0 -19
  589. package/scripts/check-release-published.sh +0 -57
  590. package/scripts/check-release-readiness.sh +0 -37
  591. package/scripts/check-release-version.mjs +0 -74
  592. package/scripts/check-skill-version.ts +0 -5
  593. package/scripts/check-tarball-install-smoke.sh +0 -150
  594. package/scripts/ensure-codegraph.sh +0 -16
  595. package/scripts/package-source-archive.sh +0 -147
  596. package/scripts/public-release-files.txt +0 -39
  597. package/scripts/public-release.ts +0 -174
  598. package/scripts/publish-release-tarball.sh +0 -27
  599. package/scripts/route-nl-vs-ts-eval.ts +0 -679
  600. package/scripts/run-skill-hook.ts +0 -244
  601. package/scripts/stage-runtime-release.ts +0 -44
  602. package/scripts/sync-codex-installed-copies.sh +0 -182
  603. package/src/cli/commands/tools.ts +0 -167
  604. package/src/cli/controller/progress.ts +0 -656
  605. package/src/cli/controller/work-mode.ts +0 -181
  606. package/src/cli/local-bridge/console-assets.ts +0 -17
  607. package/src/cli/local-bridge/dashboard.ts +0 -17
  608. package/src/cli/local-bridge/frontend/src/App.tsx +0 -10
  609. package/src/cli/local-bridge/frontend/src/components/Button.tsx +0 -1
  610. package/src/cli/local-bridge/frontend/src/components/DetailPane.tsx +0 -3
  611. package/src/cli/local-bridge/frontend/src/components/SearchField.tsx +0 -1
  612. package/src/cli/local-bridge/frontend/src/components/SectionHeader.tsx +0 -1
  613. package/src/cli/local-bridge/frontend/src/components/Segmented.tsx +0 -1
  614. package/src/cli/local-bridge/frontend/src/components/StatusText.tsx +0 -3
  615. package/src/cli/local-bridge/frontend/src/design/icons.tsx +0 -11
  616. package/src/cli/local-bridge/frontend/src/design/tokens.css +0 -8
  617. package/src/cli/local-bridge/frontend/src/features/automations/AutomationsView.tsx +0 -153
  618. package/src/cli/local-bridge/frontend/src/features/capabilities/CapabilitiesView.tsx +0 -37
  619. package/src/cli/local-bridge/frontend/src/features/overview/OverviewView.tsx +0 -183
  620. package/src/cli/local-bridge/frontend/src/features/repositories/RepositoriesView.tsx +0 -2
  621. package/src/cli/local-bridge/frontend/src/features/system/SystemView.tsx +0 -2
  622. package/src/cli/local-bridge/frontend/src/features/work/WorkView.tsx +0 -4
  623. package/src/cli/local-bridge/frontend/src/lib/api.ts +0 -30
  624. package/src/cli/local-bridge/frontend/src/lib/format.ts +0 -4
  625. package/src/cli/local-bridge/frontend/src/lib/routes.ts +0 -7
  626. package/src/cli/local-bridge/frontend/src/main.tsx +0 -1
  627. package/src/cli/local-bridge/frontend/src/shell/AppShell.tsx +0 -1
  628. package/src/cli/local-bridge/frontend/src/shell/CommandBar.tsx +0 -2
  629. package/src/cli/local-bridge/frontend/src/shell/Sidebar.tsx +0 -4
  630. package/src/cli/local-bridge/frontend/src/styles.css +0 -28
  631. package/src/cli/local-bridge/frontend/src/types.ts +0 -15
  632. package/src/cli/local-bridge/frontend/src/vite-env.d.ts +0 -1
  633. package/src/cli/local-bridge/frontend/vite.config.ts +0 -27
  634. package/src/cli/local-bridge/ui-dist/app.css +0 -1
  635. package/src/cli/local-bridge/ui-dist/app.js +0 -11228
  636. package/src/cli/mcp/access-mode.ts +0 -2
  637. package/src/cli/mcp/access-tools.ts +0 -2
  638. package/src/cli/mcp/audit.ts +0 -2
  639. package/src/cli/mcp/auth.ts +0 -2
  640. package/src/cli/mcp/instructions.ts +0 -2
  641. package/src/cli/mcp/legacy-context.ts +0 -2
  642. package/src/cli/mcp/legacy-tool-service.ts +0 -2
  643. package/src/cli/mcp/multi-repository.ts +0 -2
  644. package/src/cli/mcp/oauth.ts +0 -2
  645. package/src/cli/mcp/openai-secure-tunnel.ts +0 -2
  646. package/src/cli/mcp/paths.ts +0 -2
  647. package/src/cli/mcp/policy.ts +0 -2
  648. package/src/cli/mcp/post-finalize-work-attribution.ts +0 -2
  649. package/src/cli/mcp/proxy-env.ts +0 -2
  650. package/src/cli/mcp/readiness-projection.ts +0 -2
  651. package/src/cli/mcp/redaction.ts +0 -2
  652. package/src/cli/mcp/repo.ts +0 -2
  653. package/src/cli/mcp/repository-tools.ts +0 -2
  654. package/src/cli/mcp/server.ts +0 -2
  655. package/src/cli/mcp/setup.ts +0 -2
  656. package/src/cli/mcp/tool-capability-cache.ts +0 -2
  657. package/src/cli/mcp/tool-contract.ts +0 -2
  658. package/src/cli/mcp/tools.ts +0 -2
  659. package/src/cli/mcp/toolset-names.ts +0 -2
  660. package/src/cli/mcp/toolset-selection.ts +0 -2
  661. package/src/cli/mcp/toolset.ts +0 -2
  662. package/src/cli/mcp/transports/http.ts +0 -2
  663. package/src/cli/mcp/transports/session-registry.ts +0 -2
  664. package/src/cli/mcp/transports/stdio.ts +0 -2
  665. package/src/cli/mcp/types.ts +0 -2
  666. package/src/cli/mcp/umbrella-tools.ts +0 -2
  667. package/src/cli/tools/codegraph.ts +0 -695
  668. package/src/core/adoption/helper-wrapper-plan.ts +0 -159
  669. package/src/runtime/context/codegraph-cache-boundary.ts +0 -255
  670. package/src/runtime/context/codegraph-read-provider.ts +0 -611
  671. package/src/runtime/context/codegraph-sidecar.cjs +0 -248
  672. package/src/runtime/control-plane/codegraph-cache-retention.ts +0 -164
  673. package/src/runtime/control-plane/execution/content-equivalent-commit-authority.ts +0 -169
  674. package/src/runtime/control-plane/execution/direct-canonical-work-reconciliation.ts +0 -85
  675. package/src/runtime/control-plane/execution/direct-edit-work-completion.ts +0 -655
  676. package/src/runtime/control-plane/execution/work-finalization-service.ts +0 -2850
  677. package/src/runtime/control-plane/execution/work-path-scope.ts +0 -37
  678. package/src/runtime/control-plane/execution/work-task-receipt.ts +0 -468
  679. package/src/runtime/control-plane/facade/controller-round-relay.ts +0 -3
  680. package/src/runtime/control-plane/facade/work-admission-policy.ts +0 -142
  681. package/src/runtime/control-plane/facade/work-implementation-review.ts +0 -2
  682. package/src/runtime/control-plane/facade/work-state-machine.ts +0 -2
  683. package/src/runtime/control-plane/facade/work-task-projection.ts +0 -66
  684. package/src/runtime/control-plane/routing/index.ts +0 -1
  685. package/src/runtime/control-plane/routing/route-policy.ts +0 -401
  686. package/src/runtime/control-plane/routing/workspace-admission.ts +0 -70
  687. package/src/runtime/gateway/mcp/execution-tools.ts +0 -2
  688. package/src/runtime/gateway/mcp/legacy-ios-tool-adapter.ts +0 -2
  689. package/src/runtime/gateway/mcp/persisted-check-process.ts +0 -2
  690. package/src/runtime/gateway/mcp/process-tools.ts +0 -2
  691. package/src/runtime/gateway/mcp/router.ts +0 -2
  692. package/src/runtime/gateway/mcp/runtime-tool-definitions.ts +0 -2
  693. package/src/runtime/gateway/mcp/runtime-tools.ts +0 -2
  694. package/src/runtime/gateway/mcp/work-validation-reconciler.ts +0 -2
  695. package/src/runtime/plugins/browser-provider-registry.ts +0 -2
@@ -0,0 +1,708 @@
1
+ import { randomUUID } from 'node:crypto';
2
+ import type {
3
+ ComputerChatgptBootstrapIdentity,
4
+ ComputerChatgptConversationIdentity,
5
+ ComputerChatgptConversationInventory,
6
+ ComputerChatgptConversationObservation,
7
+ ComputerChatgptConversationObservationOptions,
8
+ ComputerChatgptConversationTarget,
9
+ ComputerChatgptConversationTargetPort,
10
+ ComputerChatgptExtensionBrokerRpc,
11
+ ComputerChatgptExtensionCommand,
12
+ ComputerChatgptExtensionCommandInput,
13
+ ComputerChatgptExtensionCommandResult,
14
+ ComputerChatgptExtensionHeartbeat,
15
+ ComputerChatgptTargetIdentity,
16
+ ComputerChatgptTargetResult,
17
+ ComputerInteractionTargetAuthorityPort,
18
+ ComputerSurfaceProviderBinding,
19
+ ComputerSurfaceTarget,
20
+ } from '../../packages/plugin-runtime/computer';
21
+
22
+ const PROVIDER_ID = 'browser.chrome-extension';
23
+ const HEARTBEAT_FRESH_MS = 15_000;
24
+ const COMMAND_TIMEOUT_MS = 12_000;
25
+
26
+ type ProviderState = {
27
+ receivedAtMs: number;
28
+ heartbeat: ComputerChatgptExtensionHeartbeat;
29
+ };
30
+
31
+ type PendingCommand = {
32
+ providerInstanceId: string;
33
+ command: ComputerChatgptExtensionCommand;
34
+ claimed: boolean;
35
+ resolve: (value: { claimed: boolean; result?: ComputerChatgptExtensionCommandResult }) => void;
36
+ timer: ReturnType<typeof setTimeout>;
37
+ };
38
+
39
+ function stableIdentity(identity: ComputerChatgptTargetIdentity) {
40
+ return {
41
+ surfaceType: 'browser-tab' as const,
42
+ ownership: 'provider_owned' as const,
43
+ resource: identity.namespace === 'chatgpt.conversation'
44
+ ? { namespace: identity.namespace, key: identity.conversationId }
45
+ : { namespace: identity.namespace, key: identity.bootstrapKey },
46
+ };
47
+ }
48
+
49
+ function alias(identity: ComputerChatgptTargetIdentity): string {
50
+ return identity.namespace === 'chatgpt.conversation'
51
+ ? `chatgpt:conversation:${identity.conversationId}`
52
+ : `chatgpt:bootstrap:${identity.bootstrapKey}`;
53
+ }
54
+
55
+ function providerInstanceId(value: unknown): string | undefined {
56
+ if (typeof value !== 'string') return undefined;
57
+ const normalized = value.trim();
58
+ return normalized && normalized.length <= 256 ? normalized : undefined;
59
+ }
60
+
61
+ function conversationContentAvailable(observation: ComputerChatgptConversationObservation): boolean {
62
+ // A matching URL is not enough: an extension can observe the navigation
63
+ // shell before ChatGPT hydrates the conversation, or after the browser has
64
+ // lost the content script. Treat that as transport-unavailable so the
65
+ // preferred target router can try the native browser attachment without
66
+ // sending anything through the empty surface.
67
+ return observation.composerText !== undefined || observation.isGenerating
68
+ || Boolean(observation.latestUserText.trim() || observation.latestAssistantResponse.trim() || observation.providerActivityText.trim());
69
+ }
70
+
71
+ function failure(code: string, input: { retryable?: boolean; failoverSafe?: boolean; humanAction?: 'login' | 'grant_permission' } = {}): ComputerChatgptTargetResult {
72
+ return {
73
+ state: 'unavailable',
74
+ failure: {
75
+ code,
76
+ retryable: input.retryable !== false,
77
+ phase: 'pre_mutation',
78
+ ...(input.failoverSafe === undefined ? {} : { failoverSafe: input.failoverSafe }),
79
+ ...(input.humanAction ? { humanAction: input.humanAction } : {}),
80
+ },
81
+ };
82
+ }
83
+
84
+ function normalizeBinding(binding: ComputerSurfaceProviderBinding | undefined, instanceId?: string): ComputerSurfaceProviderBinding | undefined {
85
+ if (!binding) return undefined;
86
+ if (binding.providerId !== PROVIDER_ID || !binding.windowId || !binding.tabId) return undefined;
87
+ const bindingInstanceId = providerInstanceId(binding.providerSessionId);
88
+ if (instanceId && bindingInstanceId && bindingInstanceId !== instanceId) return undefined;
89
+ return {
90
+ providerId: PROVIDER_ID,
91
+ observedAt: binding.observedAt || new Date().toISOString(),
92
+ ...(instanceId || bindingInstanceId ? { providerSessionId: instanceId ?? bindingInstanceId } : {}),
93
+ ...(binding.browserProduct ? { browserProduct: binding.browserProduct } : {}),
94
+ windowId: String(binding.windowId),
95
+ tabId: String(binding.tabId),
96
+ ...(binding.ownerToken ? { ownerToken: binding.ownerToken } : {}),
97
+ };
98
+ }
99
+
100
+ export class ChromeExtensionChatgptConversationTargetPort
101
+ implements ComputerChatgptConversationTargetPort, ComputerChatgptExtensionBrokerRpc {
102
+ private readonly providerStates = new Map<string, ProviderState>();
103
+ private readonly pending = new Map<string, PendingCommand>();
104
+ private readonly queues = new Map<string, string[]>();
105
+ // Process-local physical-operation singleflight, not a second tab lifecycle
106
+ // authority. Exact Surface binding/CAS remains the only durable owner.
107
+ private readonly retiring = new Map<string, Promise<boolean>>();
108
+
109
+ constructor(
110
+ private readonly controllerHome: string,
111
+ private readonly authority: ComputerInteractionTargetAuthorityPort,
112
+ private readonly nowMs: () => number = () => Date.now(),
113
+ ) {}
114
+
115
+ heartbeat(input: ComputerChatgptExtensionHeartbeat): void {
116
+ if (input.providerId !== PROVIDER_ID) throw new Error('COMPUTER_CHATGPT_EXTENSION_PROVIDER_ID_INVALID');
117
+ const instanceId = providerInstanceId(input.providerInstanceId);
118
+ if (!instanceId) throw new Error('COMPUTER_CHATGPT_EXTENSION_PROVIDER_INSTANCE_REQUIRED');
119
+ const conversations = Array.isArray(input.conversations)
120
+ ? input.conversations.flatMap((entry) => {
121
+ if (!entry || typeof entry.conversationId !== 'string' || !entry.conversationId.trim() || typeof entry.canonicalUrl !== 'string' || !entry.canonicalUrl.trim()) return [];
122
+ const binding = normalizeBinding(entry.providerBinding, instanceId);
123
+ return [{
124
+ conversationId: entry.conversationId.trim(),
125
+ canonicalUrl: entry.canonicalUrl.trim(),
126
+ ...(entry.title ? { title: String(entry.title).slice(0, 512) } : {}),
127
+ ...(entry.projectTitle ? { projectTitle: String(entry.projectTitle).slice(0, 512) } : {}),
128
+ ...(entry.projectUrl ? { projectUrl: String(entry.projectUrl) } : {}),
129
+ ...(entry.isCurrent ? { isCurrent: true } : {}),
130
+ ...(binding ? { providerBinding: binding } : {}),
131
+ }];
132
+ })
133
+ : [];
134
+ this.providerStates.set(instanceId, {
135
+ receivedAtMs: this.nowMs(),
136
+ heartbeat: {
137
+ providerId: PROVIDER_ID,
138
+ providerInstanceId: instanceId,
139
+ observedAt: typeof input.observedAt === 'string' && input.observedAt ? input.observedAt : new Date(this.nowMs()).toISOString(),
140
+ conversations,
141
+ },
142
+ });
143
+ }
144
+
145
+ claim(rawProviderInstanceId: string): ComputerChatgptExtensionCommand | undefined {
146
+ const instanceId = providerInstanceId(rawProviderInstanceId);
147
+ if (!instanceId) return undefined;
148
+ const queue = this.queues.get(instanceId);
149
+ while (queue && queue.length > 0) {
150
+ const id = queue.shift()!;
151
+ const entry = this.pending.get(id);
152
+ if (!entry || entry.providerInstanceId !== instanceId || entry.claimed) continue;
153
+ entry.claimed = true;
154
+ return structuredClone(entry.command);
155
+ }
156
+ if (queue?.length === 0) this.queues.delete(instanceId);
157
+ return undefined;
158
+ }
159
+
160
+ complete(rawProviderInstanceId: string, commandId: string, result: ComputerChatgptExtensionCommandResult): boolean {
161
+ const instanceId = providerInstanceId(rawProviderInstanceId);
162
+ const entry = this.pending.get(commandId);
163
+ if (!instanceId || !entry || entry.providerInstanceId !== instanceId || !entry.claimed) return false;
164
+ clearTimeout(entry.timer);
165
+ this.pending.delete(commandId);
166
+ entry.resolve({ claimed: true, result: structuredClone(result) });
167
+ return true;
168
+ }
169
+
170
+ private freshProviders(): Array<[string, ProviderState]> {
171
+ const now = this.nowMs();
172
+ const fresh: Array<[string, ProviderState]> = [];
173
+ for (const [instanceId, state] of this.providerStates) {
174
+ if (now - state.receivedAtMs > HEARTBEAT_FRESH_MS) {
175
+ this.providerStates.delete(instanceId);
176
+ continue;
177
+ }
178
+ fresh.push([instanceId, state]);
179
+ }
180
+ return fresh.sort(([left], [right]) => left.localeCompare(right));
181
+ }
182
+
183
+ private providerIsFresh(instanceId: string): boolean {
184
+ return this.freshProviders().some(([candidate]) => candidate === instanceId);
185
+ }
186
+
187
+ private selectProviderInstance(preferredInstanceId?: string): { instanceId?: string; ambiguous: boolean } {
188
+ const fresh = this.freshProviders();
189
+ if (preferredInstanceId) {
190
+ // A disconnected profile is unavailable, not permission to switch to
191
+ // the only other signed-in (or signed-out) Chrome instance.
192
+ return { ...(fresh.some(([instanceId]) => instanceId === preferredInstanceId)
193
+ ? { instanceId: preferredInstanceId } : {}), ambiguous: false };
194
+ }
195
+ // Foreground tab is not a durable browser-principal binding. If more
196
+ // than one Extension instance is connected, require a known pin instead
197
+ // of guessing which profile should receive a new Supervisor effect.
198
+ if (fresh.length === 1) return { instanceId: fresh[0]![0], ambiguous: false };
199
+ return { ambiguous: fresh.length > 1 };
200
+ }
201
+
202
+ private preferredProviderInstance(identity: ComputerChatgptTargetIdentity): string | undefined {
203
+ const existing = this.authority.findSurfaceByStableIdentity(this.controllerHome, stableIdentity(identity));
204
+ const binding = existing?.providerBinding;
205
+ if (binding?.providerId !== PROVIDER_ID) return undefined;
206
+ return providerInstanceId(binding.providerSessionId);
207
+ }
208
+
209
+ private async submit(providerInstanceId: string, command: ComputerChatgptExtensionCommandInput): Promise<{ claimed: boolean; result?: ComputerChatgptExtensionCommandResult }> {
210
+ const commandId = `computer-extension-${randomUUID()}`;
211
+ return await new Promise((resolve) => {
212
+ const timer = setTimeout(() => {
213
+ const current = this.pending.get(commandId);
214
+ if (!current) return;
215
+ this.pending.delete(commandId);
216
+ resolve({ claimed: current.claimed });
217
+ }, COMMAND_TIMEOUT_MS);
218
+ timer.unref?.();
219
+ const full = { ...command, commandId } as ComputerChatgptExtensionCommand;
220
+ this.pending.set(commandId, { providerInstanceId, command: full, claimed: false, resolve, timer });
221
+ const queue = this.queues.get(providerInstanceId) ?? [];
222
+ queue.push(commandId);
223
+ this.queues.set(providerInstanceId, queue);
224
+ });
225
+ }
226
+
227
+ private upsert(identity: ComputerChatgptTargetIdentity, binding?: ComputerSurfaceProviderBinding): ComputerSurfaceTarget {
228
+ return this.authority.upsertSurface(this.controllerHome, {
229
+ stableIdentity: stableIdentity(identity),
230
+ compatibilityAliases: [alias(identity)],
231
+ visibility: 'controller',
232
+ ...(binding ? { providerBinding: binding } : {}),
233
+ compatibilityRecords: [{
234
+ namespace: 'chatgpt.target',
235
+ schemaVersion: 1,
236
+ value: identity.namespace === 'chatgpt.conversation'
237
+ ? { namespace: identity.namespace, conversationId: identity.conversationId, canonicalUrl: identity.canonicalUrl }
238
+ : { namespace: identity.namespace, bootstrapKey: identity.bootstrapKey, projectUrl: identity.projectUrl },
239
+ updatedAt: new Date(this.nowMs()).toISOString(),
240
+ }],
241
+ reactivate: true,
242
+ }).target;
243
+ }
244
+
245
+ private async bindAsync(identity: ComputerChatgptTargetIdentity, binding: ComputerSurfaceProviderBinding | undefined, instanceId: string): Promise<ComputerSurfaceTarget> {
246
+ const record = this.upsert(identity);
247
+ const normalized = normalizeBinding(binding, instanceId);
248
+ if (!normalized) return record;
249
+ return await this.authority.withSurfaceLease(this.controllerHome, record.targetId, async (lease) => {
250
+ const previous = lease.current().providerBinding;
251
+ // Heartbeat inventory omits the Forge-create token. Carry it forward only
252
+ // for the same exact physical attachment; never transfer it to a new tab.
253
+ const sameAttachment = previous?.providerId === normalized.providerId
254
+ && previous.providerSessionId === normalized.providerSessionId
255
+ && previous.browserProduct === normalized.browserProduct
256
+ && previous.windowId === normalized.windowId
257
+ && previous.tabId === normalized.tabId;
258
+ return lease.bind({
259
+ ...normalized,
260
+ ...(normalized.ownerToken ? {} : sameAttachment && previous?.ownerToken ? { ownerToken: previous.ownerToken } : {}),
261
+ });
262
+ });
263
+ }
264
+
265
+ private target(identity: ComputerChatgptTargetIdentity, record: ComputerSurfaceTarget, instanceId: string): ComputerChatgptConversationTarget {
266
+ return {
267
+ targetId: record.targetId,
268
+ identity,
269
+ observe: async (options) => {
270
+ const response = await this.submit(instanceId, { kind: 'observe', identity, ...(record.providerBinding ? { providerBinding: record.providerBinding } : {}), ...(options ? { options } : {}) });
271
+ if (!response.result) throw new Error(response.claimed ? 'COMPUTER_CHATGPT_EXTENSION_OBSERVATION_OUTCOME_UNKNOWN' : 'COMPUTER_CHATGPT_EXTENSION_NOT_CONNECTED');
272
+ if (response.result.kind === 'observation') {
273
+ if (response.result.providerBinding) {
274
+ const observed = normalizeBinding(response.result.providerBinding, instanceId);
275
+ const saved = this.authority.getSurface(this.controllerHome, record.targetId)?.providerBinding;
276
+ // A newer observedAt is not a new physical binding. Normal reads
277
+ // must not rewrite the Surface and its binding indexes on every poll.
278
+ if (!observed || !saved || saved.providerId !== observed.providerId
279
+ || saved.providerSessionId !== observed.providerSessionId
280
+ || saved.browserProduct !== observed.browserProduct
281
+ || saved.windowId !== observed.windowId || saved.tabId !== observed.tabId
282
+ || (observed.ownerToken && saved.ownerToken !== observed.ownerToken)) {
283
+ await this.bindAsync(identity, response.result.providerBinding, instanceId);
284
+ }
285
+ }
286
+ return response.result.observation;
287
+ }
288
+ if (response.result.kind === 'failed') throw new Error(response.result.code);
289
+ throw new Error('COMPUTER_CHATGPT_EXTENSION_OBSERVATION_INVALID');
290
+ },
291
+ prepare: async (prompt, options) => {
292
+ const response = await this.submit(instanceId, { kind: 'prepare', identity, ...(record.providerBinding ? { providerBinding: record.providerBinding } : {}), prompt,
293
+ ...(options?.mode ? { mode: options.mode } : {}),
294
+ });
295
+ if (!response.result) return { ready: false, reasonCode: response.claimed
296
+ ? 'COMPUTER_CHATGPT_EXTENSION_PREPARE_OUTCOME_UNKNOWN' : 'COMPUTER_CHATGPT_EXTENSION_NOT_CONNECTED' };
297
+ if (response.result.kind === 'prepared') {
298
+ if (!response.result.ready) return { ready: false, reasonCode: response.result.reasonCode };
299
+ return { ready: true };
300
+ }
301
+ return { ready: false, reasonCode: response.result.kind === 'failed'
302
+ ? response.result.code : 'COMPUTER_CHATGPT_EXTENSION_PREPARE_INVALID' };
303
+ },
304
+ dispatch: async (prompt, options) => {
305
+ const response = await this.submit(instanceId, { kind: 'dispatch', identity, ...(record.providerBinding ? { providerBinding: record.providerBinding } : {}), prompt, ...(options?.mode ? { mode: options.mode } : {}) });
306
+ if (!response.result) {
307
+ return response.claimed
308
+ ? { mutation: 'attempted' as const }
309
+ : { mutation: 'not_attempted' as const, reasonCode: 'COMPUTER_CHATGPT_EXTENSION_NOT_CONNECTED' };
310
+ }
311
+ if (response.result.kind === 'dispatch') {
312
+ if (response.result.mutation === 'attempted') return { mutation: 'attempted' as const, ...(response.result.confirmed === undefined ? {} : { confirmed: response.result.confirmed }) };
313
+ if (response.result.mutation === 'not_attempted') return { mutation: 'not_attempted' as const, reasonCode: response.result.reasonCode };
314
+ }
315
+ // Only a typed dispatch/not_attempted result proves no Send click. A
316
+ // generic failure or wrong response kind cannot authorize another send.
317
+ return { mutation: 'attempted' as const, confirmed: false };
318
+ },
319
+ };
320
+ }
321
+
322
+ async inventory(): Promise<ComputerChatgptConversationInventory> {
323
+ const fresh = this.freshProviders();
324
+ if (fresh.length === 0) return { conversations: [], complete: false, unavailableProviders: [PROVIDER_ID] };
325
+ const byConversationId = new Map<string, ComputerChatgptConversationInventory['conversations'][number]>();
326
+ for (const [, state] of fresh) {
327
+ for (const { providerBinding: _binding, ...entry } of state.heartbeat.conversations) {
328
+ const previous = byConversationId.get(entry.conversationId);
329
+ if (!previous || entry.isCurrent) byConversationId.set(entry.conversationId, entry);
330
+ }
331
+ }
332
+ return { conversations: [...byConversationId.values()], complete: true, unavailableProviders: [] };
333
+ }
334
+
335
+ async ensureExact(identity: ComputerChatgptConversationIdentity, options: { createIfMissing?: boolean } = {}): Promise<ComputerChatgptTargetResult> {
336
+ const preferredInstanceId = this.preferredProviderInstance(identity);
337
+ const fresh = this.freshProviders();
338
+ if (fresh.length === 0 || (preferredInstanceId && !fresh.some(([instanceId]) => instanceId === preferredInstanceId))) {
339
+ return failure('COMPUTER_CHATGPT_EXTENSION_NOT_CONNECTED', { failoverSafe: !preferredInstanceId });
340
+ }
341
+ const exact = fresh.filter(([instanceId]) => !preferredInstanceId || instanceId === preferredInstanceId)
342
+ .flatMap(([instanceId, state]) => state.heartbeat.conversations
343
+ .filter((entry) => entry.conversationId === identity.conversationId)
344
+ .map((entry) => ({ instanceId, entry })));
345
+ // Multiple tabs can show one conversation. Prefer the existing exact
346
+ // Computer binding over heartbeat focus or an arbitrary matching tab.
347
+ const binding = this.authority.findSurfaceByStableIdentity(this.controllerHome, stableIdentity(identity))?.providerBinding;
348
+ let candidates = exact;
349
+ if (binding?.providerId === PROVIDER_ID && binding.windowId && binding.tabId) {
350
+ const bound = exact.filter(({ instanceId, entry }) => instanceId === binding.providerSessionId
351
+ && entry.providerBinding?.tabId === binding.tabId
352
+ && (!binding.browserProduct || entry.providerBinding?.browserProduct === binding.browserProduct));
353
+ // Chrome restart replaces physical tab IDs, not the profile principal or
354
+ // conversation identity. A unique exact tab observed by that SAME live
355
+ // provider may replace an absent pin through the Surface lease below.
356
+ // Never choose between multiple matching tabs or switch browser profiles.
357
+ const replacement = exact.length === 1 && exact[0]!.instanceId === binding.providerSessionId
358
+ && (!binding.browserProduct || exact[0]!.entry.providerBinding?.browserProduct === binding.browserProduct)
359
+ ? exact : [];
360
+ candidates = bound.length ? bound : replacement;
361
+ }
362
+ // A stale binding must not turn two observed exact tabs into a third tab.
363
+ if (exact.length > 1 && candidates.length !== 1) return failure('COMPUTER_CHATGPT_EXTENSION_EXACT_TARGET_AMBIGUOUS', { failoverSafe: false });
364
+ if (candidates.length === 1) {
365
+ const candidate = candidates[0]!;
366
+ if (!candidate.entry.providerBinding) return failure('COMPUTER_CHATGPT_EXTENSION_PHYSICAL_TAB_UNVERIFIED', { failoverSafe: false });
367
+ const record = await this.bindAsync(identity, candidate.entry.providerBinding, candidate.instanceId);
368
+ const target = this.target(identity, record, candidate.instanceId);
369
+ try {
370
+ const observation = await target.observe({ includeUserHistory: false, includePageText: false });
371
+ if (!conversationContentAvailable(observation)) {
372
+ return failure('COMPUTER_CHATGPT_CONVERSATION_CONTENT_UNAVAILABLE', { failoverSafe: false });
373
+ }
374
+ return { state: 'ready', target, observation };
375
+ } catch (error) {
376
+ return failure(
377
+ error instanceof Error && error.message.trim()
378
+ ? error.message.trim()
379
+ : 'COMPUTER_CHATGPT_EXTENSION_OBSERVATION_UNAVAILABLE',
380
+ { failoverSafe: false },
381
+ );
382
+ }
383
+ }
384
+ // A heartbeat is an inventory hint, not the exact-target authority.
385
+ // When it has no match, let the SAME live Chrome instance perform one
386
+ // read-only physical-tab lookup. This does not create a tab or replay Send;
387
+ // the provider refuses ambiguous matches and drifted pinned tabs.
388
+ if (options.createIfMissing === false) {
389
+ const selected = this.selectProviderInstance(preferredInstanceId);
390
+ if (!selected.instanceId) return failure(
391
+ selected.ambiguous ? 'COMPUTER_CHATGPT_EXTENSION_PROVIDER_INSTANCE_AMBIGUOUS' : 'COMPUTER_CHATGPT_EXTENSION_NOT_CONNECTED',
392
+ { failoverSafe: false },
393
+ );
394
+ const response = await this.submit(selected.instanceId, { kind: 'observe', identity,
395
+ ...(binding?.providerId === PROVIDER_ID ? { providerBinding: binding } : {}),
396
+ options: { includeUserHistory: false, includePageText: false },
397
+ });
398
+ if (!response.result) return failure('COMPUTER_CHATGPT_EXTENSION_OBSERVATION_UNAVAILABLE', { failoverSafe: false });
399
+ if (response.result.kind === 'observation') {
400
+ const { observation, providerBinding } = response.result;
401
+ let exactUrl = false;
402
+ try {
403
+ const parsed = new URL(observation.url);
404
+ exactUrl = parsed.origin === 'https://chatgpt.com'
405
+ && parsed.pathname.endsWith(`/c/${identity.conversationId}`);
406
+ } catch { /* Never bind an unparseable or changed conversation target. */ }
407
+ if (!exactUrl || !providerBinding) return failure('COMPUTER_CHATGPT_EXTENSION_TARGET_IDENTITY_UNVERIFIED', { failoverSafe: false });
408
+ if (!conversationContentAvailable(observation)) return failure('COMPUTER_CHATGPT_CONVERSATION_CONTENT_UNAVAILABLE', { failoverSafe: false });
409
+ const record = await this.bindAsync(identity, providerBinding, selected.instanceId);
410
+ return { state: 'ready', target: this.target(identity, record, selected.instanceId), observation };
411
+ }
412
+ return failure(response.result.kind === 'failed'
413
+ ? response.result.code === 'COMPUTER_CHATGPT_EXTENSION_TARGET_MISSING'
414
+ ? 'COMPUTER_CHATGPT_EXTENSION_EXACT_TARGET_ABSENT_READ_ONLY'
415
+ : response.result.code
416
+ : 'COMPUTER_CHATGPT_EXTENSION_OBSERVATION_INVALID', { failoverSafe: false });
417
+ }
418
+ const selected = this.selectProviderInstance(preferredInstanceId);
419
+ if (!selected.instanceId) {
420
+ return failure(
421
+ selected.ambiguous ? 'COMPUTER_CHATGPT_EXTENSION_PROVIDER_INSTANCE_AMBIGUOUS' : 'COMPUTER_CHATGPT_EXTENSION_NOT_CONNECTED',
422
+ { failoverSafe: !selected.ambiguous && !preferredInstanceId },
423
+ );
424
+ }
425
+ const previous = this.authority.findSurfaceByStableIdentity(this.controllerHome, stableIdentity(identity));
426
+ const response = await this.submit(selected.instanceId, { kind: 'ensure', identity,
427
+ ...(previous?.providerBinding?.providerId === PROVIDER_ID ? { providerBinding: previous.providerBinding } : {}),
428
+ });
429
+ if (!response.result) return failure(
430
+ response.claimed ? 'COMPUTER_CHATGPT_EXTENSION_TARGET_OPEN_OUTCOME_UNKNOWN' : 'COMPUTER_CHATGPT_EXTENSION_NOT_CONNECTED',
431
+ { failoverSafe: !response.claimed && !preferredInstanceId },
432
+ );
433
+ if (response.result.kind === 'ensured') {
434
+ const record = await this.bindAsync(identity, response.result.providerBinding, selected.instanceId);
435
+ if (response.result.observation && !conversationContentAvailable(response.result.observation)) {
436
+ return failure('COMPUTER_CHATGPT_CONVERSATION_CONTENT_UNAVAILABLE', { failoverSafe: false });
437
+ }
438
+ return { state: 'ready', target: this.target(identity, record, selected.instanceId), ...(response.result.observation ? { observation: response.result.observation } : {}) };
439
+ }
440
+ if (response.result.kind === 'failed') {
441
+ if (response.result.providerBinding) await this.bindAsync(identity, response.result.providerBinding, selected.instanceId);
442
+ return failure(response.result.code, { retryable: response.result.retryable,
443
+ failoverSafe: !response.result.providerBinding && !preferredInstanceId && response.result.failoverSafe === true,
444
+ humanAction: response.result.humanAction });
445
+ }
446
+ return failure('COMPUTER_CHATGPT_EXTENSION_ENSURE_INVALID', { failoverSafe: false });
447
+ }
448
+
449
+ async openBootstrap(projectUrl: string, bootstrapKey: string, recoverStalePin = true): Promise<ComputerChatgptTargetResult> {
450
+ const identity: ComputerChatgptBootstrapIdentity = { namespace: 'chatgpt.bootstrap', bootstrapKey, projectUrl };
451
+ const previous = this.authority.findSurfaceByStableIdentity(this.controllerHome, stableIdentity(identity));
452
+ const binding = previous?.providerBinding;
453
+ // Existing bootstrap tab identity survives extension reconnects. A foreign
454
+ // provider owns its tab; extension must not create another one for the
455
+ // same task. Conversely, extension absence cannot authorize native tab
456
+ // creation while an extension-owned tab might still exist.
457
+ if (binding && binding.providerId !== PROVIDER_ID) {
458
+ return failure('COMPUTER_CHATGPT_EXTENSION_BOOTSTRAP_PROVIDER_MISMATCH', { retryable: false, failoverSafe: true });
459
+ }
460
+ const selected = this.selectProviderInstance(this.preferredProviderInstance(identity));
461
+ if (!selected.instanceId) {
462
+ return failure(
463
+ selected.ambiguous ? 'COMPUTER_CHATGPT_EXTENSION_PROVIDER_INSTANCE_AMBIGUOUS' : 'COMPUTER_CHATGPT_EXTENSION_NOT_CONNECTED',
464
+ { failoverSafe: !selected.ambiguous && !binding },
465
+ );
466
+ }
467
+ // Controller's exact tab attachment, not the Project URL, is recovery
468
+ // authority after a worker restart.
469
+ const response = await this.submit(selected.instanceId, { kind: 'ensure', identity,
470
+ ...(previous?.providerBinding?.providerId === PROVIDER_ID ? { providerBinding: previous.providerBinding } : {}),
471
+ });
472
+ if (!response.result) return failure(
473
+ response.claimed ? 'COMPUTER_CHATGPT_EXTENSION_BOOTSTRAP_OPEN_OUTCOME_UNKNOWN' : 'COMPUTER_CHATGPT_EXTENSION_NOT_CONNECTED',
474
+ { failoverSafe: !response.claimed && !binding },
475
+ );
476
+ if (response.result.kind === 'ensured') {
477
+ const record = await this.bindAsync(identity, response.result.providerBinding, selected.instanceId);
478
+ return { state: 'ready', target: this.target(identity, record, selected.instanceId), ...(response.result.observation ? { observation: response.result.observation } : {}) };
479
+ }
480
+ if (response.result.kind === 'failed') {
481
+ if (response.result.providerBinding) await this.bindAsync(identity, response.result.providerBinding, selected.instanceId);
482
+ // Only openBootstrap's pre-dispatch caller may rebuild a tab attachment.
483
+ // The SAME live Chrome provider must prove that the exact pinned tab is
484
+ // either absent or now serves a DIFFERENT Project. A reused physical tab
485
+ // id is not a valid target and must not permanently strand the unspent
486
+ // bootstrap. Never close/navigate the mismatched foreign tab. Keep the
487
+ // one durable target and lease/CAS-clear only its stale binding; never
488
+ // recover from an unknown tab-create result or switch profiles/providers.
489
+ if (recoverStalePin && (response.result.code === 'COMPUTER_CHATGPT_BOOTSTRAP_PINNED_TAB_MISSING'
490
+ || response.result.code === 'COMPUTER_CHATGPT_BOOTSTRAP_PINNED_TAB_IDENTITY_CHANGED')
491
+ && previous && binding?.providerId === PROVIDER_ID
492
+ && providerInstanceId(binding.providerSessionId) === selected.instanceId
493
+ && binding.windowId && binding.tabId) {
494
+ try {
495
+ await this.authority.withSurfaceLease(this.controllerHome, previous.targetId, async (lease) => {
496
+ const current = lease.current();
497
+ const attached = current.providerBinding;
498
+ if (current.stableIdentity.resource?.namespace !== identity.namespace
499
+ || current.stableIdentity.resource.key !== identity.bootstrapKey
500
+ || attached?.providerId !== binding.providerId
501
+ || attached.providerSessionId !== binding.providerSessionId
502
+ || attached.windowId !== binding.windowId || attached.tabId !== binding.tabId
503
+ || attached.browserProduct !== binding.browserProduct) {
504
+ throw new Error('COMPUTER_CHATGPT_BOOTSTRAP_PINNED_BINDING_CHANGED');
505
+ }
506
+ lease.clearBinding();
507
+ });
508
+ } catch {
509
+ return failure('COMPUTER_CHATGPT_BOOTSTRAP_PINNED_BINDING_CHANGED', { failoverSafe: false });
510
+ }
511
+ // Exactly one same-provider re-open. A claimed but unanswered tabCreate
512
+ // still reports outcome unknown and must never create another tab.
513
+ return await this.openBootstrap(projectUrl, bootstrapKey, false);
514
+ }
515
+ return failure(response.result.code, {
516
+ retryable: response.result.retryable, failoverSafe: response.result.failoverSafe === true && !binding && !response.result.providerBinding,
517
+ humanAction: response.result.humanAction,
518
+ });
519
+ }
520
+ return failure('COMPUTER_CHATGPT_EXTENSION_BOOTSTRAP_INVALID', { failoverSafe: false });
521
+ }
522
+
523
+ async findBySubmittedMarker(marker: string, bootstrapKey?: string, betweenObservations?: () => Promise<void>): Promise<ComputerChatgptTargetResult[]> {
524
+ await betweenObservations?.();
525
+ const fresh = this.freshProviders();
526
+ if (fresh.length === 0) return [];
527
+ const responses = await Promise.all(fresh.map(async ([instanceId]) => ({
528
+ instanceId,
529
+ response: await this.submit(instanceId, { kind: 'find_marker', marker, ...(bootstrapKey ? { bootstrapKey } : {}) }),
530
+ })));
531
+ await betweenObservations?.();
532
+ const results: ComputerChatgptTargetResult[] = [];
533
+ type MarkerMatch = Extract<ComputerChatgptExtensionCommandResult, { kind: 'marker_matches' }>['matches'][number];
534
+ const matchesByConversation = new Map<string, Array<{ instanceId: string; match: MarkerMatch }>>();
535
+ for (const { instanceId, response } of responses) {
536
+ if (response.result?.kind !== 'marker_matches') continue;
537
+ for (const match of response.result.matches) {
538
+ const entries = matchesByConversation.get(match.identity.conversationId) ?? [];
539
+ entries.push({ instanceId, match });
540
+ matchesByConversation.set(match.identity.conversationId, entries);
541
+ }
542
+ }
543
+ for (const matches of matchesByConversation.values()) {
544
+ const first = matches[0]!;
545
+ const existing = this.authority.findSurfaceByStableIdentity(this.controllerHome, stableIdentity(first.match.identity))?.providerBinding;
546
+ const samePhysicalBinding = (match: MarkerMatch, binding: NonNullable<typeof existing>, instanceId: string): boolean => {
547
+ const observed = match.providerBinding;
548
+ return Boolean(observed
549
+ && observed.providerId === binding.providerId
550
+ && observed.providerSessionId === binding.providerSessionId
551
+ && observed.browserProduct === binding.browserProduct
552
+ && observed.windowId === binding.windowId
553
+ && observed.tabId === binding.tabId
554
+ && observed.ownerToken === binding.ownerToken
555
+ && instanceId === binding.providerSessionId);
556
+ };
557
+ const existingMatch = existing?.providerId === PROVIDER_ID
558
+ ? matches.find(({ instanceId, match }) => samePhysicalBinding(match, existing, instanceId))
559
+ : undefined;
560
+ const bootstrap = bootstrapKey
561
+ ? this.authority.findSurfaceByStableIdentity(this.controllerHome, {
562
+ surfaceType: 'browser-tab', ownership: 'provider_owned',
563
+ resource: { namespace: 'chatgpt.bootstrap', key: bootstrapKey },
564
+ })
565
+ : undefined;
566
+ const pinned = bootstrap?.providerBinding;
567
+ const bootstrapMatch = pinned?.providerId === PROVIDER_ID
568
+ ? matches.find(({ instanceId, match }) => samePhysicalBinding(match, pinned, instanceId))
569
+ : undefined;
570
+ // A task-specific bootstrap pin outranks a conversation surface for the
571
+ // same conversationId. If that exact physical pin is absent, preserve the
572
+ // unknown outcome instead of letting another tab's marker become authority.
573
+ if (pinned && !bootstrapMatch) continue;
574
+ const candidate = pinned
575
+ ? bootstrapMatch
576
+ : existingMatch ?? (matches.length === 1 && first.match.providerBinding ? first : undefined);
577
+ const bootstrapMatchBinding = bootstrapMatch?.match.providerBinding;
578
+ const existingMatchesBootstrap = Boolean(existingMatch && bootstrapMatch && bootstrapMatchBinding
579
+ && existingMatch.instanceId === bootstrapMatch.instanceId
580
+ && samePhysicalBinding(existingMatch.match, bootstrapMatchBinding, existingMatch.instanceId));
581
+ // Resolve duplicate marker tabs only with an exact persisted physical pin.
582
+ // A bootstrap pin already owns its tab: return that target so the caller
583
+ // can promote it, instead of prematurely binding a second conversation
584
+ // Surface to the same tab and hitting COMPUTER_SURFACE_INDEX_CONFLICT.
585
+ if (!candidate) continue;
586
+ if (bootstrap && candidate === bootstrapMatch && !existingMatchesBootstrap) {
587
+ const metadata = bootstrap.compatibilityRecords.find((entry) => entry.namespace === 'chatgpt.target')?.value as Record<string, unknown> | undefined;
588
+ if (typeof metadata?.projectUrl !== 'string' || !metadata.projectUrl) continue;
589
+ const identity: ComputerChatgptBootstrapIdentity = { namespace: 'chatgpt.bootstrap', bootstrapKey: bootstrapKey!, projectUrl: metadata.projectUrl };
590
+ results.push({ state: 'ready', target: this.target(identity, bootstrap, candidate.instanceId), observation: candidate.match.observation });
591
+ continue;
592
+ }
593
+ const record = await this.bindAsync(candidate.match.identity, candidate.match.providerBinding, candidate.instanceId);
594
+ results.push({ state: 'ready', target: this.target(candidate.match.identity, record, candidate.instanceId), observation: candidate.match.observation });
595
+ }
596
+ return results;
597
+ }
598
+
599
+ async promoteBootstrap(targetId: string, identity: ComputerChatgptConversationIdentity): Promise<ComputerChatgptTargetResult> {
600
+ const previous = this.authority.getSurface(this.controllerHome, targetId);
601
+ if (!previous) return failure('COMPUTER_CHATGPT_EXTENSION_BOOTSTRAP_TARGET_MISSING', { failoverSafe: false });
602
+ const binding = previous.providerBinding;
603
+ if (binding && binding.providerId !== PROVIDER_ID) {
604
+ return failure('COMPUTER_CHATGPT_EXTENSION_BOOTSTRAP_PROVIDER_MISMATCH', { retryable: false, failoverSafe: true });
605
+ }
606
+ const boundInstanceId = providerInstanceId(binding?.providerSessionId);
607
+ const selected = boundInstanceId ? { instanceId: boundInstanceId, ambiguous: false } : this.selectProviderInstance();
608
+ if (!selected.instanceId) return failure('COMPUTER_CHATGPT_EXTENSION_PROVIDER_INSTANCE_AMBIGUOUS', { failoverSafe: false });
609
+ await this.authority.withSurfaceLease(this.controllerHome, targetId, async (lease) => { lease.clearBinding(); });
610
+ const record = await this.bindAsync(identity, binding, selected.instanceId);
611
+ this.authority.tombstoneSurface(this.controllerHome, targetId);
612
+ return { state: 'ready', target: this.target(identity, record, selected.instanceId) };
613
+ }
614
+
615
+ /** Existing Surface binding is the only retirement authority. A claimed
616
+ * Chrome close with missing acknowledgement is outcome-unknown: retain the
617
+ * exact attachment so the same owner can reconcile/retry, never make it
618
+ * eligible for another physical owner by clearing the index prematurely. */
619
+ private retirePhysicalBinding(record: ComputerSurfaceTarget, identity?: ComputerChatgptTargetIdentity): Promise<boolean> {
620
+ const existing = this.retiring.get(record.targetId);
621
+ if (existing) return existing;
622
+ const pending = this.retirePhysicalBindingOnce(record, identity);
623
+ this.retiring.set(record.targetId, pending);
624
+ const release = (): void => {
625
+ if (this.retiring.get(record.targetId) === pending) this.retiring.delete(record.targetId);
626
+ };
627
+ void pending.then(release, release);
628
+ return pending;
629
+ }
630
+
631
+ private async retirePhysicalBindingOnce(record: ComputerSurfaceTarget, identity?: ComputerChatgptTargetIdentity): Promise<boolean> {
632
+ const previous = record.providerBinding;
633
+ if (previous?.providerId !== PROVIDER_ID) return false;
634
+ const resource = record.stableIdentity.resource;
635
+ if (previous.ownerToken) {
636
+ const instanceId = providerInstanceId(previous.providerSessionId);
637
+ if (!identity || !instanceId || !this.providerIsFresh(instanceId)) return false;
638
+ if ([...this.pending.values()].some((entry) => 'identity' in entry.command
639
+ && entry.command.kind !== 'close'
640
+ && entry.command.identity.namespace === resource?.namespace
641
+ && (entry.command.identity.namespace === 'chatgpt.conversation'
642
+ ? entry.command.identity.conversationId === resource?.key
643
+ : entry.command.identity.namespace === 'chatgpt.bootstrap' && entry.command.identity.bootstrapKey === resource?.key))) return false;
644
+ let acknowledged = false;
645
+ try {
646
+ const response = await this.submit(instanceId, { kind: 'close', identity, providerBinding: previous });
647
+ acknowledged = response.result?.kind === 'closed';
648
+ } catch { return false; }
649
+ if (!acknowledged) return false;
650
+ }
651
+ // A legacy or user-attached tab has no Forge-create token: detach only,
652
+ // never turn a matching ChatGPT URL into permission for physical closure.
653
+ let cleared = false;
654
+ try {
655
+ await this.authority.withSurfaceLease(this.controllerHome, record.targetId, async (lease) => {
656
+ const binding = lease.current().providerBinding;
657
+ if (binding?.providerId !== previous.providerId
658
+ || binding.providerSessionId !== previous.providerSessionId
659
+ || binding.browserProduct !== previous.browserProduct
660
+ || binding.windowId !== previous.windowId || binding.tabId !== previous.tabId
661
+ || binding.ownerToken !== previous.ownerToken) return;
662
+ lease.clearBinding();
663
+ cleared = true;
664
+ });
665
+ } catch { return false; }
666
+ return cleared;
667
+ }
668
+
669
+ async cleanup(activeResourceKeys: readonly string[]): Promise<void> {
670
+ const active = new Set(activeResourceKeys);
671
+ for (const record of this.authority.listAllSurfaces(this.controllerHome)) {
672
+ const resource = record.stableIdentity.resource;
673
+ if (!resource || !['chatgpt.conversation', 'chatgpt.bootstrap'].includes(resource.namespace)) continue;
674
+ if (record.providerBinding?.providerId !== PROVIDER_ID || active.has(`${resource.namespace}:${resource.key}`)) continue;
675
+ const compatibility = record.compatibilityRecords.find((entry) => entry.namespace === 'chatgpt.target')?.value as Record<string, unknown> | undefined;
676
+ const identity: ComputerChatgptTargetIdentity | undefined = resource.namespace === 'chatgpt.conversation'
677
+ ? (typeof compatibility?.canonicalUrl === 'string' ? { namespace: 'chatgpt.conversation', conversationId: resource.key, canonicalUrl: compatibility.canonicalUrl } : undefined)
678
+ : (typeof compatibility?.projectUrl === 'string' ? { namespace: 'chatgpt.bootstrap', bootstrapKey: resource.key, projectUrl: compatibility.projectUrl } : undefined);
679
+ const cleared = await this.retirePhysicalBinding(record, identity);
680
+ if (cleared && resource.namespace === 'chatgpt.bootstrap') this.authority.tombstoneSurface(this.controllerHome, record.targetId);
681
+ }
682
+ }
683
+
684
+ async release(targetId: string): Promise<void> {
685
+ const record = this.authority.getSurface(this.controllerHome, targetId);
686
+ if (!record || (record.providerBinding && record.providerBinding.providerId !== PROVIDER_ID)) return;
687
+ const resource = record.stableIdentity.resource;
688
+ const compatibility = record.compatibilityRecords.find((entry) => entry.namespace === 'chatgpt.target')?.value as Record<string, unknown> | undefined;
689
+ const identity: ComputerChatgptTargetIdentity | undefined = resource?.namespace === 'chatgpt.conversation' && typeof compatibility?.canonicalUrl === 'string'
690
+ ? { namespace: 'chatgpt.conversation', conversationId: resource.key, canonicalUrl: compatibility.canonicalUrl }
691
+ : resource?.namespace === 'chatgpt.bootstrap' && typeof compatibility?.projectUrl === 'string'
692
+ ? { namespace: 'chatgpt.bootstrap', bootstrapKey: resource.key, projectUrl: compatibility.projectUrl }
693
+ : undefined;
694
+ if (record.providerBinding) await this.retirePhysicalBinding(record, identity);
695
+ }
696
+
697
+ async close(): Promise<void> {
698
+ for (const entry of this.pending.values()) {
699
+ clearTimeout(entry.timer);
700
+ entry.resolve({ claimed: entry.claimed, result: entry.command.kind === 'dispatch' && entry.claimed
701
+ ? { kind: 'dispatch', mutation: 'attempted' }
702
+ : { kind: 'failed', code: 'COMPUTER_CHATGPT_EXTENSION_RUNTIME_CLOSED', retryable: true } });
703
+ }
704
+ this.pending.clear();
705
+ this.queues.clear();
706
+ this.providerStates.clear();
707
+ }
708
+ }