@moretea-labs/forge 1.8.0 → 1.8.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (528) hide show
  1. package/AGENTS.md +70 -7
  2. package/CHANGELOG.md +14 -0
  3. package/CLAUDE.md +17 -2
  4. package/CONTRIBUTING.md +3 -2
  5. package/THIRD_PARTY_NOTICES.md +1 -1
  6. package/adapters/chatgpt/browser-delivery-host.ts +7 -1
  7. package/adapters/chatgpt/browser-delivery-runtime.ts +529 -56
  8. package/adapters/chatgpt/controller-binding-store.ts +101 -22
  9. package/adapters/chatgpt/controller-round-host.ts +15 -25
  10. package/adapters/chatgpt/controller-round-settlement-store.ts +58 -4
  11. package/adapters/chatgpt/provider-delivery.ts +228 -1
  12. package/adapters/chatgpt/work-conversation-binding-store.ts +79 -53
  13. package/adapters/computer/chatgpt-extension-target.ts +463 -0
  14. package/adapters/computer/chatgpt-target-router.ts +103 -0
  15. package/adapters/computer/chrome-extension/background.js +385 -0
  16. package/adapters/computer/chrome-extension/content.js +378 -0
  17. package/adapters/computer/chrome-extension/core.js +24 -0
  18. package/adapters/computer/chrome-extension/manifest.json +30 -0
  19. package/adapters/computer/desktop-operator-discovery.ts +11 -31
  20. package/adapters/computer/interaction-target-authority.ts +142 -18
  21. package/adapters/mcp/auth.ts +0 -1
  22. package/adapters/mcp/instructions.ts +5 -4
  23. package/adapters/mcp/multi-repository.ts +3 -19
  24. package/adapters/mcp/oauth.ts +73 -0
  25. package/adapters/mcp/paths.ts +4 -1
  26. package/adapters/mcp/runtime-gateway/automation-receipt-adapter.ts +87 -0
  27. package/adapters/mcp/runtime-gateway/bounded-result-runtime.ts +62 -0
  28. package/adapters/mcp/runtime-gateway/cognition-settlement.ts +201 -0
  29. package/adapters/mcp/runtime-gateway/context-adapter.ts +411 -73
  30. package/adapters/mcp/runtime-gateway/context-pack-sidecar.ts +91 -0
  31. package/adapters/mcp/runtime-gateway/controller-authority-adapter.ts +20 -5
  32. package/adapters/mcp/runtime-gateway/core-capability-adapter.ts +258 -0
  33. package/adapters/mcp/runtime-gateway/engineering-preconditions.ts +10 -27
  34. package/adapters/mcp/runtime-gateway/engineering-tool-contract.ts +15 -0
  35. package/adapters/mcp/runtime-gateway/execution-tools.ts +8 -42
  36. package/adapters/mcp/runtime-gateway/gateway-execution-adapter.ts +2 -1
  37. package/adapters/mcp/runtime-gateway/plugin-adapter.ts +117 -45
  38. package/adapters/mcp/runtime-gateway/process-tools.ts +190 -22
  39. package/adapters/mcp/runtime-gateway/protected-computer-adapter.ts +16 -4
  40. package/adapters/mcp/runtime-gateway/recovery-adapter.ts +69 -52
  41. package/adapters/mcp/runtime-gateway/repository-compat-adapter.ts +4 -35
  42. package/adapters/mcp/runtime-gateway/result-adapter.ts +10 -4
  43. package/adapters/mcp/runtime-gateway/router.ts +18 -504
  44. package/adapters/mcp/runtime-gateway/routing-policy.ts +499 -0
  45. package/adapters/mcp/runtime-gateway/runtime-observation-adapter.ts +14 -65
  46. package/adapters/mcp/runtime-gateway/runtime-readiness-observation.ts +218 -0
  47. package/adapters/mcp/runtime-gateway/runtime-tool-definitions.ts +113 -173
  48. package/adapters/mcp/runtime-gateway/runtime-tools.ts +15 -5
  49. package/adapters/mcp/runtime-gateway/scheduler-adapter.ts +1 -0
  50. package/adapters/mcp/runtime-gateway/shared-adapter.ts +20 -0
  51. package/adapters/mcp/runtime-gateway/status-inbox-adapter.ts +358 -266
  52. package/adapters/mcp/runtime-gateway/typescript-navigation-sidecar.ts +136 -0
  53. package/adapters/mcp/runtime-gateway/work-adapter.ts +261 -3122
  54. package/adapters/mcp/runtime-gateway/work-controller-operations.ts +257 -0
  55. package/adapters/mcp/runtime-gateway/work-detail-projection.ts +60 -0
  56. package/adapters/mcp/runtime-gateway/work-input-wire-migration.ts +246 -0
  57. package/adapters/mcp/runtime-gateway/work-learning-operations.ts +145 -0
  58. package/adapters/mcp/runtime-gateway/work-list-projection.ts +38 -0
  59. package/adapters/mcp/runtime-gateway/work-plan-operations.ts +382 -0
  60. package/adapters/mcp/runtime-gateway/work-repair-adapter.ts +308 -0
  61. package/adapters/mcp/runtime-gateway/work-requirement-operations.ts +148 -0
  62. package/adapters/mcp/runtime-gateway/work-semantic-operations.ts +263 -0
  63. package/adapters/mcp/runtime-gateway/work-workflow-operations.ts +113 -0
  64. package/adapters/mcp/runtime-gateway/workflow-supervisor-adapter.ts +156 -0
  65. package/adapters/mcp/server.ts +67 -23
  66. package/adapters/mcp/setup.ts +1 -3
  67. package/adapters/mcp/tool-mapping/legacy-tool-service.ts +44 -170
  68. package/adapters/mcp/tool-mapping/post-finalize-work-attribution.ts +4 -9
  69. package/adapters/mcp/tool-mapping/repository-tools.ts +133 -142
  70. package/adapters/mcp/toolset-names.ts +5 -0
  71. package/adapters/mcp/toolset.ts +6 -5
  72. package/adapters/mcp/transports/http-observation.ts +365 -0
  73. package/adapters/mcp/transports/http.ts +154 -677
  74. package/adapters/mcp/transports/oauth-http.ts +322 -0
  75. package/adapters/mcp/transports/session-registry.ts +6 -0
  76. package/adapters/mcp/tunnels/openai-secure-tunnel.ts +89 -5
  77. package/assets/plugin-registry.v1.json +6 -4
  78. package/assets/reference-configs/agentic-development-flow.md +25 -0
  79. package/assets/reference-configs/global-working-rules.md +19 -0
  80. package/assets/skill-version.json +2 -2
  81. package/docs/architecture/CURRENT.md +111 -41
  82. package/docs/architecture/decisions/20260803-release-identity-binding-and-exit-policy.md +14 -5
  83. package/docs/architecture/decisions/20260823-immediate-controller-relay.md +6 -3
  84. package/docs/architecture/decisions/20260907-assistant-learning-loop.md +2 -0
  85. package/docs/architecture/decisions/20260907-controller-round-transition-policy.md +19 -4
  86. package/docs/architecture/decisions/20260916-workflow-supervisor-authority.md +249 -0
  87. package/docs/architecture/decisions/20260917-cognitive-memory-foundation.md +82 -0
  88. package/docs/architecture/decisions/20260918-stable-candidate-release-lifecycle.md +221 -0
  89. package/docs/architecture/decisions/20260919-autonomous-work-liveness.md +62 -0
  90. package/docs/architecture/decisions/20260924-thin-semantic-working-context.md +72 -0
  91. package/docs/architecture/decisions/20261001-supervisor-turn-authority.md +237 -0
  92. package/docs/architecture/decisions/20261005-forge-v3-desktop-client-boundary.md +77 -0
  93. package/docs/architecture/domains/verification.md +1 -0
  94. package/docs/architecture/domains/workflow-engine.md +6 -0
  95. package/docs/architecture/modules/controller-runtime/transport-lifecycle.md +1 -1
  96. package/docs/forge-plugin-management.md +2 -2
  97. package/docs/operations/controller-performance-and-502.md +17 -0
  98. package/docs/operations/controller-reliability-runbook.md +2 -2
  99. package/docs/operations/features.md +1 -1
  100. package/docs/operations/features.zh-CN.md +1 -1
  101. package/docs/operations/homebrew.md +2 -2
  102. package/docs/operations/mcp-tool-exposure.md +2 -0
  103. package/docs/operations/releasing.md +2 -0
  104. package/docs/operations/standalone-disaster-recovery.md +14 -6
  105. package/docs/wiki/Implementation.md +1 -1
  106. package/package.json +25 -14
  107. package/packages/kernel/cognition/api/index.ts +6 -0
  108. package/packages/kernel/cognition/application/activation-service.ts +451 -0
  109. package/packages/kernel/cognition/application/consolidation-service.ts +185 -0
  110. package/packages/kernel/cognition/application/legacy-experience-adapter.ts +38 -0
  111. package/packages/kernel/cognition/application/memory-service.ts +64 -0
  112. package/packages/kernel/cognition/domain/learning.ts +106 -0
  113. package/packages/kernel/cognition/domain/memory.ts +254 -0
  114. package/packages/kernel/controller/api/index.ts +1 -0
  115. package/packages/kernel/controller/application/continuation-service.ts +281 -0
  116. package/packages/kernel/controller/application/controller-round-service.ts +12 -0
  117. package/packages/kernel/controller/domain/controller-round-transition-policy.ts +242 -21
  118. package/packages/kernel/controller/domain/controller-round.ts +4 -1
  119. package/packages/kernel/controller/domain/execution-quality.ts +3 -1
  120. package/packages/kernel/controller/infrastructure/controller-round-store.ts +689 -103
  121. package/packages/kernel/controller/infrastructure/controller-session-store.ts +297 -71
  122. package/packages/kernel/controller/ports/controller-host.ts +2 -0
  123. package/packages/kernel/identity/api/index.ts +10 -0
  124. package/packages/kernel/identity/domain/activity-projection.ts +43 -0
  125. package/packages/kernel/identity/domain/capability-broker.ts +60 -0
  126. package/packages/kernel/identity/domain/grant.ts +72 -0
  127. package/packages/kernel/identity/domain/owned-resource.ts +116 -0
  128. package/packages/kernel/identity/domain/user-request.ts +93 -0
  129. package/packages/kernel/identity/infrastructure/activity-projection-store.ts +77 -0
  130. package/packages/kernel/identity/infrastructure/capability-broker.ts +81 -0
  131. package/packages/kernel/identity/infrastructure/grant-store.ts +284 -0
  132. package/packages/kernel/identity/infrastructure/owned-resource-store.ts +259 -0
  133. package/packages/kernel/identity/infrastructure/user-request-store.ts +182 -0
  134. package/packages/kernel/scheduler/api/index.ts +0 -2
  135. package/packages/kernel/scheduler/application/schedule-service.ts +3 -0
  136. package/packages/kernel/scheduler/application/settlement.ts +0 -15
  137. package/packages/kernel/scheduler/domain/schedule.ts +87 -0
  138. package/packages/kernel/scheduler/infrastructure/schedule-store.ts +153 -133
  139. package/packages/kernel/work/api/index.ts +3 -2
  140. package/packages/kernel/work/application/work-service.ts +17 -42
  141. package/packages/kernel/work/domain/current-task-lineage.ts +104 -0
  142. package/packages/kernel/work/domain/engineering-design.ts +10 -5
  143. package/packages/kernel/work/domain/engineering-profile.ts +8 -12
  144. package/packages/kernel/work/domain/evaluation-promotion-receipt.ts +186 -0
  145. package/packages/kernel/work/domain/execution-concurrency.ts +19 -26
  146. package/packages/kernel/work/domain/execution-snapshot.ts +0 -31
  147. package/packages/kernel/work/domain/implementation-review.ts +14 -331
  148. package/packages/kernel/work/domain/objective-graph.ts +119 -0
  149. package/packages/kernel/work/domain/project-engineering-contract.ts +23 -1
  150. package/packages/kernel/work/domain/repository-completion-receipt.ts +1 -1
  151. package/packages/kernel/work/domain/state-machine.ts +25 -63
  152. package/packages/kernel/work/domain/types.ts +57 -51
  153. package/packages/kernel/work/infrastructure/work-contract-store.ts +819 -728
  154. package/packages/kernel/work/ports/work-contract-store.ts +5 -2
  155. package/packages/plugin-runtime/browser/session-authority.ts +2 -1
  156. package/packages/plugin-runtime/computer/chatgpt-identity.ts +24 -0
  157. package/packages/plugin-runtime/computer/conversation-target.ts +143 -0
  158. package/packages/plugin-runtime/computer/index.ts +2 -0
  159. package/packages/plugin-runtime/computer/target-authority.ts +26 -1
  160. package/packages/plugin-runtime/external/unix-jsonl-transport.ts +142 -18
  161. package/packages/protocols/computer/contract.ts +27 -1
  162. package/scripts/activate-source-baseline.ts +7 -9
  163. package/scripts/canary-controller-semantic-wait.ts +12 -24
  164. package/scripts/check-mcp-compatibility.ts +48 -136
  165. package/scripts/check-runtime-architecture.mjs +622 -217
  166. package/scripts/forge-local-recovery-helper.mjs +93 -15
  167. package/scripts/lib/project-init-lib.sh +3 -0
  168. package/scripts/open-source-audit-allowlist.txt +1 -2
  169. package/scripts/run-bounded-command.mjs +5 -0
  170. package/scripts/run-governed-gate.ts +0 -1
  171. package/scripts/run-mobile-monitor-bridge.ts +0 -1
  172. package/scripts/smoke-control-plane-failure-domain.ts +94 -0
  173. package/scripts/smoke-mcp-http-runtime.ts +5 -0
  174. package/scripts/smoke-runtime-recovery.ts +12 -43
  175. package/scripts/smoke-schedule-engine.ts +23 -15
  176. package/scripts/smoke-unattended-transport-recovery.ts +223 -0
  177. package/scripts/smoke-user-request-continuation-restart.ts +232 -0
  178. package/scripts/smoke-workflow-supervisor-chrome-adapter.ts +92 -0
  179. package/scripts/smoke-workflow-supervisor-process-restart.ts +276 -0
  180. package/scripts/smoke-workflow-supervisor-restart-recovery.ts +150 -0
  181. package/scripts/smoke-workflow-supervisor.ts +103 -0
  182. package/scripts/verify-forge-runtime.sh +2 -1
  183. package/src/cli/agent-jobs/executor-health.ts +11 -34
  184. package/src/cli/agent-jobs/integration.ts +18 -49
  185. package/src/cli/agent-jobs/job-manager.ts +7 -3
  186. package/src/cli/commands/brain-assistant.ts +27 -13
  187. package/src/cli/commands/brain.ts +13 -15
  188. package/src/cli/commands/chatgpt.ts +1 -163
  189. package/src/cli/commands/recovery.ts +135 -121
  190. package/src/cli/commands/runtime.ts +3 -3
  191. package/src/cli/commands/setup-profile.ts +8 -0
  192. package/src/cli/controller/check-runner.ts +13 -2
  193. package/src/cli/controller/completion-backlog.ts +3 -3
  194. package/src/cli/controller/completion-orchestrator.ts +4 -43
  195. package/src/cli/controller/completion-target.ts +3 -72
  196. package/src/cli/controller/context/source-materializer.ts +81 -100
  197. package/src/cli/controller/context-pack.ts +10 -8
  198. package/src/cli/controller/execution-completion.ts +4 -7
  199. package/src/cli/controller/execution-policy.ts +36 -153
  200. package/src/cli/controller/governance.ts +2 -3
  201. package/src/cli/controller/issue-store.ts +4 -99
  202. package/src/cli/controller/launch-agents.ts +59 -18
  203. package/src/cli/controller/operational-plan.ts +24 -51
  204. package/src/cli/controller/runtime-config.ts +5 -1
  205. package/src/cli/controller/stuck-state-migration.ts +2 -3
  206. package/src/cli/controller/systemd-user.ts +39 -1
  207. package/src/cli/editing/edit-session.ts +1 -7
  208. package/src/cli/local-bridge/console-automations.ts +18 -13
  209. package/src/cli/local-bridge/console-view-models.ts +3 -12
  210. package/src/cli/local-bridge/facade-api.ts +64 -191
  211. package/src/cli/local-bridge/server.ts +24 -147
  212. package/src/cli/local-bridge/types.ts +0 -1
  213. package/src/cli/mcp/oauth-client-retirement.ts +74 -0
  214. package/src/cli/repositories/command-executor.ts +29 -23
  215. package/src/cli/repositories/command-scope.ts +35 -16
  216. package/src/cli/repositories/controller-home.ts +48 -0
  217. package/src/cli/repositories/ephemeral-workspace.ts +20 -30
  218. package/src/cli/repositories/git-command-executor.ts +2 -2
  219. package/src/cli/repositories/registry.ts +77 -11
  220. package/src/cli/repositories/structured-git.ts +62 -2
  221. package/src/cli/repository/session-cache.ts +92 -6
  222. package/src/runtime/context/assistant-context.ts +20 -7
  223. package/src/runtime/context/assistant-work-context.ts +89 -27
  224. package/src/runtime/context/automatic-learning.ts +565 -0
  225. package/src/runtime/context/cognitive-attention.ts +173 -0
  226. package/src/runtime/context/cognitive-skill-canary.ts +158 -0
  227. package/src/runtime/context/context-closure.ts +46 -9
  228. package/src/runtime/context/context-pack-process.ts +103 -0
  229. package/src/runtime/context/context-plane.ts +1 -9
  230. package/src/runtime/context/direct-controller-learning.ts +298 -0
  231. package/src/runtime/context/semantic-navigation-contract.ts +9 -0
  232. package/src/runtime/context/semantic-navigation.ts +6 -34
  233. package/src/runtime/context/typescript-navigation-process.ts +145 -0
  234. package/src/runtime/context/typescript-navigation.ts +89 -3
  235. package/src/runtime/control-plane/cleanup-artifact-retention.ts +212 -9
  236. package/src/runtime/control-plane/concurrency/work-execution-concurrency.ts +9 -47
  237. package/src/runtime/control-plane/execution/controller-authority-recovery.ts +34 -4
  238. package/src/runtime/control-plane/execution/edit-validation-coordinator.ts +29 -20
  239. package/src/runtime/control-plane/execution/execution-identity.ts +23 -3
  240. package/src/runtime/control-plane/execution/repository-work-attribution.ts +7 -30
  241. package/src/runtime/control-plane/execution/retained-work-resume.ts +206 -199
  242. package/src/runtime/control-plane/execution/session-store.ts +31 -1
  243. package/src/runtime/control-plane/execution/validation.ts +6 -8
  244. package/src/runtime/control-plane/execution/work-authority-reconciler.ts +13 -42
  245. package/src/runtime/control-plane/execution/work-check-evidence.ts +137 -0
  246. package/src/runtime/control-plane/execution/work-completion-authority.ts +30 -85
  247. package/src/runtime/control-plane/execution/work-delivery-service.ts +497 -0
  248. package/src/runtime/control-plane/execution/work-evidence-policy.ts +12 -50
  249. package/src/runtime/control-plane/execution/work-execution-support.ts +50 -149
  250. package/src/runtime/control-plane/execution/work-handle-authority.ts +188 -109
  251. package/src/runtime/control-plane/execution/work-handle-store.ts +19 -43
  252. package/src/runtime/control-plane/execution/work-head-settlement.ts +53 -20
  253. package/src/runtime/control-plane/execution/work-lifecycle-audit.ts +52 -29
  254. package/src/runtime/control-plane/execution/work-operation-service.ts +43 -27
  255. package/src/runtime/control-plane/execution/work-preparation-service.ts +126 -266
  256. package/src/runtime/control-plane/execution/work-remote-delivery.ts +2 -3
  257. package/src/runtime/control-plane/execution/work-revision-diff.ts +39 -0
  258. package/src/runtime/control-plane/execution/work-terminal-cleanup.ts +173 -186
  259. package/src/runtime/control-plane/execution/work-validation-reconciler.ts +28 -84
  260. package/src/runtime/control-plane/execution/work-verification-service.ts +406 -50
  261. package/src/runtime/control-plane/execution/work-verification-snapshot.ts +5 -1
  262. package/src/runtime/control-plane/facade/capability-registry.ts +362 -37
  263. package/src/runtime/control-plane/facade/check-normalization.ts +3 -9
  264. package/src/runtime/control-plane/facade/codex-delegation.ts +10 -11
  265. package/src/runtime/control-plane/facade/controller-connection.ts +135 -0
  266. package/src/runtime/control-plane/facade/goal-workloop-access.ts +1 -20
  267. package/src/runtime/control-plane/facade/goal-workloop.ts +281 -1753
  268. package/src/runtime/control-plane/facade/handoff-inbox-application.ts +12 -25
  269. package/src/runtime/control-plane/facade/handoff-inbox-store.ts +256 -52
  270. package/src/runtime/control-plane/facade/index.ts +0 -1
  271. package/src/runtime/control-plane/facade/operation-digest.ts +12 -15
  272. package/src/runtime/control-plane/facade/plan-contract-store.ts +451 -991
  273. package/src/runtime/control-plane/facade/policy-gate.ts +0 -23
  274. package/src/runtime/control-plane/facade/repository-work-admission.ts +12 -22
  275. package/src/runtime/control-plane/facade/requirement-authority.ts +102 -199
  276. package/src/runtime/control-plane/facade/requirement-board.ts +3 -3
  277. package/src/runtime/control-plane/facade/rh-work-operation-contract.ts +51 -14
  278. package/src/runtime/control-plane/facade/self-healing-loop.ts +18 -53
  279. package/src/runtime/control-plane/facade/suggested-actions.ts +15 -18
  280. package/src/runtime/control-plane/facade/types.ts +49 -108
  281. package/src/runtime/control-plane/facade/work-continuation.ts +8 -8
  282. package/src/runtime/control-plane/generated-cache-retention.ts +97 -1
  283. package/src/runtime/control-plane/global-scheduler/autonomous-continuation.ts +248 -0
  284. package/src/runtime/control-plane/global-scheduler/durable-admission.ts +1 -1
  285. package/src/runtime/control-plane/global-scheduler/maintenance.ts +239 -112
  286. package/src/runtime/control-plane/global-scheduler/reconciliation.ts +2 -1
  287. package/src/runtime/control-plane/global-scheduler/scheduler.ts +66 -40
  288. package/src/runtime/control-plane/global-scheduler/wake-signal.ts +42 -2
  289. package/src/runtime/control-plane/governance/access-policy.ts +19 -2
  290. package/src/runtime/control-plane/governance/authorization.ts +20 -3
  291. package/src/runtime/control-plane/launcher/chatgpt-round-continuation.ts +63 -300
  292. package/src/runtime/control-plane/launcher/chatgpt-work-continuation.ts +28 -300
  293. package/src/runtime/control-plane/launcher/local-conversation-controller.ts +238 -0
  294. package/src/runtime/control-plane/launcher/provider-mcp-bootstrap.ts +5 -2
  295. package/src/runtime/control-plane/launcher/thin-launcher.ts +96 -240
  296. package/src/runtime/control-plane/persistence/cognition-store.ts +820 -0
  297. package/src/runtime/control-plane/persistence/experience-store.ts +162 -29
  298. package/src/runtime/control-plane/persistence/requirement-store.ts +216 -74
  299. package/src/runtime/control-plane/persistence/sqlite-store.ts +113 -6
  300. package/src/runtime/control-plane/release-retention.ts +135 -47
  301. package/src/runtime/control-plane/repository-namespace-retention.ts +2 -2
  302. package/src/runtime/control-plane/runtime-cleanup.ts +290 -21
  303. package/src/runtime/control-plane/workspace/project-onboarding.ts +80 -0
  304. package/src/runtime/control-plane/workspace/semantic-sync-service.ts +19 -5
  305. package/src/runtime/control-plane/workspace/workspace-store.ts +169 -0
  306. package/src/runtime/diagnostics/incident-repair.ts +313 -146
  307. package/src/runtime/diagnostics/mcp-timing.ts +114 -0
  308. package/src/runtime/evidence/artifact-store.ts +158 -40
  309. package/src/runtime/evidence/evidence-store.ts +112 -8
  310. package/src/runtime/evidence/output-handle-index.ts +225 -0
  311. package/src/runtime/evidence/result-store.ts +158 -44
  312. package/src/runtime/execution/jobs/store.ts +3 -4
  313. package/src/runtime/execution/managed-workspace.ts +57 -0
  314. package/src/runtime/execution/process-runtime/check-facade.ts +1 -1
  315. package/src/runtime/execution/process-runtime/check-result-retention.ts +2 -2
  316. package/src/runtime/execution/process-runtime/check-result.ts +105 -1
  317. package/src/runtime/execution/process-runtime/check-runner-sidecar.ts +18 -8
  318. package/src/runtime/execution/process-runtime/command-facade.ts +79 -27
  319. package/src/runtime/execution/process-runtime/gc.ts +15 -2
  320. package/src/runtime/execution/process-runtime/handle-index.ts +176 -0
  321. package/src/runtime/execution/process-runtime/host-command-lane.ts +139 -0
  322. package/src/runtime/execution/process-runtime/index.ts +3 -0
  323. package/src/runtime/execution/process-runtime/lightweight-managed.ts +251 -72
  324. package/src/runtime/execution/process-runtime/persisted-check.ts +3 -3
  325. package/src/runtime/execution/process-runtime/process-runner-entry.ts +47 -5
  326. package/src/runtime/execution/process-runtime/process-scope.ts +160 -0
  327. package/src/runtime/execution/process-runtime/resource-claims.ts +65 -61
  328. package/src/runtime/execution/process-runtime/runtime.ts +35 -2
  329. package/src/runtime/execution/process-runtime/store.ts +30 -2
  330. package/src/runtime/execution/process-runtime/types.ts +6 -1
  331. package/src/runtime/execution/workers/executor.ts +2 -6
  332. package/src/runtime/platform/service-inventory.ts +130 -0
  333. package/src/runtime/platform/service-manager.ts +8 -0
  334. package/src/runtime/plugins/action-application.ts +85 -28
  335. package/src/runtime/plugins/app-store-connect-adapter.ts +38 -14
  336. package/src/runtime/plugins/browser-adapter.ts +757 -34
  337. package/src/runtime/plugins/browser-automation-service.ts +23 -3
  338. package/src/runtime/plugins/browser-macos-bridge.ts +321 -29
  339. package/src/runtime/plugins/browser-manifest-surface.ts +45 -11
  340. package/src/runtime/plugins/browser-native-session-service.ts +63 -13
  341. package/src/runtime/plugins/browser-registration.ts +16 -0
  342. package/src/runtime/plugins/browser-runtime.ts +14 -1
  343. package/src/runtime/plugins/browser-session-authority.ts +2 -2
  344. package/src/runtime/plugins/browser-session-store.ts +46 -76
  345. package/src/runtime/plugins/capability-authorization-grants.ts +258 -62
  346. package/src/runtime/plugins/computer-chatgpt-browser-adapter-installer.ts +219 -0
  347. package/src/runtime/plugins/computer-chatgpt-macos-target.ts +891 -0
  348. package/src/runtime/plugins/computer-registration.ts +222 -11
  349. package/src/runtime/plugins/desktop-operator-external-policy.ts +36 -4
  350. package/src/runtime/plugins/desktop-operator-registration.ts +12 -4
  351. package/src/runtime/plugins/external-adapter.ts +42 -6
  352. package/src/runtime/plugins/external-registration.ts +21 -1
  353. package/src/runtime/plugins/gmail-adapter.ts +23 -2
  354. package/src/runtime/plugins/google-calendar-adapter.ts +2 -2
  355. package/src/runtime/plugins/google-shared.ts +14 -7
  356. package/src/runtime/plugins/google-tasks-adapter.ts +2 -2
  357. package/src/runtime/plugins/ios-adapter.ts +1 -1
  358. package/src/runtime/plugins/lightweight-action.ts +208 -2
  359. package/src/runtime/plugins/local-system-adapter.ts +12 -2
  360. package/src/runtime/plugins/managed-process-adapter.ts +12 -5
  361. package/src/runtime/plugins/plugin-action-sidecar.ts +17 -13
  362. package/src/runtime/plugins/plugin-management-adapter.ts +1 -1
  363. package/src/runtime/plugins/store.ts +602 -428
  364. package/src/runtime/plugins/types.ts +20 -0
  365. package/src/runtime/plugins/xiaohongshu-publish.ts +16 -0
  366. package/src/runtime/projections/invalidation.ts +7 -3
  367. package/src/runtime/projections/materialized-view.ts +80 -36
  368. package/src/runtime/recovery/actions.ts +3 -3
  369. package/src/runtime/recovery/capability-action-application.ts +46 -45
  370. package/src/runtime/recovery/lifecycle-inventory.ts +29 -29
  371. package/src/runtime/recovery/maintenance-executor.ts +374 -123
  372. package/src/runtime/recovery/store.ts +29 -11
  373. package/src/runtime/release/release-coordinator.ts +296 -0
  374. package/src/runtime/release/release-session.ts +716 -0
  375. package/src/runtime/release/release-state-migration.ts +25 -0
  376. package/src/runtime/resources/leases/store.ts +56 -25
  377. package/src/runtime/root/computer-composition.ts +191 -6
  378. package/src/runtime/root/controller-progression-composition.ts +192 -0
  379. package/src/runtime/root/controller-round-composition.ts +20 -1
  380. package/src/runtime/root/deployment-topology.ts +106 -0
  381. package/src/runtime/root/entry.ts +4 -3
  382. package/src/runtime/root/known-good-recovery.ts +184 -0
  383. package/src/runtime/root/local-bridge.ts +0 -1
  384. package/src/runtime/root/mcp-transport.ts +111 -18
  385. package/src/runtime/root/ownership.ts +261 -9
  386. package/src/runtime/root/package-connector-service.ts +105 -19
  387. package/src/runtime/root/package-runtime-release.ts +117 -18
  388. package/src/runtime/root/package-runtime-service.ts +17 -11
  389. package/src/runtime/root/release-execution-canary.ts +44 -12
  390. package/src/runtime/root/release-loader.ts +90 -8
  391. package/src/runtime/root/release-manifest.ts +80 -6
  392. package/src/runtime/root/release-materialize.ts +372 -28
  393. package/src/runtime/root/release-store.ts +395 -36
  394. package/src/runtime/root/runtime-lane.ts +191 -0
  395. package/src/runtime/root/runtime.ts +159 -27
  396. package/src/runtime/root/scheduled-controller-composition.ts +28 -3
  397. package/src/runtime/root/service-runner.ts +2 -2
  398. package/src/runtime/root/service.ts +36 -33
  399. package/src/runtime/root/status.ts +48 -0
  400. package/src/runtime/root/types.ts +32 -3
  401. package/src/runtime/root/workflow-supervisor-composition.ts +493 -0
  402. package/src/runtime/root/workflow-supervisor-runtime.ts +209 -0
  403. package/src/runtime/root/write-fence.ts +50 -2
  404. package/src/runtime/safe-tooling/google-credential-store.ts +76 -21
  405. package/src/runtime/safe-tooling/google-oauth-broker.ts +25 -7
  406. package/src/runtime/safe-tooling/workspace-auth.ts +1 -1
  407. package/src/runtime/shared/bounded-child-supervisor.ts +9 -1
  408. package/src/runtime/shared/process-environment.ts +20 -9
  409. package/src/runtime/shared/response-budget.ts +1 -3
  410. package/src/runtime/standalone-recovery/controller-home-migration.ts +16 -24
  411. package/src/runtime/standalone-recovery/core.ts +3702 -342
  412. package/src/runtime/standalone-recovery/entry.ts +469 -39
  413. package/src/runtime/standalone-recovery/installer.ts +262 -148
  414. package/src/runtime/standalone-recovery/mcp-server.ts +29 -193
  415. package/src/runtime/standalone-recovery/operation-lock.ts +1 -1
  416. package/src/runtime/standalone-recovery/performance.ts +54 -16
  417. package/src/runtime/standalone-recovery/release.ts +53 -5
  418. package/src/runtime/standalone-recovery/service-labels.ts +5 -2
  419. package/src/runtime/standalone-recovery/watchdog-heartbeat.ts +5 -2
  420. package/src/runtime/workflow/schedules/browser-probe.ts +17 -6
  421. package/src/runtime/workflow/schedules/chatgpt-automation-migration.ts +10 -3
  422. package/src/runtime/workflow/schedules/engine.ts +138 -172
  423. package/src/runtime/workflow/schedules/work-continuation.ts +44 -5
  424. package/src/runtime/workflows/runtime.ts +15 -19
  425. package/src/testing/test-governance.ts +5 -1
  426. package/supervisor/chatgpt-conversation.ts +23 -0
  427. package/supervisor/client.ts +201 -0
  428. package/supervisor/control-plane.ts +868 -0
  429. package/supervisor/entry.ts +15 -0
  430. package/supervisor/forge-validators.ts +80 -0
  431. package/supervisor/index.ts +5 -0
  432. package/supervisor/native-browser-adapter.ts +786 -0
  433. package/supervisor/native-messaging/host.ts +39 -0
  434. package/supervisor/native-messaging/manifest.ts +26 -0
  435. package/supervisor/native-messaging/protocol.ts +27 -0
  436. package/supervisor/paths.ts +18 -0
  437. package/supervisor/protocol.ts +202 -0
  438. package/supervisor/server.ts +404 -0
  439. package/supervisor/store.ts +1451 -0
  440. package/supervisor/tsconfig.json +8 -0
  441. package/supervisor/types.ts +255 -0
  442. package/adapters/chatgpt/controller-host.ts +0 -119
  443. package/adapters/mcp/controller-round-compatibility.ts +0 -184
  444. package/adapters/mcp/frozen-client-semantic-compatibility.ts +0 -292
  445. package/adapters/mcp/runtime-gateway/work-compat-adapter.ts +0 -502
  446. package/packages/kernel/progression/api/index.ts +0 -2
  447. package/packages/kernel/progression/application/projector.ts +0 -211
  448. package/packages/kernel/progression/domain/types.ts +0 -116
  449. package/packages/kernel/progression/index.ts +0 -1
  450. package/packages/kernel/scheduler/application/continuation-service.ts +0 -212
  451. package/packages/kernel/scheduler/domain/continuation.ts +0 -38
  452. package/packages/kernel/scheduler/infrastructure/continuation-dispatch-store.ts +0 -38
  453. package/packages/kernel/work/domain/admission-policy.ts +0 -34
  454. package/scripts/benchmark-background-check-overlap.ts +0 -228
  455. package/scripts/benchmark-computer-hotpath.ts +0 -255
  456. package/scripts/benchmark-controller-hotpath.ts +0 -212
  457. package/scripts/benchmark-controller-round2.ts +0 -191
  458. package/scripts/benchmark-ios-agent-device.ts +0 -511
  459. package/scripts/benchmark-mcp-host.sh +0 -117
  460. package/scripts/benchmark-mcp-transport.ts +0 -169
  461. package/scripts/benchmark-operational-memory-activation.ts +0 -235
  462. package/scripts/benchmark-operational-shadow.ts +0 -28
  463. package/scripts/benchmark-quality-harness.ts +0 -146
  464. package/scripts/benchmark-route-session-concurrency.ts +0 -915
  465. package/scripts/benchmark-thin-harness-gateway-ab.ts +0 -632
  466. package/scripts/benchmark-thin-harness-mcp-e2e.ts +0 -498
  467. package/scripts/benchmark-thin-harness.ts +0 -251
  468. package/scripts/benchmark-typescript-navigation.ts +0 -186
  469. package/scripts/benchmark-work-efficiency.ts +0 -334
  470. package/scripts/build-controller-ui.ts +0 -28
  471. package/scripts/check-npm-release.sh +0 -32
  472. package/scripts/check-public-release-surface.sh +0 -19
  473. package/scripts/check-release-published.sh +0 -57
  474. package/scripts/check-release-readiness.sh +0 -37
  475. package/scripts/check-release-version.mjs +0 -74
  476. package/scripts/check-tarball-install-smoke.sh +0 -150
  477. package/scripts/package-source-archive.sh +0 -147
  478. package/scripts/public-release-files.txt +0 -39
  479. package/scripts/public-release.ts +0 -174
  480. package/scripts/publish-release-tarball.sh +0 -27
  481. package/scripts/route-nl-vs-ts-eval.ts +0 -679
  482. package/scripts/stage-runtime-release.ts +0 -44
  483. package/src/cli/controller/progress.ts +0 -656
  484. package/src/cli/controller/work-mode.ts +0 -181
  485. package/src/cli/local-bridge/console-assets.ts +0 -17
  486. package/src/cli/local-bridge/dashboard.ts +0 -17
  487. package/src/cli/local-bridge/frontend/src/App.tsx +0 -10
  488. package/src/cli/local-bridge/frontend/src/components/Button.tsx +0 -1
  489. package/src/cli/local-bridge/frontend/src/components/DetailPane.tsx +0 -3
  490. package/src/cli/local-bridge/frontend/src/components/SearchField.tsx +0 -1
  491. package/src/cli/local-bridge/frontend/src/components/SectionHeader.tsx +0 -1
  492. package/src/cli/local-bridge/frontend/src/components/Segmented.tsx +0 -1
  493. package/src/cli/local-bridge/frontend/src/components/StatusText.tsx +0 -3
  494. package/src/cli/local-bridge/frontend/src/design/icons.tsx +0 -11
  495. package/src/cli/local-bridge/frontend/src/design/tokens.css +0 -8
  496. package/src/cli/local-bridge/frontend/src/features/automations/AutomationsView.tsx +0 -153
  497. package/src/cli/local-bridge/frontend/src/features/capabilities/CapabilitiesView.tsx +0 -37
  498. package/src/cli/local-bridge/frontend/src/features/overview/OverviewView.tsx +0 -183
  499. package/src/cli/local-bridge/frontend/src/features/repositories/RepositoriesView.tsx +0 -2
  500. package/src/cli/local-bridge/frontend/src/features/system/SystemView.tsx +0 -2
  501. package/src/cli/local-bridge/frontend/src/features/work/WorkView.tsx +0 -4
  502. package/src/cli/local-bridge/frontend/src/lib/api.ts +0 -30
  503. package/src/cli/local-bridge/frontend/src/lib/format.ts +0 -4
  504. package/src/cli/local-bridge/frontend/src/lib/routes.ts +0 -7
  505. package/src/cli/local-bridge/frontend/src/main.tsx +0 -1
  506. package/src/cli/local-bridge/frontend/src/shell/AppShell.tsx +0 -1
  507. package/src/cli/local-bridge/frontend/src/shell/CommandBar.tsx +0 -2
  508. package/src/cli/local-bridge/frontend/src/shell/Sidebar.tsx +0 -4
  509. package/src/cli/local-bridge/frontend/src/styles.css +0 -28
  510. package/src/cli/local-bridge/frontend/src/types.ts +0 -15
  511. package/src/cli/local-bridge/frontend/src/vite-env.d.ts +0 -1
  512. package/src/cli/local-bridge/frontend/vite.config.ts +0 -27
  513. package/src/cli/local-bridge/ui-dist/app.css +0 -1
  514. package/src/cli/local-bridge/ui-dist/app.js +0 -11228
  515. package/src/runtime/control-plane/execution/content-equivalent-commit-authority.ts +0 -169
  516. package/src/runtime/control-plane/execution/direct-canonical-work-reconciliation.ts +0 -85
  517. package/src/runtime/control-plane/execution/direct-edit-work-completion.ts +0 -655
  518. package/src/runtime/control-plane/execution/work-finalization-service.ts +0 -2850
  519. package/src/runtime/control-plane/execution/work-path-scope.ts +0 -37
  520. package/src/runtime/control-plane/execution/work-task-receipt.ts +0 -468
  521. package/src/runtime/control-plane/facade/controller-round-relay.ts +0 -3
  522. package/src/runtime/control-plane/facade/work-admission-policy.ts +0 -142
  523. package/src/runtime/control-plane/facade/work-implementation-review.ts +0 -2
  524. package/src/runtime/control-plane/facade/work-state-machine.ts +0 -2
  525. package/src/runtime/control-plane/facade/work-task-projection.ts +0 -66
  526. package/src/runtime/control-plane/routing/index.ts +0 -1
  527. package/src/runtime/control-plane/routing/route-policy.ts +0 -401
  528. package/src/runtime/control-plane/routing/workspace-admission.ts +0 -70
