@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
@@ -4,34 +4,55 @@ import { runProcess } from '../../../src/effects/process-runner';
4
4
  import type { MultiRepositoryMcpToolContext } from "../multi-repository";
5
5
  import { allControllerToolDefinitions, controllerExposureSnapshot, controllerToolSurfaceStatus } from "../toolset";
6
6
  import { result } from "./result-adapter";
7
- import { selected } from "./shared-adapter";
8
- import { reconcileReadinessProjectionSource } from "../readiness-projection";
9
- import { listExecutionJobs } from "../../../src/runtime/execution/jobs/store";
7
+ import { selected, selectedOptional } from "./shared-adapter";
8
+ import { SEMANTIC_SCOPE_KEY } from "../../../src/cli/repositories/controller-home";
10
9
  import type { ExecutionJob } from '../../../src/runtime/execution/jobs/types';
11
10
  import { getProcessRecord, isManagedProcessActive, processRuntimeResourceDiagnostics } from "../../../src/runtime/execution/process-runtime";
12
- import { readForgeRuntimeStatus } from "../../../src/runtime/control-plane/runtime-status-client";
13
- import { readSchedulerHealthSnapshot } from "../../../src/runtime/control-plane/global-scheduler/scheduler";
14
- import { evaluateActiveRuntimeSourceDrift, formatRuntimeSourceDriftMessage, readRuntimeGeneration, type RuntimeSourceIdentity } from "../../../src/runtime/control-plane/runtime-generation";
15
- import { projectionObservation, readRepositoryProjectionSnapshot } from "../../../src/runtime/projections/materialized-view";
16
- import { buildRuntimeOperationalView, classifyRuntimeReadinessSemantics, evaluateRuntimeHealth, RUNTIME_HEALTH_THRESHOLDS, type RuntimeOperationalView, type GradedObservation } from "../../../src/runtime/health";
17
- import { buildControllerTaskLedgerProjection } from "../../../src/cli/controller/task-ledger";
18
- import { legacyIssueAuthorityRetired } from "../../../src/cli/controller/legacy-issue-cutover";
11
+ import { formatRuntimeSourceDriftMessage, readRuntimeGeneration } from "../../../src/runtime/control-plane/runtime-generation";
19
12
  import { listControllerChecks } from "../../../src/cli/controller/check-runner";
20
13
  import { buildCheckExecutionSchedule } from "../../../src/runtime/execution/process-runtime/check-scheduling";
21
- import { FORGE_MCP_SCHEMA_VERSION, FORGE_TOOL_SURFACE, FORGE_VERSION } from "../../../src/cli/controller/runtime-config";
22
- import { resolveLocalBridgeSurface } from "../../../src/runtime/shared/local-bridge-surface";
23
14
  import { listAssistantPluginManifests } from "../../../src/runtime/plugins/store";
24
15
  import { cachedGitIdentity, gitSnapshot } from "../../../src/cli/repository/inspector";
25
16
  import { buildRuntimeMaintenanceStatus } from "../../../src/runtime/recovery";
26
- import { allowedFacadeOperations, buildFacadeResult, listCapabilityDescriptors, summarizeCapabilityGroups, listHandoffAttentionItems, listHandoffItems, normalizeCheckIds, buildWorkContinuationSnapshot, listPlanContracts, summarizePlanContract, runHandoffInboxApplication, type FacadeTool } from "../../../src/runtime/control-plane/facade";
17
+ import { allowedFacadeOperations, buildFacadeResult, listCapabilityDescriptors, summarizeCapabilityGroups, listHandoffAttentionItems, normalizeCheckIds, buildWorkContinuationSnapshot, listPlanContracts, summarizePlanContract, runHandoffInboxApplication, type FacadeTool } from "../../../src/runtime/control-plane/facade";
27
18
  import { buildJobOperationDigest } from '../../../src/runtime/control-plane/facade/operation-digest';
28
19
  import { readActiveWorkCandidates, type InvalidActiveWorkCandidate } from "../../../packages/kernel/work/api/index";
29
20
  import { observeRuntimeStatus } from "../../../src/runtime/root/status";
30
21
  import { getControllerSession } from "../../../packages/kernel/controller/api/index";
22
+ import { listActiveOccurrences, listSchedules, scheduleOwnsWork } from "../../../packages/kernel/scheduler/api/index";
31
23
  import { summarizeHandoffItem } from '../../../src/runtime/control-plane/facade';
32
24
  import type { CallToolResult } from '../../../packages/protocols/mcp/tool-contract';
33
- import { handoffResolvedContinuationEventName, triggerWorkContinuationRepositoryEvent } from '../../../src/runtime/workflow/schedules/work-continuation';
25
+ import { triggerResolvedHandoffContinuation } from '../../../src/runtime/workflow/schedules/work-continuation';
26
+ import { getUserRequest, listUserRequests, recordUserRequest, resolveUserRequest, type UserRequest } from '../../../packages/kernel/identity/api/index';
27
+ import { controllerReadinessEvidence, runtimeSourceSnapshotStatus } from './runtime-readiness-observation';
28
+ import { readRuntimeReleaseAuthority } from '../../../src/runtime/root/release-store';
29
+ import { getWorkflowSupervisorConsumerStatus, getWorkflowSupervisorContinuationProof } from '../../../supervisor/client';
30
+ import { resolveWorkflowSupervisorForgeHome } from '../../../supervisor/paths';
31
+ export { ageMs, probeLocalControllerHealth, localControllerDiagnosticMatchesRuntime, controllerReadinessEvidence, runtimeSourceSnapshotStatus } from './runtime-readiness-observation';
32
+ export type { ControllerReadinessSignals } from './runtime-readiness-observation';
34
33
 
34
+ export const PRIMARY_WORK_RUNTIME_ACTIVITIES = [
35
+ 'running',
36
+ 'waiting_for_user',
37
+ 'scheduled',
38
+ 'recoverable',
39
+ 'needs_reconciliation',
40
+ ] as const;
41
+ export type PrimaryWorkRuntimeActivity = (typeof PRIMARY_WORK_RUNTIME_ACTIVITIES)[number];
42
+
43
+ /** Read-only runtime projection. These facts never mutate or extend semantic Work state. */
44
+ export function primaryWorkRuntimeActivity(facts: {
45
+ running: boolean;
46
+ waitingForUser: boolean;
47
+ scheduled: boolean;
48
+ needsReconciliation: boolean;
49
+ }): PrimaryWorkRuntimeActivity {
50
+ if (facts.running) return 'running';
51
+ if (facts.waitingForUser) return 'waiting_for_user';
52
+ if (facts.scheduled) return 'scheduled';
53
+ if (facts.needsReconciliation) return 'needs_reconciliation';
54
+ return 'recoverable';
55
+ }
35
56
 