@@ -19,6 +19,8 @@ import { basename, dirname, join } from 'path';
19
19
  import { ensureRepositoryControllerLayout, repositoryControllerRoot } from '../../../cli/repositories/controller-home';
20
20
  import { mutateControlPlaneRecord, readOrImportControlPlaneRecord } from '../../control-plane/persistence/sqlite-store';
21
21
  import { isSensitiveOutputKey, redactSensitiveText } from '../../evidence/sensitive-output';
22
+ import { touchSchedulerWakeSignal } from '../../control-plane/global-scheduler/wake-signal';
23
+ import { isRepositoryProcessScopeKey, legacyWorkspaceScopeRoot, processScopeRoot } from './process-scope';
22
24
  import {
23
25
  isManagedProcessActive,
24
26
  isManagedProcessTerminal,
@@ -30,7 +32,12 @@ import {
30
32
  } from './types';
31
33
 
32
34
  function processesRoot(controllerHome: string, repoId: string): string {
33
- const root = ensureRepositoryControllerLayout(controllerHome, repoId);
35
+ // Repository scopes keep the established per-repository layout. Instance and
36
+ // workspace scopes own sibling partitions so a non-repository process never
37
+ // needs a synthetic repository identity or repository storage.
38
+ const root = isRepositoryProcessScopeKey(repoId)
39
+ ? ensureRepositoryControllerLayout(controllerHome, repoId)
40
+ : processScopeRoot(controllerHome, repoId);
34
41
  const dir = join(root, 'processes');
35
42
  mkdirSync(dir, { recursive: true });
36
43
  mkdirSync(join(dir, 'logs'), { recursive: true });
@@ -522,7 +529,13 @@ export function getProcessRecord(
522
529
  repoId: string,
523
530
  processId: string,
524
531
  ): ManagedProcessRecord | undefined {
525
- return readProcessRecord(processPath(controllerHome, repoId, processId));
532
+ const current = readProcessRecord(processPath(controllerHome, repoId, processId));
533
+ if (current) return current;
534
+ // Bounded migration read: workspace processes written before the workspace
535
+ // partition existed are still attachable instead of being reported missing.
536
+ const legacyRoot = legacyWorkspaceScopeRoot(controllerHome, repoId);
537
+ if (!legacyRoot) return undefined;
538
+ return readProcessRecord(join(legacyRoot, 'processes', `${processId}.json`));
526
539
  }
527
540
 
528
541
  /**
@@ -559,6 +572,21 @@ export function tryCompleteProcessRecord(
559
572
  const sanitized = sanitizeProcessRecord(next).record;
560
573
  atomicWrite(path, sanitized);
561
574
  updateRecoveryIndexMembership(controllerHome, repoId, processId, processRecoveryMembership(sanitized));
575
+ // Terminal Process persistence remains the lifecycle authority. The scheduler
576
+ // notification is emitted only after durable terminal state exists, and only
577
+ // for Check-backed Processes whose receipts can unblock Work/Edit validation.
578
+ // Notification failure must never reinterpret or roll back the terminal CAS;
579
+ // the explicit schedule deadline still provides a bounded observation path.
580
+ if (sanitized.checkExecution || sanitized.origin?.surface === 'check' || sanitized.origin?.checkId) {
581
+ try {
582
+ touchSchedulerWakeSignal(controllerHome, `check-process-terminal:${processId}`);
583
+ } catch (error) {
584
+ console.error(
585
+ `[forge scheduler] Check Process terminal wake failed for ${processId}:`,
586
+ error instanceof Error ? error.message : String(error),
587
+ );
588
+ }
589
+ }
562
590
  return { ok: true, record: sanitized };
563
591
  }
564
592
 
@@ -17,7 +17,6 @@ export interface ExecutionConcurrencyWaitProjection {
17
17
  wakeTrigger:
18
18
  | { kind: 'work_terminal'; workId: string }
19
19
  | { kind: 'resource_release'; resourceKeys: string[] }
20
- | { kind: 'controller_release'; workId: string }
21
20
  | { kind: 'scheduler_capacity'; capacityKey: string }
22
21
  | { kind: 'work_contract_change'; workId: string };
23
22
  observedAt: string;
@@ -186,6 +185,8 @@ export interface ManagedProcessRecord {
186
185
  processId: string;
187
186
  repoId: string;
188
187
  checkoutId?: string;
188
+ /** Authenticated principal that owns the handle; opaque ids never authorize by themselves. */
189
+ principalId?: string;
189
190
  /** Optional facade WorkContract that owns this command. */
190
191
  workId?: string;
191
192
  /** Immutable pre-spawn authority required for post-terminal Work reconciliation. */
@@ -288,6 +289,8 @@ export interface SpawnManagedProcessInput {
288
289
  controllerHome: string;
289
290
  repoId: string;
290
291
  checkoutId?: string;
292
+ /** Authenticated principal recorded for principal-bound attachment. */
293
+ principalId?: string;
291
294
  /** Immutable resolved execution identity — required; validated immediately before spawn. */
292
295
  executionIdentity: ResolvedExecutionIdentity;
293
296
  workId?: string;
@@ -306,6 +309,8 @@ export interface SpawnManagedProcessInput {
306
309
  resourceClaims?: ProcessResourceClaim[];
307
310
  checkExecution?: ProcessCheckExecutionIdentity;
308
311
  origin?: ManagedProcessRecord['origin'];
312
+ /** Runtime-owned child allowed to rebind only the exact current Runtime write authority. */
313
+ trustedRuntimeChild?: 'plugin_action_sidecar';
309
314
  runtimeInstanceId?: string;
310
315
  releaseAuthorityRevision?: number;
311
316
  releaseId?: string;
@@ -29,7 +29,6 @@ import { existsSync } from 'fs';
29
29
  import { isAbsolute, relative, resolve, sep } from 'path';
30
30
  import { isAssistantPluginError } from '../../plugins/errors';
31
31
  import { executeWork, validateWork } from '../../control-plane/execution/work-operation-service';
32
- import { finalizeWork } from '../../control-plane/execution/work-finalization-service';
33
32
  import { describeFailure } from '../../../../packages/protocols/failure';
34
33
 
35
34
 
@@ -525,8 +524,7 @@ export async function executeExecutionJob(controllerHome: string, job: Execution
525
524
  // Durable Work mutations execute through control-plane application services.
526
525
  // The Worker must never import MCP transport to obtain Work semantics.
527
526
  const durableWorkOperation = job.payload.operation === 'work_execute'
528
- || job.payload.operation === 'work_validate'
529
- || job.payload.operation === 'work_finalize';
527
+ || job.payload.operation === 'work_validate';
530
528
  const toolArguments = { ...(job.payload.arguments ?? {}) };
531
529
  const workArguments = {
532
530
  ...toolArguments,
@@ -537,9 +535,7 @@ export async function executeExecutionJob(controllerHome: string, job: Execution
537
535
  ? await executeWork(runtimeContext, workArguments)
538
536
  : job.payload.operation === 'work_validate'
539
537
  ? await validateWork(runtimeContext, workArguments)
540
- : job.payload.operation === 'work_finalize'
541
- ? await finalizeWork(runtimeContext, workArguments)
542
- : undefined;
538
+ : undefined;
543
539
  const executionResult: CallToolResult | undefined = durableWorkOperation && executionRecord
544
540
  ? { structuredContent: executionRecord, content: [] }
545
541
  : undefined;
@@ -0,0 +1,130 @@
1
+ import { createHash } from 'crypto';
2
+ import { resolve } from 'path';
3
+ import type { PlatformServiceManagerHost } from './service-manager';
4
+
5
+ export type ForgePersistentServiceOwner = 'forge-core' | 'provider';
6
+ export type ForgePersistentServiceState = 'current' | 'retired';
7
+
8
+ export interface ForgePersistentServiceIdentity {
9
+ id: string;
10
+ owner: ForgePersistentServiceOwner;
11
+ state: ForgePersistentServiceState;
12
+ launchdLabel: string;
13
+ systemdUnitName: string;
14
+ }
15
+
16
+ export const FORGE_RECOVERY_DAEMON_LABEL = 'com.moretea.forge-recovery';
17
+ export const FORGE_RECOVERY_GATEWAY_LABEL = 'com.moretea.forge-recovery-gateway';
18
+ export const FORGE_RECOVERY_WATCHDOG_LABEL = 'com.moretea.forge-recovery-watchdog';
19
+
20
+ const RETIRED_CORE_LABELS = [
21
+ ['legacy-runtime', 'com.moretea.forge.runtime'],
22
+ ['legacy-mcp-gateway', 'com.moretea.forge.mcp-gateway'],
23
+ ['bootstrap-supervisor', 'com.moretea.forge-bootstrap-supervisor'],
24
+ ['evolution-supervisor', 'com.moretea.forge-evolution-supervisor'],
25
+ ['legacy-recovery-gateway', FORGE_RECOVERY_GATEWAY_LABEL],
26
+ ['legacy-recovery-watchdog', FORGE_RECOVERY_WATCHDOG_LABEL],
27
+ ] as const;
28
+
29
+ /**
30
+ * These identities are intentionally outside Forge core lifecycle authority.
31
+ * They are listed to make the negative ownership boundary machine-visible,
32
+ * not to authorize any retirement action.
33
+ */
34
+ export const FORGE_PROVIDER_OWNED_PERSISTENT_SERVICES = [
35
+ 'com.moretea.forge.desktop-operator',
36
+ 'com.moretea.desktop-operator',
37
+ ] as const;
38
+
39
+ function controllerHomeSuffix(controllerHome: string): string {
40
+ return createHash('sha256').update(resolve(controllerHome)).digest('hex').slice(0, 12);
41
+ }
42
+
43
+ export function forgeRuntimePersistentServiceLabel(controllerHome: string): string {
44
+ return `com.moretea.forge.runtime.${controllerHomeSuffix(controllerHome)}`;
45
+ }
46
+
47
+ export function forgeConnectorPersistentServiceLabel(controllerHome: string): string {
48
+ return `com.moretea.forge.mcp-gateway.${controllerHomeSuffix(controllerHome)}`;
49
+ }
50
+
51
+ function identity(
52
+ id: string,
53
+ label: string,
54
+ state: ForgePersistentServiceState,
55
+ ): ForgePersistentServiceIdentity {
56
+ return {
57
+ id,
58
+ owner: 'forge-core',
59
+ state,
60
+ launchdLabel: label,
61
+ systemdUnitName: `${label}.service`,
62
+ };
63
+ }
64
+
65
+ export const FORGE_RETIRED_PERSISTENT_SERVICES: readonly ForgePersistentServiceIdentity[] =
66
+ RETIRED_CORE_LABELS.map(([id, label]) => identity(id, label, 'retired'));
67
+
68
+ export function forgeOwnedPersistentServiceInventory(controllerHome: string): {
69
+ current: ForgePersistentServiceIdentity[];
70
+ retired: readonly ForgePersistentServiceIdentity[];
71
+ providerOwnedExcludedLabels: readonly string[];
72
+ } {
73
+ return {
74
+ current: [
75
+ identity('runtime', forgeRuntimePersistentServiceLabel(controllerHome), 'current'),
76
+ identity('mcp-gateway', forgeConnectorPersistentServiceLabel(controllerHome), 'current'),
77
+ identity('recovery', FORGE_RECOVERY_DAEMON_LABEL, 'current'),
78
+ ],
79
+ retired: FORGE_RETIRED_PERSISTENT_SERVICES,
80
+ providerOwnedExcludedLabels: FORGE_PROVIDER_OWNED_PERSISTENT_SERVICES,
81
+ };
82
+ }
83
+
84
+ export interface ForgeRetiredServiceReconciliation {
85
+ id: string;
86
+ label: string;
87
+ platform: 'launchd' | 'systemd-user';
88
+ serviceWasPresent: boolean;
89
+ artifactWasPresent: boolean;
90
+ retired: boolean;
91
+ }
92
+
93
+ export async function reconcileRetiredForgePersistentServices(input: {
94
+ host: PlatformServiceManagerHost;
95
+ env?: NodeJS.ProcessEnv;
96
+ accountHome?: string;
97
+ }): Promise<ForgeRetiredServiceReconciliation[]> {
98
+ if (!input.host.selection.persistent || input.host.selection.kind === 'portable') return [];
99
+ const results: ForgeRetiredServiceReconciliation[] = [];
100
+ for (const service of FORGE_RETIRED_PERSISTENT_SERVICES) {
101
+ if (input.host.selection.kind === 'launchd') {
102
+ const result = await input.host.retireLaunchdExact({
103
+ label: service.launchdLabel,
104
+ accountHome: input.accountHome,
105
+ });
106
+ results.push({
107
+ id: service.id,
108
+ label: service.launchdLabel,
109
+ platform: 'launchd',
110
+ serviceWasPresent: result.serviceWasPresent,
111
+ artifactWasPresent: result.plistWasPresent,
112
+ retired: result.absentAfter,
113
+ });
114
+ } else {
115
+ const result = input.host.retireSystemdUserExact({
116
+ unitName: service.systemdUnitName,
117
+ env: input.env,
118
+ });
119
+ results.push({
120
+ id: service.id,
121
+ label: service.systemdUnitName,
122
+ platform: 'systemd-user',
123
+ serviceWasPresent: result.serviceWasPresent,
124
+ artifactWasPresent: result.unitFileWasPresent,
125
+ retired: result.absentAfter,
126
+ });
127
+ }
128
+ }
129
+ return results;
130
+ }
@@ -8,6 +8,8 @@ import {
8
8
  installLaunchAgent,
9
9
  launchAgentPath,
10
10
  retireConflictingForgeLaunchAgents,
11
+ retireLaunchAgentExact,
12
+ type ExactLaunchAgentRetirementResult,
11
13
  } from '../../cli/controller/launch-agents';
12
14
  import {
13
15
  installSystemdUserUnit,
@@ -15,6 +17,8 @@ import {
15
17
  systemdUserAvailable,
16
18
  writeSystemdUserUnit,
17
19
  systemdUserInstallCommands,
20
+ retireSystemdUserUnitExact,
21
+ type ExactSystemdUserUnitRetirementResult,
18
22
  type SystemdUserUnitInput,
19
23
  } from '../../cli/controller/systemd-user';
20
24
 
@@ -48,6 +52,8 @@ export interface PlatformServiceManagerHost {
48
52
  bootstrapLaunchd(input: { label: string; plistPath: string }): Promise<{ ok: boolean; diagnostics: string[] }>;
49
53
  bootoutLaunchd(input: { label: string; plistPath: string }): Promise<{ ok: boolean; diagnostics: string[] }>;
50
54
  retireConflictingLaunchd(input: Parameters<typeof retireConflictingForgeLaunchAgents>[0]): ReturnType<typeof retireConflictingForgeLaunchAgents>;
55
+ retireLaunchdExact(input: { label: string; accountHome?: string }): Promise<ExactLaunchAgentRetirementResult>;
56
+ retireSystemdUserExact(input: { unitName: string; env?: NodeJS.ProcessEnv }): ExactSystemdUserUnitRetirementResult;
51
57
  launchdDomain(): string;
52
58
  detachLaunchdBootout(label: string): void;
53
59
  startDetached(input: PlatformDetachedProcessInput): number;
@@ -98,6 +104,8 @@ export function createPlatformServiceManagerHost(input: {
98
104
  bootstrapLaunchd: bootstrapLaunchAgentWithRetryV2,
99
105
  bootoutLaunchd: bootoutLaunchAgentWithRetryV2,
100
106
  retireConflictingLaunchd: retireConflictingForgeLaunchAgents,
107
+ retireLaunchdExact: retireLaunchAgentExact,
108
+ retireSystemdUserExact: retireSystemdUserUnitExact,
101
109
  launchdDomain: currentUserLaunchdDomain,
102
110
  detachLaunchdBootout(label: string): void {
103
111
  if (platform !== 'darwin') return;
@@ -1,13 +1,23 @@
1
+ import { MAX_PLUGIN_ACTION_TIMEOUT_MS } from '../../../packages/plugin-runtime/external/index';
1
2
  import type { RepositoryRecord } from '../../cli/repositories/types';
2
3
  import type { ProcessHandle } from '../execution/process-runtime/types';
3
- import { startLightweightPluginAction, waitLightweightPluginAction } from './lightweight-action';
4
+ import {
5
+ startManagedControllerPluginAction,
6
+ startManagedPluginAction,
7
+ waitManagedControllerPluginAction,
8
+ waitManagedPluginAction,
9
+ } from './lightweight-action';
4
10
  import {
5
11
  executeAssistantPluginDirectNonPersistent,
6
12
  executeAssistantPluginReadDirect,
13
+ executeControllerPluginDirectNonPersistent,
14
+ executeControllerPluginReadDirect,
7
15
  getAssistantPluginManifest,
16
+ getControllerPluginManifest,
8
17
  isDirectNonPersistentPluginAction,
9
18
  isDirectPluginReadAction,
10
19
  submitAssistantPluginAction,
20
+ submitControllerPluginAction,
11
21
  } from './store';
12
22
  import type {
13
23
  AssistantPluginActionDescriptor,
@@ -15,12 +25,19 @@ import type {
15
25
  AssistantPluginManifest,
16
26
  } from './types';
17
27
 
28
+ export const PLUGIN_ACTION_SIDECAR_SETTLEMENT_GRACE_MS = 30_000;
29
+
30
+ export function pluginActionSidecarTimeoutMs(providerTimeoutMs: number): number {
31
+ return providerTimeoutMs + PLUGIN_ACTION_SIDECAR_SETTLEMENT_GRACE_MS;
32
+ }
33
+
18
34
  export type AssistantPluginActionApplicationResult =
19
35
  | {
20
36
  kind: 'direct_read';
21
37
  manifest: AssistantPluginManifest;
22
38
  action: AssistantPluginActionDescriptor;
23
39
  result: Record<string, unknown>;
40
+ receipt: Awaited<ReturnType<typeof executeAssistantPluginReadDirect>>['receipt'];
24
41
  }
25
42
  | {
26
43
  kind: 'direct_non_persistent';
@@ -29,14 +46,14 @@ export type AssistantPluginActionApplicationResult =
29
46
  result: Record<string, unknown>;
30
47
  }
31
48
  | {
32
- kind: 'lightweight_running';
49
+ kind: 'managed_running';
33
50
  manifest: AssistantPluginManifest;
34
51
  action?: AssistantPluginActionDescriptor;
35
52
  requestId: string;
36
53
  process: ProcessHandle;
37
54
  }
38
55
  | {
39
- kind: 'lightweight_failed';
56
+ kind: 'managed_failed';
40
57
  manifest: AssistantPluginManifest;
41
58
  action?: AssistantPluginActionDescriptor;
42
59
  requestId: string;
@@ -56,22 +73,27 @@ export type AssistantPluginActionApplicationResult =
56
73
  */
57
74
  export async function executeAssistantPluginActionApplication(input: {
58
75
  controllerHome: string;
59
- repository: RepositoryRecord;
76
+ scope: { kind: 'controller' } | { kind: 'repository'; repository: RepositoryRecord };
60
77
  request: AssistantPluginActionRequest;
61
78
  interactiveWaitMs?: number;
62
79
  wait?: boolean;
63
80
  waitMs?: number;
64
81
  }): Promise<AssistantPluginActionApplicationResult> {
65
- const manifest = getAssistantPluginManifest(input.controllerHome, input.repository, input.request.pluginId);
82
+ const manifest = input.scope.kind === 'controller'
83
+ ? getControllerPluginManifest(input.controllerHome, input.request.pluginId)
84
+ : getAssistantPluginManifest(input.controllerHome, input.scope.repository, input.request.pluginId);
66
85
  const action = manifest.actions.find((entry) => entry.actionId === input.request.actionId);
67
86
 
68
87
  if (action && isDirectPluginReadAction(action)) {
69
- const direct = await executeAssistantPluginReadDirect(input.controllerHome, input.repository, input.request);
88
+ const direct = input.scope.kind === 'controller'
89
+ ? await executeControllerPluginReadDirect(input.controllerHome, input.request)
90
+ : await executeAssistantPluginReadDirect(input.controllerHome, input.scope.repository, input.request);
70
91
  return {
71
92
  kind: 'direct_read',
72
93
  manifest: direct.manifest,
73
94
  action: direct.action,
74
95
  result: direct.result,
96
+ receipt: direct.receipt,
75
97
  };
76
98
  }
77
99
 
@@ -79,7 +101,9 @@ export async function executeAssistantPluginActionApplication(input: {
79
101
  if (!isDirectNonPersistentPluginAction(action)) {
80
102
  throw new Error(`PLUGIN_DIRECT_NON_PERSISTENT_CONTRACT_INVALID: ${input.request.pluginId}/${input.request.actionId}`);
81
103
  }
82
- const direct = await executeAssistantPluginDirectNonPersistent(input.controllerHome, input.repository, input.request);
104
+ const direct = input.scope.kind === 'controller'
105
+ ? await executeControllerPluginDirectNonPersistent(input.controllerHome, input.request)
106
+ : await executeAssistantPluginDirectNonPersistent(input.controllerHome, input.scope.repository, input.request);
83
107
  return {
84
108
  kind: 'direct_non_persistent',
85
109
  manifest: direct.manifest,
@@ -88,27 +112,57 @@ export async function executeAssistantPluginActionApplication(input: {
88
112
  };
89
113
  }
90
114
 
91
- if (input.repository.repoId !== '__controller__' && action?.executionMode === 'lightweight_process') {
92
- const timeoutMs = Math.max(1_000, input.request.timeoutMs ?? action.defaultTimeoutMs ?? 10 * 60_000);
93
- let { handle } = await startLightweightPluginAction({
94
- controllerHome: input.controllerHome,
95
- repository: input.repository,
96
- request: input.request,
97
- interactiveWaitMs: input.interactiveWaitMs,
98
- timeoutMs,
99
- });
115
+ if (action?.executionMode === 'runtime') {
116
+ // Stateful providers may own in-memory resources whose identity is valid only
117
+ // inside the canonical Runtime process. Keep the normal durable request/effect
118
+ // receipt path, but do not relocate execution into a short-lived sidecar.
119
+ return {
120
+ kind: 'submitted',
121
+ submitted: input.scope.kind === 'controller'
122
+ ? await submitControllerPluginAction(input.controllerHome, input.request)
123
+ : await submitAssistantPluginAction(input.controllerHome, input.scope.repository, input.request),
124
+ };
125
+ }
126
+
127
+ if (action) {
128
+ const requestedTimeoutMs = Number.isFinite(input.request.timeoutMs)
129
+ ? input.request.timeoutMs!
130
+ : action.defaultTimeoutMs;
131
+ const timeoutMs = Math.min(Math.max(1_000, Math.trunc(requestedTimeoutMs)), MAX_PLUGIN_ACTION_TIMEOUT_MS);
132
+ const sidecarTimeoutMs = pluginActionSidecarTimeoutMs(timeoutMs);
133
+ let { handle } = input.scope.kind === 'controller'
134
+ ? await startManagedControllerPluginAction({
135
+ controllerHome: input.controllerHome,
136
+ request: input.request,
137
+ interactiveWaitMs: input.interactiveWaitMs,
138
+ timeoutMs: sidecarTimeoutMs,
139
+ })
140
+ : await startManagedPluginAction({
141
+ controllerHome: input.controllerHome,
142
+ repository: input.scope.repository,
143
+ request: input.request,
144
+ interactiveWaitMs: input.interactiveWaitMs,
145
+ timeoutMs: sidecarTimeoutMs,
146
+ });
100
147
  if (!handle.completed && input.wait === true) {
101
- handle = await waitLightweightPluginAction(
102
- input.controllerHome,
103
- input.repository.repoId,
104
- handle.processId,
105
- Math.max(1, input.waitMs ?? 15_000),
106
- input.request.signal,
107
- );
148
+ handle = input.scope.kind === 'controller'
149
+ ? await waitManagedControllerPluginAction(
150
+ input.controllerHome,
151
+ handle.processId,
152
+ Math.max(1, input.waitMs ?? 15_000),
153
+ input.request.signal,
154
+ )
155
+ : await waitManagedPluginAction(
156
+ input.controllerHome,
157
+ input.scope.repository.repoId,
158
+ handle.processId,
159
+ Math.max(1, input.waitMs ?? 15_000),
160
+ input.request.signal,
161
+ );
108
162
  }
109
163
  if (!handle.completed) {
110
164
  return {
111
- kind: 'lightweight_running',
165
+ kind: 'managed_running',
112
166
  manifest,
113
167
  action,
114
168
  requestId: input.request.requestId,
@@ -117,19 +171,22 @@ export async function executeAssistantPluginActionApplication(input: {
117
171
  }
118
172
  if (!handle.ok) {
119
173
  return {
120
- kind: 'lightweight_failed',
174
+ kind: 'managed_failed',
121
175
  manifest,
122
176
  action,
123
177
  requestId: input.request.requestId,
124
178
  process: handle,
125
179
  };
126
180
  }
127
- // The sidecar writes the authoritative receipt. Re-enter the deterministic
128
- // store with the same request id to read/bind that receipt without replay.
181
+ // The durable sidecar writes the authoritative receipt. Re-enter the
182
+ // deterministic store with the same request id to bind/read it without
183
+ // replaying the provider effect.
129
184
  }
130
185
 
131
186
  return {
132
187
  kind: 'submitted',
133
- submitted: await submitAssistantPluginAction(input.controllerHome, input.repository, input.request),
188
+ submitted: input.scope.kind === 'controller'
189
+ ? await submitControllerPluginAction(input.controllerHome, input.request)
190
+ : await submitAssistantPluginAction(input.controllerHome, input.scope.repository, input.request),
134
191
  };
135
192
  }
@@ -16,6 +16,7 @@ import { readRepositoryPluginConfig, writeRepositoryPluginConfig } from './confi
16
16
  import { buildQueryString, encodeBase64Url, stableMockId } from './google-shared';
17
17
 
18
18
  const APP_STORE_CONNECT_PLUGIN_ID = 'app_store_connect';
19
+ const CONTROLLER_PLUGIN_CONFIG_SCOPE = 'controller:global';
19
20
  const API_BASE_URL = 'https://api.appstoreconnect.apple.com';
20
21
  const DEFAULT_TIMEOUT_MS = 60_000;
21
22
  const PRIVATE_KEY_READ_MAX_ATTEMPTS = 4;
@@ -107,7 +108,7 @@ function repositoryConfig(repoRoot: string, controllerHome?: string, repoId?: st
107
108
 
108
109
  function loadConfig(repoRoot: string, controllerHome?: string, repoId?: string): AppStoreConnectPluginConfig {
109
110
  const global = controllerHome ? readConfigFile(globalConfigPath(controllerHome)) : undefined;
110
- if (repoId === CONTROLLER_SCOPE_REPO_ID) return normalizeConfig(global ?? {});
111
+ if (repoId === CONTROLLER_SCOPE_REPO_ID || repoId === CONTROLLER_PLUGIN_CONFIG_SCOPE) return normalizeConfig(global ?? {});
111
112
  const local = repositoryConfig(repoRoot, controllerHome, repoId);
112
113
  return normalizeConfig({ ...(global ?? {}), ...(local ?? {}) });
113
114
  }
@@ -123,7 +124,7 @@ function saveConfig(
123
124
  repoId?: string,
124
125
  ): AppStoreConnectPluginConfig {
125
126
  const cleanPatch = definedPatch(patch);
126
- if (controllerHome && repoId === CONTROLLER_SCOPE_REPO_ID) {
127
+ if (controllerHome && repoId === CONTROLLER_PLUGIN_CONFIG_SCOPE) {
127
128
  const path = globalConfigPath(controllerHome);
128
129
  const next = normalizeConfig({ ...(readConfigFile(path) ?? {}), ...cleanPatch });
129
130
  mkdirSync(dirname(path), { recursive: true });
@@ -131,6 +132,7 @@ function saveConfig(
131
132
  return next;
132
133
  }
133
134
 
135
+ if (repoId === CONTROLLER_SCOPE_REPO_ID) throw new Error('APP_STORE_CONNECT_LEGACY_CONTROLLER_SCOPE_WRITE_RETIRED');
134
136
  if (!controllerHome || !repoId) throw new Error('APP_STORE_CONNECT_CONTROLLER_CONTEXT_REQUIRED');
135
137
  // Repository state is an overlay only. Do not materialize inherited global
136
138
  // credential references into every repository just because configure ran.
@@ -199,9 +201,9 @@ async function readPrivateKeyFile(path: string, source: string): Promise<{ key?:
199
201
  }
200
202
  if (code === 'EDEADLK') {
201
203
  throw new AssistantPluginError(
202
- 'PLUGIN_PROVIDER_UNAVAILABLE',
203
- 'App Store Connect private key is temporarily unavailable because the filesystem is busy.',
204
- { retryable: true, details: { credentialSource: source, code } },
204
+ 'PLUGIN_AUTH_REQUIRED',
205
+ 'Configured App Store Connect private key is not locally available. Keep File Provider/iCloud credentials downloaded or configure a stable local private_key_path.',
206
+ { retryable: false, details: { credentialSource: source, code, localCredentialUnavailable: true } },
205
207
  );
206
208
  }
207
209
  throw new AssistantPluginError(
@@ -211,7 +213,11 @@ async function readPrivateKeyFile(path: string, source: string): Promise<{ key?:
211
213
  );
212
214
  }
213
215
  }
214
- throw new AssistantPluginError('PLUGIN_PROVIDER_UNAVAILABLE', 'App Store Connect private key is temporarily unavailable.', { retryable: true });
216
+ throw new AssistantPluginError(
217
+ 'PLUGIN_AUTH_REQUIRED',
218
+ 'Configured App Store Connect private key is not locally available.',
219
+ { retryable: false, details: { credentialSource: source, localCredentialUnavailable: true } },
220
+ );
215
221
  }
216
222
 
217
223
  async function privateKeyMaterial(config: AppStoreConnectPluginConfig): Promise<{ key?: string; source?: string; warning?: string }> {
@@ -223,6 +229,23 @@ async function privateKeyMaterial(config: AppStoreConnectPluginConfig): Promise<
223
229
  return {};
224
230
  }
225
231
 
232
+ async function resolveLiveAuthStatus(config: AppStoreConnectPluginConfig): Promise<AppStoreConnectAuthState> {
233
+ const auth = resolveAuth(config);
234
+ if (config.provider !== 'app-store-connect-api' || !config.enabled || !auth.ready) return auth;
235
+ try {
236
+ const material = await privateKeyMaterial(config);
237
+ if (material.key) return auth;
238
+ const detail = material.warning ?? 'Configured App Store Connect private key is not locally readable.';
239
+ return { ...auth, ready: false, authenticated: false, errors: [...auth.errors, detail] };
240
+ } catch (error) {
241
+ if (error instanceof AssistantPluginError && error.code === 'PLUGIN_AUTH_REQUIRED') {
242
+ const detail = error.message.replace(/^PLUGIN_AUTH_REQUIRED:\s*/, '');
243
+ return { ...auth, ready: false, authenticated: false, errors: [...auth.errors, detail] };
244
+ }
245
+ throw error;
246
+ }
247
+ }
248
+
226
249
  function resolveAuth(config: AppStoreConnectPluginConfig): AppStoreConnectAuthState {
227
250
  if (config.provider === 'mock') {
228
251
  return {
@@ -860,15 +883,16 @@ export async function executeAppStoreConnectPluginAction(input: AssistantPluginA
860
883
  if (config.provider === 'mock') return mockResponse(input.actionId, input.args, config);
861
884
  const auth = resolveAuth(config);
862
885
  if (input.actionId === 'auth_status') {
886
+ const liveAuth = await resolveLiveAuthStatus(config);
863
887
  return {
864
- ready: config.enabled && auth.ready,
865
- provider: auth.provider,
866
- issuerId: auth.issuerId ? 'configured' : undefined,
867
- keyId: auth.keyId ? 'configured' : undefined,
868
- credentialSource: auth.credentialSource,
869
- errors: auth.errors,
870
- warnings: auth.warnings,
871
- userFacingStatus: userFacingAscStatus(config, auth),
888
+ ready: config.enabled && liveAuth.ready,
889
+ provider: liveAuth.provider,
890
+ issuerId: liveAuth.issuerId ? 'configured' : undefined,
891
+ keyId: liveAuth.keyId ? 'configured' : undefined,
892
+ credentialSource: liveAuth.credentialSource,
893
+ errors: liveAuth.errors,
894
+ warnings: liveAuth.warnings,
895
+ userFacingStatus: userFacingAscStatus(config, liveAuth),
872
896
  };
873
897
  }
874
898
  if (!config.enabled || !auth.ready) throw new AssistantPluginError('PLUGIN_NOT_READY', 'App Store Connect plugin is not ready.', { retryable: false, details: { enabled: config.enabled, errors: auth.errors } });