36
57
  export const GIT_IDENTITY_SAMPLE_TTL_MS = Math.max(1_000, Number(process.env.FORGE_GIT_IDENTITY_SAMPLE_TTL_MS ?? 3_000));
37
58
 
@@ -79,7 +100,7 @@ export function summarizeWorkListItem(job: ExecutionJob): Record<string, unknown
79
100
  createdAt: job.createdAt,
80
101
  updatedAt: job.updatedAt,
81
102
  suggestedNextAction: digest.suggestedNextActions[0],
82
- detailPointer: { tool: 'work_get', work_id: job.jobId },
103
+ detailPointer: { tool: 'rh_work', operation: 'get', work_id: job.jobId },
83
104
  };
84
105
  }
85
106
 
@@ -103,210 +124,6 @@ export function invalidFacadeOperation(tool: FacadeTool, operation: string): Cal
103
124
  }
104
125
 
105
126
 
106
- export function ageMs(value: string | undefined): number | undefined {
107
- if (!value) return undefined;
108
- const parsed = Date.parse(value);
109
- return Number.isFinite(parsed) ? Math.max(0, Date.now() - parsed) : undefined;
110
- }
111
-
112
- export async function probeLocalControllerHealth(endpoint: string | undefined): Promise<Record<string, unknown> | null> {
113
- if (!endpoint) return null;
114
- const controller = new AbortController();
115
- const timeout = setTimeout(() => controller.abort(), 1_500);
116
- try {
117
- const url = new URL(endpoint);
118
- url.pathname = '/health';
119
- url.search = '';
120
- url.hash = '';
121
- const response = await fetch(url, { signal: controller.signal, headers: { accept: 'application/json' } });
122
- if (!response.ok) return null;
123
- return await response.json() as Record<string, unknown>;
124
- } catch {
125
- return null;
126
- } finally {
127
- clearTimeout(timeout);
128
- }
129
- }
130
-
131
- export function localControllerDiagnosticMatchesRuntime(
132
- payload: Record<string, unknown> | null,
133
- expected: { generation?: string } = {},
134
- ): boolean {
135
- return payload?.status === 'ok'
136
- && payload.toolSurface === FORGE_TOOL_SURFACE
137
- && payload.schemaVersion === FORGE_MCP_SCHEMA_VERSION
138
- && payload.version === FORGE_VERSION
139
- && (expected.generation === undefined || payload.generation === expected.generation);
140
- }
141
-
142
- export interface ControllerReadinessSignals {
143
- externalEndpoint?: GradedObservation;
144
- mcpHandshake?: GradedObservation;
145
- sessionContinuity?: GradedObservation;
146
- }
147
-
148
- export async function controllerReadinessEvidence(
149
- ctx: MultiRepositoryMcpToolContext,
150
- repository = ctx.explicitRepository,
151
- signals: ControllerReadinessSignals = {},
152
- ) {
153
- const daemon = readForgeRuntimeStatus(ctx.controllerHome);
154
- const scheduler = readSchedulerHealthSnapshot(ctx.controllerHome);
155
- const projectionSnapshot = repository ? readRepositoryProjectionSnapshot(ctx.controllerHome, repository.repoId) : undefined;
156
- const projection = projectionSnapshot?.projection;
157
- const taskLedger = repository && !legacyIssueAuthorityRetired(repository.canonicalRoot)
158
- ? buildControllerTaskLedgerProjection(repository.canonicalRoot)
159
- : undefined;
160
- const projectionReconciliation = projectionSnapshot
161
- ? reconcileReadinessProjectionSource(projectionSnapshot, taskLedger)
162
- : undefined;
163
- const localBridgeSurface = repository
164
- ? resolveLocalBridgeSurface({
165
- controllerHome: ctx.controllerHome,
166
- repoRoot: repository.canonicalRoot,
167
- allowProcessScan: false,
168
- })
169
- : undefined;
170
- const localBridgeEndpoint = localBridgeSurface?.endpoint;
171
- const shouldProbeLocalBridge = Boolean(
172
- localBridgeSurface?.enabled
173
- && localBridgeSurface.endpointConfigured
174
- && localBridgeEndpoint
175
- && localBridgeSurface.mode !== 'disabled',
176
- );
177
- const localBridgeLiveHealth = shouldProbeLocalBridge
178
- ? await probeLocalControllerHealth(localBridgeEndpoint)
179
- : null;
180
- const localBridgeEndpointReachable = localBridgeLiveHealth !== null;
181
- const localBridgeExpectedSurface = shouldProbeLocalBridge
182
- ? localControllerDiagnosticMatchesRuntime(localBridgeLiveHealth, {
183
- generation: localBridgeSurface?.generation,
184
- })
185
- : true;
186
- const schedulerHeartbeatAgeMs = ageMs(scheduler.lastTickAt);
187
- const dispatchHeartbeatAgeMs = ageMs(scheduler.lastDispatchAt);
188
- const localBridgeObservation = {
189
- enabled: localBridgeSurface?.enabled ?? false,
190
- requiredForReadiness: localBridgeSurface?.requiredForReadiness ?? false,
191
- mode: localBridgeSurface?.mode ?? ('disabled' as const),
192
- endpoint: localBridgeEndpoint,
193
- endpointReachable: shouldProbeLocalBridge ? localBridgeEndpointReachable : true,
194
- expectedSurface: localBridgeExpectedSurface,
195
- processAlive: localBridgeSurface?.processRunning,
196
- runtimeStateFresh: localBridgeSurface?.source === 'service-runtime'
197
- || localBridgeSurface?.source === 'repo-runtime',
198
- error: localBridgeSurface?.error,
199
- };
200
- const runtimeHealth = evaluateRuntimeHealth({
201
- daemon: {
202
- status: daemon.status,
203
- error: daemon.error,
204
- // Scheduler ticks are emitted by the Canonical Forge Runtime process and provide
205
- // its continuously refreshed heartbeat without introducing a second timer.
206
- heartbeatAgeMs: schedulerHeartbeatAgeMs,
207
- },
208
- scheduler: {
209
- status: daemon.degraded ? 'degraded' : daemon.status,
210
- heartbeatAgeMs: schedulerHeartbeatAgeMs,
211
- dispatchHeartbeatAgeMs,
212
- },
213
- workers: {
214
- queueDepth: projection?.queueDepth,
215
- runningWorkers: projection?.runningWorkers,
216
- activeLeases: projection?.activeLeases,
217
- activeAttentionCount: projection?.currentAttention.length,
218
- },
219
- projection: projectionSnapshot ? projectionObservation(projectionSnapshot, projectionReconciliation) : {
220
- readable: true,
221
- persisted: true,
222
- },
223
- localBridge: localBridgeObservation,
224
- runtimeStorage: { readable: true, ready: true },
225
- ...signals,
226
- });
227
- const operationalView: RuntimeOperationalView = buildRuntimeOperationalView({
228
- health: runtimeHealth,
229
- handoffs: repository
230
- ? listHandoffItems({ controllerHome: ctx.controllerHome, repoId: repository.repoId, status: 'all', limit: 100 })
231
- : [],
232
- jobs: repository ? listExecutionJobs(ctx.controllerHome, repository.repoId, 100) : [],
233
- });
234
- const reasons: Array<{ code: string; message: string }> = runtimeHealth.activeBlockers.map((item) => ({
235
- code: item.code === 'SCHEDULER_NOT_PROGRESSING'
236
- ? 'DISPATCH_LOOP_STALLED'
237
- : item.code === 'LEASE_WITHOUT_WORKER' || item.code === 'WORKER_NOT_RUNNING'
238
- ? 'WORKER_NOT_RUNNING'
239
- : item.code,
240
- message: item.message,
241
- }));
242
- if (
243
- reasons.some((item) => item.code === 'WORKER_NOT_RUNNING')
244
- && (dispatchHeartbeatAgeMs === undefined || dispatchHeartbeatAgeMs > RUNTIME_HEALTH_THRESHOLDS.queueProgressStaleMs)
245
- ) {
246
- reasons.push({
247
- code: 'QUEUE_NOT_PROGRESSING',
248
- message: 'Queued Jobs have not received a recent dispatch heartbeat.',
249
- });
250
- }
251
- const ready = runtimeHealth.ready;
252
- return {
253
- ready,
254
- state: ready ? runtimeHealth.state === 'healthy' ? 'ready' as const : 'degraded' as const : daemon.status === 'ready' ? 'degraded' as const : 'not_ready' as const,
255
- reasons,
256
- warnings: runtimeHealth.warnings.map((item) => ({ code: item.code, message: item.message })),
257
- health: runtimeHealth,
258
- operationalView,
259
- daemon,
260
- durableScheduler: {
261
- status: runtimeHealth.components.scheduler.ready ? 'ready' : daemon.status === 'ready' ? 'degraded' : 'not_ready',
262
- loopStartedAt: scheduler.loopStartedAt,
263
- lastTickAt: scheduler.lastTickAt,
264
- lastDispatchAt: scheduler.lastDispatchAt,
265
- lastReconcileAt: scheduler.lastReconcileAt,
266
- heartbeatAgeMs: schedulerHeartbeatAgeMs,
267
- dispatchHeartbeatAgeMs,
268
- },
269
- workerLoop: {
270
- status: projection?.runningWorkers ? 'running' : projection?.queueDepth ? 'idle' : 'ready',
271
- queueDepth: projection?.queueDepth ?? 0,
272
- runningWorkers: projection?.runningWorkers ?? 0,
273
- activeLeases: projection?.activeLeases ?? 0,
274
- activeAttentionCount: projection?.currentAttention.length ?? 0,
275
- consuming: (projection?.queueDepth ?? 0) === 0 || (projection?.runningWorkers ?? 0) > 0,
276
- },
277
- localBridge: repository ? {
278
- running: Boolean(localBridgeSurface?.enabled)
279
- && runtimeHealth.components.localBridge.ready
280
- && (!shouldProbeLocalBridge || (localBridgeEndpointReachable && localBridgeExpectedSurface)),
281
- endpoint: localBridgeEndpoint,
282
- error: localBridgeSurface?.error,
283
- inferredPid: localBridgeSurface?.pid,
284
- statusSource: localBridgeSurface?.source ?? 'none',
285
- health: runtimeHealth.components.localBridge,
286
- } : undefined,
287
- projection,
288
- projectionSnapshot,
289
- taskLedger,
290
- projectionReconciliation,
291
- semantics: classifyRuntimeReadinessSemantics(runtimeHealth),
292
- };
293
- }
294
-
295
- export function runtimeSourceSnapshotStatus(
296
- active: RuntimeSourceIdentity | undefined,
297
- currentRuntimeRoot?: string,
298
- ) {
299
- const drift = evaluateActiveRuntimeSourceDrift(active, {
300
- currentRuntimeRoot,
301
- });
302
- return {
303
- current: drift.current,
304
- restartRequired: drift.restartRequired,
305
- reasons: drift.reasons,
306
- code: drift.code,
307
- };
308
- }
309
-
310
127
  export function repositoryExecutionReadiness(
311
128
  repoRoot: string,
312
129
  availableChecks: ReturnType<typeof listControllerChecks>,
@@ -406,21 +223,35 @@ export async function callStatusInboxAdapter(
406
223
  ports: StatusInboxAdapterPorts,
407
224
  ): Promise<CallToolResult | undefined> {
408
225
  if (name === 'rh_status') {
409
- const repository = selected(ctx, args);
226
+ const repository = selectedOptional(ctx, args);
410
227
  const operation = String(args.operation ?? 'get');
411
228
  if (!allowedFacadeOperations('rh_status').includes(operation)) {
412
229
  return invalidFacadeOperation('rh_status', operation);
413
230
  }
414
- const store = {
415
- controllerHome: ctx.controllerHome,
416
- repoId: repository.repoId,
417
- revisionContains: (ancestorRevision: string, descendantRevision: string) =>
418
- repositoryRevisionContains(repository.canonicalRoot, ancestorRevision, descendantRevision),
419
- };
231
+ // Instance-level status stays available with zero (or several) registered
232
+ // repositories: only the repository-derived sections need a target.
233
+ const store = repository
234
+ ? {
235
+ controllerHome: ctx.controllerHome,
236
+ repoId: repository.repoId,
237
+ revisionContains: (ancestorRevision: string, descendantRevision: string) =>
238
+ repositoryRevisionContains(repository.canonicalRoot, ancestorRevision, descendantRevision),
239
+ }
240
+ : undefined;
420
241
  if (operation === 'repair') {
242
+ if (!repository) {
243
+ return result(buildFacadeResult({
244
+ status: 'blocked',
245
+ summary: 'REPOSITORY_CONTEXT_REQUIRED_FOR_REPAIR: rh_status repair needs an explicit repository target.',
246
+ data: { operation, repositoryContext: null },
247
+ }) as unknown as Record<string, unknown>, true);
248
+ }
421
249
  return await ports.repair(ctx, repository, args);
422
250
  }
423
- const detailLevel = args.detail_level === 'detail' ? 'detail' : 'summary';
251
+ const requestedDetailLevel = args.detail_level === 'detail' ? 'detail' : 'summary';
252
+ // Repository detail needs a repository; the instance-level summary remains
253
+ // available and reports the downgrade explicitly instead of failing.
254
+ const detailLevel = repository ? requestedDetailLevel : 'summary';
424
255
  if (detailLevel === 'summary') {
425
256
  const startedAt = performance.now();
426
257
  let summaryTimingMark = startedAt;
@@ -435,8 +266,8 @@ export async function callStatusInboxAdapter(
435
266
  // Summary answers only whether this repository can work now. Reuse one
436
267
  // porcelain-v2 sample for branch/HEAD/dirty and avoid the full Git
437
268
  // status/diff-stat, access-policy, and inventory construction paths.
438
- const repositoryIdentity = cachedGitIdentity(repository.canonicalRoot);
439
- const repositoryIdentityAgeMs = Math.max(0, Date.now() - repositoryIdentity.sampledAt);
269
+ const repositoryIdentity = repository ? cachedGitIdentity(repository.canonicalRoot) : undefined;
270
+ const repositoryIdentityAgeMs = repositoryIdentity ? Math.max(0, Date.now() - repositoryIdentity.sampledAt) : undefined;
440
271
  markSummaryPhase('git');
441
272
  const runtimeGeneration = readRuntimeGeneration(ctx.controllerHome);
442
273
  const runtimeSource = runtimeSourceSnapshotStatus(
@@ -457,29 +288,39 @@ export async function callStatusInboxAdapter(
457
288
  : 'RUNTIME_SOURCE_SNAPSHOT_STALE');
458
289
  const runtimeReadiness = observation.snapshot?.readiness;
459
290
  const releaseDiagnostic = runtimeReadiness?.diagnostics.releaseCoherence;
460
- const activeWorkProjection = readActiveWorkCandidates({ ...store, limit: 3 });
291
+ const activeWorkProjection = repository && store
292
+ ? readActiveWorkCandidates({ ...store, limit: 3 })
293
+ : { contracts: [], invalid: [] };
461
294
  const activeWorkSnapshot = activeWorkProjection.contracts.map((entry) => ({
462
295
  workId: entry.workId,
463
- status: entry.status,
464
- mode: entry.mode,
296
+ state: entry.semanticState,
465
297
  objective: entry.objective.slice(0, 160),
466
298
  semantics: buildWorkContinuationSnapshot(entry).semantics,
467
299
  nextSafeAction: buildWorkContinuationSnapshot(entry).nextSafeAction,
468
300
  }));
469
- const activePlanSnapshot = listPlanContracts({ ...store, status: 'active', limit: 3 }).map(summarizePlanContract);
470
- const pendingHandoffAttention = listHandoffAttentionItems(store, 100);
301
+ // Plans are authored semantic context: without a repository target the
302
+ // instance-level semantic scope carries them.
303
+ const activePlanSnapshot = (repository && store
304
+ ? listPlanContracts({ ...store, status: 'active', limit: 3 })
305
+ : listPlanContracts({ controllerHome: ctx.controllerHome, scopeKey: SEMANTIC_SCOPE_KEY, status: 'active', limit: 3 })
306
+ ).map(summarizePlanContract);
307
+ const pendingHandoffAttention = store ? listHandoffAttentionItems(store, 100) : [];
471
308
  const pendingHandoffSnapshot = pendingHandoffAttention.slice(0, 4);
472
309
  const pendingHandoffCount = pendingHandoffAttention.length;
473
310
  markSummaryPhase('controller_state');
474
- const preferredFacadeTools = ['rh_access', 'rh_status', 'rh_inbox', 'rh_context', 'rh_work'] as const;
311
+ const preferredFacadeTools = ['rh_access', 'rh_status', 'rh_inbox', 'rh_context', 'rh_work', 'capability_execute'] as const;
475
312
  const facade = buildFacadeResult({
476
313
  status: ready ? 'ok' : 'blocked',
477
314
  summary: ready ? 'Controller and MCP tool surface are ready for bounded work.' : 'Controller or MCP tool surface needs attention before work.',
478
315
  data: {
479
316
  operation,
480
- repoId: repository.repoId,
317
+ ...(repository ? { repoId: repository.repoId } : {}),
318
+ /** Null means this answer is ForgeInstance-scoped, not repository-scoped. */
319
+ repositoryContext: repository ? { repoId: repository.repoId, checkoutId: repository.activeCheckoutId } : null,
320
+ requestedDetailLevel,
481
321
  readiness: {
482
322
  ready,
323
+ readyFor: 'bounded_execution',
483
324
  reasonCodes: [...new Set(reasonCodes)],
484
325
  diagnostics: {
485
326
  runtime: { ready: observation.ready },
@@ -503,6 +344,11 @@ export async function callStatusInboxAdapter(
503
344
  },
504
345
  semantics: {
505
346
  executionReady: observation.ready,
347
+ // Summary is intentionally the cheap Runtime snapshot path. It
348
+ // reports bounded execution readiness without pretending that the
349
+ // full scheduler/worker diagnostics for unattended continuation ran.
350
+ autonomousContinuationReady: null,
351
+ autonomousContinuationBlockers: null,
506
352
  maintenanceHealthy: null,
507
353
  maintenanceCandidateCount: 0,
508
354
  releaseReady: releaseDiagnostic?.outcome === 'pass',
@@ -513,21 +359,23 @@ export async function callStatusInboxAdapter(
513
359
  },
514
360
  observedAt: observation.observedAt,
515
361
  },
516
- repositoryState: {
517
- branch: repositoryIdentity.branch,
518
- head: repositoryIdentity.head,
519
- dirty: repositoryIdentity.dirty,
520
- observedAt: new Date(repositoryIdentity.sampledAt).toISOString(),
521
- observationAgeMs: repositoryIdentityAgeMs,
522
- observationMaxAgeMs: GIT_IDENTITY_SAMPLE_TTL_MS,
523
- observationPolicy: 'bounded_sample_with_mutation_invalidation',
524
- sourceSnapshotAgeMs: runtimeGeneration?.source.observedAt
525
- ? Math.max(0, Date.now() - Date.parse(runtimeGeneration.source.observedAt))
526
- : undefined,
527
- sourceSnapshotStale,
528
- sourceSnapshotReasons: runtimeSource.reasons,
529
- runtimeSourceDirty: runtimeSource.current?.dirty === true,
530
- },
362
+ repositoryState: repositoryIdentity
363
+ ? {
364
+ branch: repositoryIdentity.branch,
365
+ head: repositoryIdentity.head,
366
+ dirty: repositoryIdentity.dirty,
367
+ observedAt: new Date(repositoryIdentity.sampledAt).toISOString(),
368
+ observationAgeMs: repositoryIdentityAgeMs,
369
+ observationMaxAgeMs: GIT_IDENTITY_SAMPLE_TTL_MS,
370
+ observationPolicy: 'bounded_sample_with_mutation_invalidation',
371
+ sourceSnapshotAgeMs: runtimeGeneration?.source.observedAt
372
+ ? Math.max(0, Date.now() - Date.parse(runtimeGeneration.source.observedAt))
373
+ : undefined,
374
+ sourceSnapshotStale,
375
+ sourceSnapshotReasons: runtimeSource.reasons,
376
+ runtimeSourceDirty: runtimeSource.current?.dirty === true,
377
+ }
378
+ : null,
531
379
  toolArchitecture: {
532
380
  facadeTools: [...preferredFacadeTools],
533
381
  domainSchemaLoading: 'status_summary_runtime_snapshot',
@@ -581,6 +429,15 @@ export async function callStatusInboxAdapter(
581
429
  (payload.responseMeta as { structuredPayloadBytes: number }).structuredPayloadBytes = Buffer.byteLength(JSON.stringify(payload), 'utf8');
582
430
  return result(payload, facade.status !== 'ok');
583
431
  }
432
+ // Detail is repository-derived; without a repository target the requested
433
+ // detail level was already downgraded to the instance-level summary above.
434
+ if (!repository || !store) {
435
+ return result(buildFacadeResult({
436
+ status: 'blocked',
437
+ summary: 'REPOSITORY_CONTEXT_REQUIRED_FOR_DETAIL: rh_status detail needs an explicit repository target.',
438
+ data: { operation, repositoryContext: null },
439
+ }) as unknown as Record<string, unknown>, true);
440
+ }
584
441
  const detailTimingStartedAt = performance.now();
585
442
  let detailTimingMark = detailTimingStartedAt;
586
443
  const detailPhaseTimingsMs: Record<string, number> = {};
@@ -647,8 +504,77 @@ export async function callStatusInboxAdapter(
647
504
  });
648
505
  }
649
506
  const toolSurfaceComputed = exposure.expectedToolNames.length > 0 || exposure.actualToolNames.length > 0 || toolSurfaceReady;
507
+ const activeReleaseAuthority = readRuntimeReleaseAuthority(ctx.controllerHome);
508
+ let autonomousContinuationProof: Awaited<ReturnType<typeof getWorkflowSupervisorContinuationProof>>;
509
+ let autonomousContinuationProofObservation: 'proven' | 'missing' | 'unavailable' = 'missing';
510
+ if (activeReleaseAuthority?.committedAt) {
511
+ try {
512
+ autonomousContinuationProof = await getWorkflowSupervisorContinuationProof(
513
+ resolveWorkflowSupervisorForgeHome(ctx.controllerHome),
514
+ {
515
+ repoId: repository.repoId,
516
+ activeReleaseId: activeReleaseAuthority.active.releaseId,
517
+ notBefore: activeReleaseAuthority.committedAt,
518
+ },
519
+ );
520
+ autonomousContinuationProofObservation = autonomousContinuationProof ? 'proven' : 'missing';
521
+ } catch {
522
+ autonomousContinuationProofObservation = 'unavailable';
523
+ }
524
+ }
525
+ let autonomousContinuationConsumerStatus: Awaited<ReturnType<typeof getWorkflowSupervisorConsumerStatus>> | undefined;
526
+ let autonomousContinuationConsumerObservation: 'observed' | 'unavailable' = 'unavailable';
527
+ try {
528
+ autonomousContinuationConsumerStatus = await getWorkflowSupervisorConsumerStatus(
529
+ resolveWorkflowSupervisorForgeHome(ctx.controllerHome),
530
+ );
531
+ autonomousContinuationConsumerObservation = 'observed';
532
+ } catch {
533
+ autonomousContinuationConsumerObservation = 'unavailable';
534
+ }
535
+ const dueConsumerFailure = Boolean(
536
+ autonomousContinuationConsumerStatus?.dueCommand
537
+ && autonomousContinuationConsumerStatus.lastFailure
538
+ && (!autonomousContinuationConsumerStatus.lastFailure.effectId
539
+ || autonomousContinuationConsumerStatus.lastFailure.effectId === autonomousContinuationConsumerStatus.dueCommand.effectId),
540
+ );
541
+ const autonomousContinuationConsumerReady = autonomousContinuationConsumerObservation === 'observed'
542
+ && autonomousContinuationConsumerStatus?.enabled === true
543
+ && autonomousContinuationConsumerStatus.running === true
544
+ && autonomousContinuationConsumerStatus.lastTickStartedAt !== undefined
545
+ && autonomousContinuationConsumerStatus.stalled === false
546
+ && !dueConsumerFailure;
547
+ const autonomousContinuationReady = readiness.ready
548
+ && toolSurfaceReady
549
+ && !sourceSnapshotStale
550
+ && autonomousContinuationProofObservation === 'proven'
551
+ && autonomousContinuationConsumerReady;
552
+ const autonomousContinuationBlockers = [...new Set([
553
+ ...readinessReasons
554
+ .map((reason) => reason.code)
555
+ .filter((code): code is string => typeof code === 'string' && code.length > 0),
556
+ ...(autonomousContinuationProofObservation === 'proven'
557
+ ? []
558
+ : [autonomousContinuationProofObservation === 'unavailable'
559
+ ? 'AUTONOMOUS_CONTINUATION_LIVE_PROOF_UNAVAILABLE'
560
+ : 'AUTONOMOUS_CONTINUATION_LIVE_PROOF_MISSING']),
561
+ ...(autonomousContinuationConsumerObservation === 'unavailable'
562
+ ? ['AUTONOMOUS_CONTINUATION_CONSUMER_STATUS_UNAVAILABLE']
563
+ : autonomousContinuationConsumerStatus?.enabled !== true
564
+ ? ['AUTONOMOUS_CONTINUATION_CONSUMER_DISABLED']
565
+ : autonomousContinuationConsumerStatus.running !== true
566
+ ? ['AUTONOMOUS_CONTINUATION_CONSUMER_NOT_RUNNING']
567
+ : autonomousContinuationConsumerStatus.lastTickStartedAt === undefined
568
+ ? ['AUTONOMOUS_CONTINUATION_CONSUMER_NOT_OBSERVED']
569
+ : autonomousContinuationConsumerStatus.stalled
570
+ ? ['AUTONOMOUS_CONTINUATION_CONSUMER_STALLED']
571
+ : dueConsumerFailure
572
+ ? ['AUTONOMOUS_CONTINUATION_CONSUMER_DEGRADED']
573
+ : []),
574
+ ])];
650
575
  const readinessWithToolSurface = {
651
576
  ready: effectiveReady,
577
+ readyFor: 'bounded_execution' as const,
652
578
  reasonCodes: [...new Set(
653
579
  readinessReasons
654
580
  .map((reason) => reason.code)
@@ -672,6 +598,22 @@ export async function callStatusInboxAdapter(
672
598
  },
673
599
  semantics: {
674
600
  executionReady,
601
+ // Runtime/tool health is necessary but not sufficient. Thin acceptance
602
+ // requires a fresh exact-active-release Supervisor ledger proof of
603
+ // CONTINUE -> CONTINUE -> DONE spanning at least one Runtime reconnect.
604
+ autonomousContinuationReady,
605
+ autonomousContinuationBlockers,
606
+ autonomousContinuationConsumer: {
607
+ observation: autonomousContinuationConsumerObservation,
608
+ ...(autonomousContinuationConsumerStatus ? { status: autonomousContinuationConsumerStatus } : {}),
609
+ },
610
+ autonomousContinuationProof: {
611
+ observation: autonomousContinuationProofObservation,
612
+ activeReleaseId: activeReleaseAuthority?.active.releaseId,
613
+ activeReleaseAuthorityRevision: activeReleaseAuthority?.revision,
614
+ activeReleaseCommittedAt: activeReleaseAuthority?.committedAt,
615
+ ...(autonomousContinuationProof ? { proof: autonomousContinuationProof } : {}),
616
+ },
675
617
  maintenanceHealthy,
676
618
  maintenanceCandidateCount,
677
619
  maintenanceObservation,
@@ -712,14 +654,62 @@ export async function callStatusInboxAdapter(
712
654
  .map((processId) => getProcessRecord(ctx.controllerHome, repository.repoId, processId))
713
655
  .filter((process): process is NonNullable<typeof process> => Boolean(process && isManagedProcessActive(process)));
714
656
  markDetailPhase('process_state');
715
- const activeProcessWorkIds = new Set(activeProcessRecords.map((process) => process.workId).filter((workId): workId is string => Boolean(workId)));
716
- const activeControllerWorkIds = new Set(activePrimaryWork.filter((contract) => Boolean(getControllerSession({ controllerHome: ctx.controllerHome, repoId: repository.repoId }, contract.workId))).map((contract) => contract.workId));
717
- const executingPrimaryWorkIds = new Set([...activeProcessWorkIds, ...activeControllerWorkIds].filter((workId) => activePrimaryWork.some((contract) => contract.workId === workId)));
657
+ const activePrimaryWorkIds = new Set(activePrimaryWork.map((contract) => contract.workId));
658
+ const activeProcessWorkIds = new Set(
659
+ activeProcessRecords
660
+ .map((process) => process.workId)
661
+ .filter((workId): workId is string => Boolean(workId && activePrimaryWorkIds.has(workId))),
662
+ );
663
+ const activeControllerWorkIds = new Set(
664
+ activePrimaryWork
665
+ .filter((contract) => Boolean(getControllerSession({ controllerHome: ctx.controllerHome, repoId: repository.repoId }, contract.workId)))
666
+ .map((contract) => contract.workId),
667
+ );
668
+ const runningPrimaryWorkIds = new Set([...activeProcessWorkIds, ...activeControllerWorkIds]);
718
669
  markDetailPhase('controller_sessions');
719
- const preferredFacadeTools = ['rh_access', 'rh_status', 'rh_inbox', 'rh_context', 'rh_work'] as const;
670
+
671
+ const waitingForUserPrimaryWorkIds = new Set(
672
+ pendingHandoffAttention
673
+ .map((item) => item.workId?.trim())
674
+ .filter((workId): workId is string => Boolean(workId && activePrimaryWorkIds.has(workId))),
675
+ );
676
+ const schedules = listSchedules(ctx.controllerHome, repository.repoId);
677
+ const activeOccurrenceScheduleIds = new Set(
678
+ listActiveOccurrences(ctx.controllerHome, repository.repoId).map((occurrence) => occurrence.scheduleId),
679
+ );
680
+ const scheduledPrimaryWorkIds = new Set<string>();
681
+ for (const schedule of schedules) {
682
+ if (!schedule.enabled && !activeOccurrenceScheduleIds.has(schedule.scheduleId)) continue;
683
+ for (const workId of activePrimaryWorkIds) {
684
+ if (scheduleOwnsWork(schedule, workId)) scheduledPrimaryWorkIds.add(workId);
685
+ }
686
+ }
687
+ const primaryWorkActivities = activePrimaryWork.map((contract) => ({
688
+ workId: contract.workId,
689
+ activity: primaryWorkRuntimeActivity({
690
+ running: runningPrimaryWorkIds.has(contract.workId),
691
+ waitingForUser: waitingForUserPrimaryWorkIds.has(contract.workId),
692
+ scheduled: scheduledPrimaryWorkIds.has(contract.workId),
693
+ needsReconciliation: buildWorkContinuationSnapshot(contract).reconciliationRequired,
694
+ }),
695
+ }));
696
+ const primaryWorkActivityCounts: Record<PrimaryWorkRuntimeActivity, number> = {
697
+ running: 0,
698
+ waiting_for_user: 0,
699
+ scheduled: 0,
700
+ recoverable: 0,
701
+ needs_reconciliation: 0,
702
+ };
703
+ for (const projection of primaryWorkActivities) primaryWorkActivityCounts[projection.activity] += 1;
704
+ markDetailPhase('work_activity');
705
+ const preferredFacadeTools = ['rh_access', 'rh_status', 'rh_inbox', 'rh_context', 'rh_work', 'capability_execute'] as const;
720
706
  const facade = buildFacadeResult({
721
707
  status: effectiveReady ? 'ok' : 'blocked',
722
- summary: effectiveReady ? 'Controller and MCP tool surface are ready for bounded work.' : 'Controller or MCP tool surface needs attention before work.',
708
+ summary: effectiveReady
709
+ ? autonomousContinuationReady
710
+ ? 'Controller and MCP tool surface are ready for bounded work and autonomous continuation.'
711
+ : 'Controller and MCP tool surface are ready for bounded work; autonomous continuation needs attention.'
712
+ : 'Controller or MCP tool surface needs attention before bounded work.',
723
713
  data: {
724
714
  operation,
725
715
  repoId: repository.repoId,
@@ -750,8 +740,8 @@ export async function callStatusInboxAdapter(
750
740
  activePrimaryWorkCount: activePrimaryWork.length,
751
741
  activeExecutionChildCount: activeExecutionChildren.length,
752
742
  activeProcessCount: activeProcessRecords.length,
753
- executingPrimaryWorkCount: executingPrimaryWorkIds.size,
754
- waitingPrimaryWorkCount: Math.max(0, activePrimaryWork.length - executingPrimaryWorkIds.size),
743
+ primaryWorkActivityCounts,
744
+ primaryWorkActivities,
755
745
  activeContractCount: activeContracts.length,
756
746
  invalidActiveContractCount: activeWorkProjection.invalid.length,
757
747
  invalidActiveContracts: activeWorkProjection.invalid.slice(0, 10).map(summarizeInvalidActiveWorkCandidate),
@@ -792,10 +782,118 @@ export async function callStatusInboxAdapter(
792
782
  return undefined;
793
783
  }
794
784
 
785
+ function summarizeUserRequest(request: UserRequest) {
786
+ return {
787
+ requestId: request.requestId,
788
+ kind: request.kind,
789
+ title: request.title,
790
+ summary: request.summary,
791
+ actionRequired: request.actionRequired,
792
+ status: request.status,
793
+ targetScope: request.targetScope,
794
+ resolution: request.resolution,
795
+ updatedAt: request.updatedAt,
796
+ };
797
+ }
798
+
799
+ // `request_id` is Process Runtime idempotency/correlation only. UserRequest
800
+ // selection stays on `handoff_id` so retry identity can never change Inbox semantics.
801
+ export function findCanonicalUserRequest(controllerHome: string, args: Record<string, unknown>): UserRequest | undefined {
802
+ const handoffId = typeof args.handoff_id === 'string' ? args.handoff_id.trim() : '';
803
+ if (!handoffId) return undefined;
804
+ return getUserRequest(controllerHome, handoffId)
805
+ ?? listUserRequests(controllerHome, 'all').find((request) => request.presentation?.legacyHandoffId === handoffId);
806
+ }
807
+
808
+ export function shouldUseCanonicalUserRequestInbox(
809
+ repositoryRepoId: string | undefined,
810
+ operation: string,
811
+ request: UserRequest | undefined,
812
+ ): boolean {
813
+ if (!repositoryRepoId) return true;
814
+ if (operation === 'list' || operation === 'create') return false;
815
+ return Boolean(request && !request.targetScope?.repoId?.trim());
816
+ }
817
+
818
+ function callCanonicalUserRequestInbox(ctx: MultiRepositoryMcpToolContext, args: Record<string, unknown>, operation: string): CallToolResult {
819
+ const limit = Math.max(1, Math.min(Math.trunc(typeof args.limit === 'number' ? args.limit : 50), 100));
820
+ if (operation === 'list') {
821
+ const items = listUserRequests(ctx.controllerHome, 'pending').slice(0, limit);
822
+ return result(buildFacadeResult({
823
+ summary: items.length ? `${items.length} pending UserRequest item(s).` : 'No pending UserRequest items.',
824
+ data: { items: items.map(summarizeUserRequest) },
825
+ suggestedNextActions: items.slice(0, 1).map((item) => ({ label: `Read ${item.requestId}`, tool: 'rh_inbox', operation: 'get', payload: { handoff_id: item.requestId }, risk: 'readonly' as const })),
826
+ }) as unknown as Record<string, unknown>);
827
+ }
828
+ if (operation === 'create') {
829
+ const title = typeof args.title === 'string' ? args.title.trim() : '';
830
+ const summary = typeof args.summary === 'string' ? args.summary.trim() : typeof args.reason === 'string' ? args.reason.trim() : '';
831
+ if (!title || !summary) throw new Error('USER_REQUEST_TITLE_SUMMARY_REQUIRED');
832
+ const workId = typeof args.work_id === 'string' ? args.work_id.trim() : '';
833
+ const explicitId = typeof args.handoff_id === 'string' ? args.handoff_id.trim() : '';
834
+ const actionRequired = (typeof args.action_required === 'string' ? args.action_required : 'product_decision') as 'login' | 'grant_permission' | 'confirm_destructive' | 'product_decision';
835
+ const kind = (typeof args.request_kind === 'string' ? args.request_kind : actionRequired === 'product_decision' ? 'user_decision_request' : 'user_action_request') as 'user_action_request' | 'user_decision_request';
836
+ const rootCauseKey = typeof args.root_cause_key === 'string' && args.root_cause_key.trim()
837
+ ? args.root_cause_key.trim()
838
+ : `rh_inbox:${explicitId || workId || title}:${summary}`;
839
+ const item = recordUserRequest(ctx.controllerHome, {
840
+ ...(explicitId ? { requestId: explicitId } : {}),
841
+ kind,
842
+ rootCauseKey,
843
+ title,
844
+ summary,
845
+ actionRequired,
846
+ ...(workId ? { targetScope: { scopeKind: 'work', scopeId: workId, workId } } : {}),
847
+ presentation: {
848
+ ...(typeof args.handoff_id === 'string' && args.handoff_id.trim() ? { legacyHandoffId: args.handoff_id.trim() } : {}),
849
+ ...(typeof args.reason === 'string' ? { reason: args.reason } : {}),
850
+ ...(typeof args.recommended_decision === 'string' ? { recommendedDecision: args.recommended_decision } : {}),
851
+ ...(typeof args.recommended_prompt === 'string' ? { recommendedPrompt: args.recommended_prompt } : {}),
852
+ },
853
+ });
854
+ return result(buildFacadeResult({ summary: `Created UserRequest ${item.requestId}.`, data: { item: summarizeUserRequest(item) } }) as unknown as Record<string, unknown>);
855
+ }
856
+ const current = findCanonicalUserRequest(ctx.controllerHome, args);
857
+ if (operation === 'get') {
858
+ const facade = buildFacadeResult({
859
+ status: current ? 'ok' : 'not_found',
860
+ summary: current ? `UserRequest ${current.requestId}.` : 'UserRequest not found.',
861
+ data: { item: current ? summarizeUserRequest(current) : undefined },
862
+ suggestedNextActions: current?.status === 'pending' ? [{ label: 'Resolve request', tool: 'rh_inbox', operation: 'resolve', payload: { request_id: current.requestId }, risk: 'workspace_write' }] : [],
863
+ });
864
+ return result(facade as unknown as Record<string, unknown>, facade.status === 'not_found');
865
+ }
866
+ if (!current) throw new Error('USER_REQUEST_NOT_FOUND');
867
+ if (operation === 'ack' || operation === 'accept') {
868
+ return result(buildFacadeResult({
869
+ summary: `${operation === 'accept' ? 'Accepted' : 'Acknowledged'} UserRequest ${current.requestId}; semantic state remains pending until resolve/dismiss.`,
870
+ data: { item: summarizeUserRequest(current), compatibilityNoop: true },
871
+ }) as unknown as Record<string, unknown>);
872
+ }
873
+ if (operation === 'resolve' || operation === 'dismiss') {
874
+ const decision = operation === 'dismiss'
875
+ ? (typeof args.decision === 'string' && args.decision.trim() ? args.decision.trim() : 'dismissed')
876
+ : (typeof args.decision === 'string' ? args.decision.trim() : '');
877
+ if (!decision) throw new Error('USER_REQUEST_DECISION_REQUIRED');
878
+ const resolved = resolveUserRequest(ctx.controllerHome, {
879
+ requestId: current.requestId,
880
+ decision,
881
+ resolvedBy: typeof args.resolver === 'string' && args.resolver.trim() ? args.resolver.trim() : (ctx.principalId?.trim() || 'mcp-user'),
882
+ });
883
+ return result(buildFacadeResult({ summary: `Resolved UserRequest ${resolved.requestId}.`, data: { item: summarizeUserRequest(resolved) } }) as unknown as Record<string, unknown>);
884
+ }
885
+ throw new Error(`USER_REQUEST_OPERATION_UNSUPPORTED:${operation}`);
886
+ }
887
+
795
888
  async function callInboxAdapter(ctx: MultiRepositoryMcpToolContext, args: Record<string, unknown>): Promise<CallToolResult> {
796
- const repository = selected(ctx, args);
889
+ const repository = selectedOptional(ctx, args);
797
890
  const operation = String(args.operation ?? 'list');
798
891
  if (!allowedFacadeOperations('rh_inbox').includes(operation)) return invalidFacadeOperation('rh_inbox', operation);
892
+ const canonicalRequest = findCanonicalUserRequest(ctx.controllerHome, args);
893
+ if (shouldUseCanonicalUserRequestInbox(repository?.repoId, operation, canonicalRequest)) {
894
+ return callCanonicalUserRequestInbox(ctx, args, operation);
895
+ }
896
+ if (!repository) throw new Error('REPOSITORY_CONTEXT_REQUIRED_FOR_HANDOFF');
799
897
  const app = await runHandoffInboxApplication({
800
898
  operation: operation as 'get' | 'list' | 'ack' | 'accept' | 'resolve' | 'dismiss' | 'create',
801
899
  store: { controllerHome: ctx.controllerHome, repoId: repository.repoId },
@@ -814,13 +912,7 @@ async function callInboxAdapter(ctx: MultiRepositoryMcpToolContext, args: Record
814
912
  resolver: typeof args.resolver === 'string' ? args.resolver : undefined,
815
913
  controllerIdentity: { principalId: ctx.principalId, sessionId: ctx.sessionId },
816
914
  }, {
817
- triggerResolvedContinuation: (item) => triggerWorkContinuationRepositoryEvent(
818
- ctx.controllerHome,
819
- repository.repoId,
820
- handoffResolvedContinuationEventName(item.id),
821
- `handoff:${item.id}:${item.updatedAt}`,
822
- { workId: item.workId, data: { handoffId: item.id, status: item.status, decision: item.decision } },
823
- ),
915
+ triggerResolvedContinuation: (item) => triggerResolvedHandoffContinuation(ctx.controllerHome, repository.repoId, item),
824
916
  });
825
917
  if (operation === 'get') {
826
918
  const item = 'item' in app ? app.item : undefined;