@moretea-labs/forge 1.6.0 → 1.7.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 (469) hide show
  1. package/AGENTS.md +4 -0
  2. package/CHANGELOG.md +39 -0
  3. package/CLAUDE.md +4 -0
  4. package/README.md +2 -2
  5. package/README.zh-CN.md +1 -1
  6. package/SKILL.md +2 -2
  7. package/THIRD_PARTY_NOTICES.md +1 -1
  8. package/agents/openai.yaml +1 -1
  9. package/assets/hooks/hook-input.sh +11 -8
  10. package/assets/hooks/lib/session-state.sh +10 -7
  11. package/assets/hooks/lib/workflow-state.sh +13 -177
  12. package/assets/hooks/post-tool-observer.sh +8 -2
  13. package/assets/hooks/prompt-guard.sh +5 -81
  14. package/assets/hooks/session-start-context.sh +56 -1
  15. package/assets/partials/05-workflow.partial.md +1 -1
  16. package/assets/partials-agents/02-operating-mode.partial.md +2 -0
  17. package/assets/partials-agents/03-orchestration.partial.md +1 -1
  18. package/assets/plugin-registry.v1.json +3 -3
  19. package/assets/reference-configs/document-generation.md +1 -1
  20. package/assets/reference-configs/harness-overview.md +1 -1
  21. package/assets/reference-configs/sprint-contracts.md +3 -3
  22. package/assets/skill-version.json +2 -2
  23. package/assets/templates/contract.template.md +2 -7
  24. package/assets/templates/helpers/capture-plan.sh +2 -2
  25. package/assets/templates/helpers/check-architecture-sync.sh +17 -0
  26. package/assets/templates/helpers/check-task-workflow.sh +4 -4
  27. package/assets/templates/helpers/contract-worktree.sh +1 -21
  28. package/assets/templates/helpers/ensure-task-workflow.sh +11 -36
  29. package/assets/templates/helpers/inspect-project-state.ts +8 -6
  30. package/assets/templates/helpers/migrate-project-template.sh +22 -45
  31. package/assets/templates/helpers/migrate-workflow-docs.ts +9 -7
  32. package/assets/templates/helpers/new-plan.sh +1 -1
  33. package/assets/templates/helpers/plan-to-todo.sh +12 -37
  34. package/assets/templates/helpers/ship-worktrees.sh +2 -29
  35. package/assets/templates/helpers/verify-contract.sh +1 -111
  36. package/assets/templates/helpers/verify-sprint.sh +3 -180
  37. package/assets/templates/helpers/workflow-contract.ts +5 -1
  38. package/assets/templates/plan.template.md +1 -1
  39. package/assets/templates/review.template.md +9 -34
  40. package/assets/workflow-contract.v1.json +10 -19
  41. package/docs/README.md +10 -10
  42. package/docs/architecture/CURRENT.md +178 -0
  43. package/docs/architecture/EVOLUTION.md +42 -0
  44. package/docs/architecture/current/README.md +4 -156
  45. package/docs/architecture/decisions/20260803-release-identity-binding-and-exit-policy.md +2 -2
  46. package/docs/architecture/decisions/20260823-immediate-controller-relay.md +53 -0
  47. package/docs/architecture/decisions/20260826-browser-runtime-v2.md +73 -0
  48. package/docs/architecture/history/README.md +7 -0
  49. package/docs/architecture/{chatgpt-handoff-facade.md → history/chatgpt-handoff-facade.md} +4 -0
  50. package/docs/architecture/{global-hook-runtime.md → history/global-hook-runtime.md} +7 -3
  51. package/docs/architecture/{ios-semantic-automation-provider-v2.md → history/ios-semantic-automation-provider-v2.md} +6 -2
  52. package/docs/architecture/history.md +3 -34
  53. package/docs/architecture/index.md +15 -98
  54. package/docs/architecture/modules/controller-runtime/transport-lifecycle.md +1 -1
  55. package/docs/architecture/reviews/2026-08-22-semantic-harness-convergence-acceptance.md +39 -0
  56. package/docs/architecture/versions/1.6.md +38 -0
  57. package/docs/architecture/versions/1.7.md +41 -0
  58. package/docs/forge-chatgpt-browser-engine.md +2 -2
  59. package/docs/forge-chatgpt-mcp-setup.md +4 -28
  60. package/docs/forge-chatgpt-supervised-automation.md +3 -3
  61. package/docs/forge-github-issue-launcher.md +1 -1
  62. package/docs/forge-plugin-management.md +1 -1
  63. package/docs/forge-runtime-self-healing-loop.md +1 -1
  64. package/docs/operations/controller-browser-plugin.md +26 -6
  65. package/docs/operations/controller-performance-and-502.md +143 -0
  66. package/docs/operations/controller-reliability-runbook.md +1 -1
  67. package/docs/operations/features.md +2 -2
  68. package/docs/operations/github-repository.md +1 -1
  69. package/docs/operations/homebrew.md +2 -2
  70. package/docs/operations/mcp-tool-exposure.md +5 -3
  71. package/docs/wiki/Architecture.md +6 -6
  72. package/docs/wiki/Implementation.md +2 -2
  73. package/docs/wiki/Integrations.md +2 -2
  74. package/docs/wiki/Work-Lifecycle.md +1 -1
  75. package/package.json +33 -11
  76. package/scripts/activate-source-baseline.ts +17 -13
  77. package/scripts/architecture-event.ts +2 -820
  78. package/scripts/architecture-queue.sh +2 -645
  79. package/scripts/archive-architecture-request.sh +2 -242
  80. package/scripts/archive-workflow.sh +1 -291
  81. package/scripts/benchmark-background-check-overlap.ts +228 -0
  82. package/scripts/benchmark-mcp-host.sh +117 -0
  83. package/scripts/benchmark-mcp-transport.ts +170 -0
  84. package/scripts/benchmark-quality-harness.ts +146 -0
  85. package/scripts/benchmark-route-session-concurrency.ts +207 -6
  86. package/scripts/benchmark-thin-harness-mcp-e2e.ts +7 -1
  87. package/scripts/benchmark-typescript-navigation.ts +186 -0
  88. package/scripts/benchmark-work-efficiency.ts +334 -0
  89. package/scripts/capability-config.ts +2 -392
  90. package/scripts/capability-resolver.ts +2 -503
  91. package/scripts/capture-plan.sh +1 -332
  92. package/scripts/check-agent-tooling.sh +2 -1558
  93. package/scripts/check-architecture-sync.sh +2 -371
  94. package/scripts/check-brain-manifest.sh +2 -253
  95. package/scripts/check-context-files.sh +2 -47
  96. package/scripts/check-deploy-sql-order.sh +2 -115
  97. package/scripts/check-mcp-compatibility.ts +14 -0
  98. package/scripts/check-runtime-architecture.mjs +349 -79
  99. package/scripts/check-skill-version.ts +3 -191
  100. package/scripts/check-source-duplication.mjs +61 -0
  101. package/scripts/check-stable-baseline.ts +92 -0
  102. package/scripts/check-task-sync.sh +2 -63
  103. package/scripts/check-task-workflow.sh +2 -1000
  104. package/scripts/codex-handoff-resume.sh +2 -267
  105. package/scripts/context-contract-sync.sh +2 -514
  106. package/scripts/contract-run.ts +2 -463
  107. package/scripts/contract-worktree.sh +1 -722
  108. package/scripts/ensure-task-workflow.sh +1 -1225
  109. package/scripts/host-temporary-cloud-mcp-e2e.sh +265 -0
  110. package/scripts/inspect-project-state.ts +4 -279
  111. package/scripts/install-standalone-recovery.ts +24 -0
  112. package/scripts/lib/project-init-lib.sh +22 -46
  113. package/scripts/lib/run-forge-helper.sh +19 -0
  114. package/scripts/lib/run-forge-helper.ts +26 -0
  115. package/scripts/migrate-project-template.sh +1 -1189
  116. package/scripts/migrate-workflow-docs.ts +4 -412
  117. package/scripts/new-plan.sh +1 -180
  118. package/scripts/new-spec.sh +1 -47
  119. package/scripts/new-sprint.sh +1 -46
  120. package/scripts/plan-to-todo.sh +1 -796
  121. package/scripts/prepare-codex-handoff.sh +2 -201
  122. package/scripts/prepare-handoff.sh +1 -78
  123. package/scripts/refresh-current-status.sh +2 -467
  124. package/scripts/run-governed-gate.ts +5 -1
  125. package/scripts/select-agent-context-blocks.sh +2 -64
  126. package/scripts/ship-worktrees.sh +1 -558
  127. package/scripts/smoke-ios-physical-device.ts +4 -2
  128. package/scripts/smoke-runtime-recovery.ts +1 -35
  129. package/scripts/smoke-schedule-engine.ts +1 -20
  130. package/scripts/sprint-backlog.sh +1 -834
  131. package/scripts/stage-runtime-release.ts +2 -1
  132. package/scripts/summarize-failures.sh +2 -123
  133. package/scripts/switch-plan.sh +1 -150
  134. package/scripts/sync-brain-docs.sh +2 -379
  135. package/scripts/sync-generated-authority.mjs +175 -0
  136. package/scripts/verify-contract.sh +2 -703
  137. package/scripts/verify-forge-runtime.sh +0 -1
  138. package/scripts/verify-sprint.sh +1 -677
  139. package/scripts/workflow-contract.ts +4 -205
  140. package/scripts/workstream-sync.sh +2 -261
  141. package/src/cli/agent-jobs/executor-health.ts +1 -1
  142. package/src/cli/commands/init-hook.ts +3 -3
  143. package/src/cli/commands/mcp.ts +9 -5
  144. package/src/cli/commands/plugin.ts +12 -3
  145. package/src/cli/commands/recovery.ts +25 -3
  146. package/src/cli/commands/runtime.ts +55 -3
  147. package/src/cli/commands/security.ts +12 -1
  148. package/src/cli/commands/setup-profile.ts +31 -21
  149. package/src/cli/controller/check-runner.ts +113 -5
  150. package/src/cli/controller/composite-result.ts +1 -1
  151. package/src/cli/controller/context/focus.ts +51 -0
  152. package/src/cli/controller/context/instruction-context.ts +114 -0
  153. package/src/cli/controller/context/known-paths.ts +76 -0
  154. package/src/cli/controller/context/query-planning.ts +110 -0
  155. package/src/cli/controller/context/rule-resolution.ts +532 -0
  156. package/src/cli/controller/context/source-materializer.ts +278 -0
  157. package/src/cli/controller/context/structural.ts +16 -0
  158. package/src/cli/controller/context/types.ts +286 -0
  159. package/src/cli/controller/context-pack.ts +828 -487
  160. package/src/cli/controller/launch-agents.ts +77 -2
  161. package/src/cli/controller/operational-plan.ts +2 -2
  162. package/src/cli/controller/work-mode.ts +6 -4
  163. package/src/cli/editing/edit-session.ts +60 -7
  164. package/src/cli/github/contracts.ts +16 -0
  165. package/src/cli/github/github.ts +135 -16
  166. package/src/cli/github/session.ts +2 -1
  167. package/src/cli/installer/managed-entries.ts +15 -1
  168. package/src/cli/local-bridge/console-automations.ts +54 -78
  169. package/src/cli/local-bridge/console-view-models.ts +1 -35
  170. package/src/cli/local-bridge/facade-api.ts +37 -264
  171. package/src/cli/local-bridge/frontend/src/App.tsx +3 -3
  172. package/src/cli/local-bridge/frontend/src/features/automations/AutomationsView.tsx +23 -13
  173. package/src/cli/local-bridge/frontend/src/features/capabilities/CapabilitiesView.tsx +37 -4
  174. package/src/cli/local-bridge/frontend/src/features/overview/OverviewView.tsx +6 -4
  175. package/src/cli/local-bridge/frontend/src/lib/api.ts +1 -6
  176. package/src/cli/local-bridge/frontend/src/lib/routes.ts +1 -1
  177. package/src/cli/local-bridge/frontend/src/shell/Sidebar.tsx +2 -2
  178. package/src/cli/local-bridge/frontend/src/styles.css +1 -1
  179. package/src/cli/local-bridge/frontend/src/types.ts +5 -8
  180. package/src/cli/local-bridge/job-store.ts +1 -490
  181. package/src/cli/local-bridge/server.ts +2 -515
  182. package/src/cli/local-bridge/ui-dist/app.css +1 -1
  183. package/src/cli/local-bridge/ui-dist/app.js +3703 -3757
  184. package/src/cli/mcp/auth.ts +5 -5
  185. package/src/cli/mcp/instructions.ts +3 -2
  186. package/src/cli/mcp/legacy-tool-service.ts +10 -222
  187. package/src/cli/mcp/multi-repository.ts +16 -5
  188. package/src/cli/mcp/oauth.ts +175 -26
  189. package/src/cli/mcp/post-finalize-work-attribution.ts +150 -0
  190. package/src/cli/mcp/repository-tools.ts +282 -146
  191. package/src/cli/mcp/server.ts +586 -116
  192. package/src/cli/mcp/tool-capability-cache.ts +1 -1
  193. package/src/cli/mcp/tool-contract.ts +14 -0
  194. package/src/cli/mcp/toolset-selection.ts +1 -1
  195. package/src/cli/mcp/toolset.ts +44 -7
  196. package/src/cli/mcp/transports/http.ts +124 -14
  197. package/src/cli/mcp/transports/session-registry.ts +43 -5
  198. package/src/cli/mcp/types.ts +3 -3
  199. package/src/cli/repositories/command-classifier.ts +103 -21
  200. package/src/cli/repositories/command-executor.ts +78 -526
  201. package/src/cli/repositories/command-process.ts +108 -0
  202. package/src/cli/repositories/command-scope.ts +99 -41
  203. package/src/cli/repositories/controller-home.ts +7 -8
  204. package/src/cli/repositories/git-command-executor.ts +2 -0
  205. package/src/cli/repositories/locks.ts +53 -16
  206. package/src/cli/repositories/repository-snapshot.ts +124 -0
  207. package/src/cli/repositories/selected-path-actions.ts +17 -9
  208. package/src/cli/repositories/structured-git.ts +118 -6
  209. package/src/cli/repository/inspector.ts +563 -65
  210. package/src/cli/repository/session-cache.ts +58 -17
  211. package/src/cli/v81-entry.ts +1 -4
  212. package/src/effects/fs-transaction.ts +85 -17
  213. package/src/runtime/context/codegraph-read-provider.ts +233 -2
  214. package/src/runtime/context/codegraph-sidecar.cjs +74 -40
  215. package/src/runtime/context/generic-lsp-provider.ts +355 -0
  216. package/src/runtime/context/lsp-client.ts +283 -0
  217. package/src/runtime/context/semantic-navigation-contract.ts +61 -0
  218. package/src/runtime/context/semantic-navigation.ts +223 -0
  219. package/src/runtime/context/swift-navigation.ts +565 -0
  220. package/src/runtime/context/typescript-navigation.ts +226 -0
  221. package/src/runtime/control-plane/dispatch-priority.ts +28 -0
  222. package/src/runtime/control-plane/execution/direct-edit-work-completion.ts +48 -16
  223. package/src/runtime/control-plane/execution/edit-validation-coordinator.ts +86 -24
  224. package/src/runtime/control-plane/execution/repository-work-attribution.ts +106 -0
  225. package/src/runtime/control-plane/execution/retained-work-resume.ts +203 -0
  226. package/src/runtime/control-plane/execution/session-store.ts +18 -0
  227. package/src/runtime/control-plane/execution/verification-evidence.ts +58 -3
  228. package/src/runtime/control-plane/execution/work-completion-authority.ts +58 -0
  229. package/src/runtime/control-plane/execution/work-evidence-policy.ts +200 -0
  230. package/src/runtime/control-plane/execution/work-execution-support.ts +386 -0
  231. package/src/runtime/control-plane/execution/work-finalization-service.ts +1913 -0
  232. package/src/runtime/control-plane/execution/work-handle-authority.ts +96 -0
  233. package/src/runtime/control-plane/execution/work-handle-store.ts +27 -2
  234. package/src/runtime/control-plane/execution/work-lifecycle-audit.ts +258 -0
  235. package/src/runtime/control-plane/execution/work-operation-service.ts +468 -0
  236. package/src/runtime/control-plane/execution/work-path-scope.ts +37 -0
  237. package/src/runtime/control-plane/execution/work-preparation-service.ts +479 -0
  238. package/src/runtime/control-plane/execution/work-process-evidence.ts +129 -0
  239. package/src/runtime/control-plane/execution/work-remote-delivery.ts +215 -0
  240. package/src/runtime/control-plane/execution/work-task-receipt.ts +22 -18
  241. package/src/runtime/control-plane/execution/work-terminal-cleanup.ts +156 -11
  242. package/src/runtime/control-plane/execution/work-validation-reconciler.ts +22 -14
  243. package/src/runtime/control-plane/execution/work-verification-context.ts +56 -0
  244. package/src/runtime/control-plane/execution/work-verification-service.ts +388 -0
  245. package/src/runtime/control-plane/execution/work-verification-snapshot.ts +90 -9
  246. package/src/runtime/control-plane/facade/capability-registry.ts +129 -25
  247. package/src/runtime/control-plane/facade/controller-round-relay.ts +1118 -0
  248. package/src/runtime/control-plane/facade/controller-session-store.ts +302 -12
  249. package/src/runtime/control-plane/facade/goal-workloop-access.ts +17 -1
  250. package/src/runtime/control-plane/facade/goal-workloop.ts +928 -190
  251. package/src/runtime/control-plane/facade/index.ts +3 -0
  252. package/src/runtime/control-plane/facade/plan-contract-store.ts +275 -42
  253. package/src/runtime/control-plane/facade/repository-work-admission.ts +147 -0
  254. package/src/runtime/control-plane/facade/requirement-authority.ts +83 -0
  255. package/src/runtime/control-plane/facade/semantic-admission.ts +205 -0
  256. package/src/runtime/control-plane/facade/suggested-actions.ts +5 -1
  257. package/src/runtime/control-plane/facade/types.ts +90 -10
  258. package/src/runtime/control-plane/facade/work-contract-store.ts +157 -261
  259. package/src/runtime/control-plane/facade/work-state-machine.ts +250 -0
  260. package/src/runtime/control-plane/generated-cache-retention.ts +271 -0
  261. package/src/runtime/control-plane/global-scheduler/config.ts +44 -0
  262. package/src/runtime/control-plane/global-scheduler/dispatch-capacity.ts +80 -0
  263. package/src/runtime/control-plane/global-scheduler/durable-admission.ts +46 -0
  264. package/src/runtime/control-plane/global-scheduler/maintenance.ts +152 -0
  265. package/src/runtime/control-plane/global-scheduler/projection-refresh.ts +84 -0
  266. package/src/runtime/control-plane/global-scheduler/reconciliation.ts +3 -3
  267. package/src/runtime/control-plane/global-scheduler/scheduler.ts +278 -543
  268. package/src/runtime/control-plane/global-scheduler/source-scan.ts +59 -0
  269. package/src/runtime/control-plane/global-scheduler/state.ts +88 -0
  270. package/src/runtime/control-plane/global-scheduler/worker-attachment.ts +57 -0
  271. package/src/runtime/control-plane/global-scheduler/worker-exit-decision.ts +38 -0
  272. package/src/runtime/control-plane/global-scheduler/worker-exit-reconciler.ts +175 -0
  273. package/src/runtime/control-plane/global-scheduler/worker-launch.ts +111 -0
  274. package/src/runtime/control-plane/global-scheduler/worker-lifecycle-store.ts +64 -0
  275. package/src/runtime/control-plane/global-scheduler/worker-lifecycle.ts +150 -0
  276. package/src/runtime/control-plane/global-scheduler/worker-process.ts +119 -0
  277. package/src/runtime/control-plane/global-scheduler/worker-stderr.ts +60 -0
  278. package/src/runtime/control-plane/launcher/chatgpt-work-binding-store.ts +63 -0
  279. package/src/runtime/control-plane/launcher/chatgpt-work-continuation.ts +365 -117
  280. package/src/runtime/control-plane/launcher/launch-reservation-store.ts +89 -0
  281. package/src/runtime/control-plane/launcher/thin-launcher.ts +244 -11
  282. package/src/runtime/control-plane/persistence/controller-home-migration.ts +487 -0
  283. package/src/runtime/control-plane/persistence/requirement-store.ts +0 -12
  284. package/src/runtime/control-plane/persistence/sqlite-store.ts +33 -2
  285. package/src/runtime/control-plane/release-retention.ts +62 -2
  286. package/src/runtime/control-plane/repo-actor/registry.ts +4 -2
  287. package/src/runtime/control-plane/routing/route-policy.ts +24 -21
  288. package/src/runtime/control-plane/routing/workspace-admission.ts +70 -0
  289. package/src/runtime/control-plane/runtime-status-client.ts +0 -2
  290. package/src/runtime/diagnostics/mcp-timing.ts +13 -0
  291. package/src/runtime/diagnostics/mcp-transport-benchmark.ts +129 -0
  292. package/src/runtime/diagnostics/performance.ts +24 -1
  293. package/src/runtime/evidence/event-ledger.ts +1 -1
  294. package/src/runtime/evidence/process-check-execution.ts +18 -0
  295. package/src/runtime/execution/jobs/child-reference.ts +6 -2
  296. package/src/runtime/execution/jobs/store.ts +58 -4
  297. package/src/runtime/execution/jobs/types.ts +1 -1
  298. package/src/runtime/execution/managed-workspace.ts +203 -1
  299. package/src/runtime/execution/process-runtime/check-facade.ts +51 -4
  300. package/src/runtime/execution/process-runtime/check-result.ts +88 -0
  301. package/src/runtime/execution/process-runtime/check-runner-sidecar.ts +7 -1
  302. package/src/runtime/execution/process-runtime/check-scheduling.ts +114 -0
  303. package/src/runtime/execution/process-runtime/command-facade.ts +367 -40
  304. package/src/runtime/execution/process-runtime/gc.ts +38 -6
  305. package/src/runtime/execution/process-runtime/lightweight-managed.ts +1201 -0
  306. package/src/runtime/execution/process-runtime/persisted-check.ts +51 -5
  307. package/src/runtime/execution/process-runtime/resource-claims.ts +10 -6
  308. package/src/runtime/execution/process-runtime/runtime.ts +53 -3
  309. package/src/runtime/execution/process-runtime/store.ts +1 -0
  310. package/src/runtime/execution/process-runtime/types.ts +4 -12
  311. package/src/runtime/execution/thin-harness/async-process.ts +12 -2
  312. package/src/runtime/execution/thin-harness/search-worker.ts +54 -5
  313. package/src/runtime/execution/work-activity.ts +21 -0
  314. package/src/runtime/execution/workers/executor.ts +18 -61
  315. package/src/runtime/gateway/mcp/execution-tools.ts +35 -1852
  316. package/src/runtime/gateway/mcp/legacy-ios-tool-adapter.ts +61 -0
  317. package/src/runtime/gateway/mcp/process-tools.ts +83 -37
  318. package/src/runtime/gateway/mcp/router.ts +186 -84
  319. package/src/runtime/gateway/mcp/runtime-tool-definitions.ts +565 -0
  320. package/src/runtime/gateway/mcp/runtime-tools.ts +2378 -1947
  321. package/src/runtime/plugins/app-store-connect-adapter.ts +216 -47
  322. package/src/runtime/plugins/browser-adapter.ts +2662 -829
  323. package/src/runtime/plugins/browser-automation-service.ts +10 -0
  324. package/src/runtime/plugins/browser-handoff-host.ts +2 -25
  325. package/src/runtime/plugins/browser-handoff.ts +110 -5
  326. package/src/runtime/plugins/browser-macos-bridge.ts +701 -63
  327. package/src/runtime/plugins/browser-manifest-surface.ts +603 -0
  328. package/src/runtime/plugins/browser-native-session-service.ts +222 -0
  329. package/src/runtime/plugins/browser-node-bridge.ts +6 -34
  330. package/src/runtime/plugins/browser-provider-registry.ts +109 -0
  331. package/src/runtime/plugins/browser-runtime-contract.ts +154 -0
  332. package/src/runtime/plugins/browser-runtime.ts +193 -0
  333. package/src/runtime/plugins/browser-session-authority.ts +332 -0
  334. package/src/runtime/plugins/browser-session-store.ts +121 -0
  335. package/src/runtime/plugins/browser-session-types.ts +98 -0
  336. package/src/runtime/plugins/capability-authorization-grants.ts +354 -0
  337. package/src/runtime/plugins/desktop-operator-registration.ts +10 -4
  338. package/src/runtime/plugins/external-adapter.ts +358 -3
  339. package/src/runtime/plugins/external-unix-socket.ts +7 -1
  340. package/src/runtime/plugins/first-party-registry.ts +2 -0
  341. package/src/runtime/plugins/github-adapter.ts +125 -0
  342. package/src/runtime/plugins/ios/agent-device-provider.ts +1 -1
  343. package/src/runtime/plugins/ios/agent-device-typed-provider.ts +52 -9
  344. package/src/runtime/plugins/ios/remote-xpc-hid.ts +1171 -0
  345. package/src/runtime/plugins/ios-adapter.ts +106 -16
  346. package/src/runtime/plugins/ios-agent-device.ts +234 -64
  347. package/src/runtime/plugins/ios-physical-device.ts +1143 -392
  348. package/src/runtime/plugins/lightweight-action.ts +153 -0
  349. package/src/runtime/plugins/local-system-adapter.ts +123 -6
  350. package/src/runtime/plugins/macos-capability-broker.ts +47 -9
  351. package/src/runtime/plugins/plugin-action-sidecar.ts +59 -0
  352. package/src/runtime/plugins/plugin-management-adapter.ts +49 -8
  353. package/src/runtime/plugins/resend-adapter.ts +1 -1
  354. package/src/runtime/plugins/store.ts +330 -33
  355. package/src/runtime/plugins/types.ts +38 -3
  356. package/src/runtime/plugins/xiaohongshu-publish.ts +515 -0
  357. package/src/runtime/projections/git-status-sampler.ts +16 -16
  358. package/src/runtime/projections/materialized-view.ts +28 -10
  359. package/src/runtime/recovery/maintenance-executor.ts +426 -25
  360. package/src/runtime/root/mcp-transport.ts +180 -10
  361. package/src/runtime/root/package-connector-service.ts +230 -10
  362. package/src/runtime/root/package-runtime-release.ts +143 -17
  363. package/src/runtime/root/package-runtime-service.ts +461 -22
  364. package/src/runtime/root/release-manifest.ts +144 -18
  365. package/src/runtime/root/release-materialize.ts +125 -32
  366. package/src/runtime/root/release-store.ts +48 -11
  367. package/src/runtime/root/runtime.ts +23 -5
  368. package/src/runtime/root/service.ts +100 -29
  369. package/src/runtime/root/types.ts +12 -0
  370. package/src/runtime/safe-tooling/ios-development.ts +321 -63
  371. package/src/runtime/shared/trusted-executable.ts +62 -0
  372. package/src/runtime/shared/trusted-node-executable.ts +48 -0
  373. package/src/runtime/standalone-recovery/core.ts +1079 -240
  374. package/src/runtime/standalone-recovery/entry.ts +100 -24
  375. package/src/runtime/standalone-recovery/installer.ts +20 -4
  376. package/src/runtime/standalone-recovery/service-labels.ts +2 -0
  377. package/src/runtime/standalone-recovery/watchdog-heartbeat.ts +160 -0
  378. package/src/runtime/workflow/schedules/browser-probe.ts +81 -3
  379. package/src/runtime/workflow/schedules/engine.ts +364 -202
  380. package/src/runtime/workflow/schedules/github-issue-watch.ts +158 -0
  381. package/src/runtime/workflow/schedules/settlement.ts +64 -17
  382. package/src/runtime/workflow/schedules/store.ts +209 -19
  383. package/src/runtime/workflow/schedules/types.ts +2 -4
  384. package/src/runtime/workflow/schedules/work-continuation.ts +26 -13
  385. package/src/testing/test-governance.ts +8 -40
  386. package/assets/reference-configs/heartbeat-triage.md +0 -57
  387. package/assets/templates/helpers/harness-trace-grade.sh +0 -150
  388. package/assets/templates/helpers/heartbeat-triage.sh +0 -361
  389. package/assets/templates/helpers/maintenance-triage.sh +0 -167
  390. package/docs/architecture/current/approved-target-architecture.zh-CN.md +0 -1501
  391. package/docs/architecture/current/architecture-invariants.md +0 -331
  392. package/docs/architecture/current/automation-and-schedule-engine.md +0 -459
  393. package/docs/architecture/current/codegraph-context-provider.md +0 -238
  394. package/docs/architecture/current/control-plane-authority-inventory.md +0 -94
  395. package/docs/architecture/current/controller-repository-decoupling.md +0 -148
  396. package/docs/architecture/current/dispatch-and-agent-strategy.md +0 -373
  397. package/docs/architecture/current/entity-model.md +0 -612
  398. package/docs/architecture/current/external-plugin-governance.md +0 -396
  399. package/docs/architecture/current/failure-recovery.md +0 -447
  400. package/docs/architecture/current/governance.md +0 -213
  401. package/docs/architecture/current/human-interaction-plane.md +0 -87
  402. package/docs/architecture/current/implementation-status.md +0 -128
  403. package/docs/architecture/current/job-and-run-lifecycle.md +0 -413
  404. package/docs/architecture/current/legacy-governance.md +0 -58
  405. package/docs/architecture/current/local-workspace-target-grants.md +0 -70
  406. package/docs/architecture/current/migration-roadmap.md +0 -105
  407. package/docs/architecture/current/multi-repository-execution.md +0 -371
  408. package/docs/architecture/current/operations-runbook.md +0 -45
  409. package/docs/architecture/current/peer-supercontroller-runtime.md +0 -32
  410. package/docs/architecture/current/personal-assistant-plugin-baseline.md +0 -206
  411. package/docs/architecture/current/repository-access-modes.md +0 -102
  412. package/docs/architecture/current/route-policy.md +0 -15
  413. package/docs/architecture/current/route-session-concurrency.md +0 -85
  414. package/docs/architecture/current/runtime-architecture-simplification.md +0 -214
  415. package/docs/architecture/current/runtime-directory-map.md +0 -49
  416. package/docs/architecture/current/runtime-health-and-resource-lifecycle.md +0 -85
  417. package/docs/architecture/current/scheduler-and-resource-claims.md +0 -422
  418. package/docs/architecture/current/session-aware-execution-and-authorization.md +0 -77
  419. package/docs/architecture/current/system-overview.md +0 -169
  420. package/docs/architecture/current/target-requirements-traceability.md +0 -202
  421. package/docs/architecture/current/thin-harness-governance-policy.md +0 -32
  422. package/docs/architecture/current/thin-harness-v1.md +0 -321
  423. package/docs/architecture/current/verification-and-release-gates.md +0 -391
  424. package/docs/forge-autonomous-goal-loop.md +0 -9
  425. package/docs/forge-provider-configuration.md +0 -7
  426. package/docs/operations/chatgpt-personal-assistant-runtime.md +0 -93
  427. package/docs/operations/gmail-assistant-routines.md +0 -186
  428. package/docs/operations/personal-assistant-operator-guide.md +0 -61
  429. package/docs/operations/provider-configuration.md +0 -31
  430. package/scripts/harness-trace-grade.sh +0 -150
  431. package/scripts/heartbeat-triage.sh +0 -361
  432. package/scripts/maintenance-triage.sh +0 -167
  433. package/src/cli/local-bridge/frontend/src/features/settings/SettingsView.tsx +0 -2
  434. package/src/cli/repositories/goal-registry.ts +0 -239
  435. package/src/runtime/assistant/action-proposals.ts +0 -279
  436. package/src/runtime/assistant/intent.ts +0 -395
  437. package/src/runtime/assistant/model-provider.ts +0 -460
  438. package/src/runtime/assistant/openapi.ts +0 -223
  439. package/src/runtime/assistant/policy.ts +0 -89
  440. package/src/runtime/assistant/readiness.ts +0 -258
  441. package/src/runtime/assistant/routine-runtime.ts +0 -477
  442. package/src/runtime/assistant/schedule-binding.ts +0 -171
  443. package/src/runtime/assistant/standing-grants.ts +0 -375
  444. package/src/runtime/assistant/store.ts +0 -243
  445. package/src/runtime/assistant/types.ts +0 -135
  446. package/src/runtime/control-plane/goal-loop/config-facade.ts +0 -700
  447. package/src/runtime/control-plane/goal-loop/config-store.ts +0 -570
  448. package/src/runtime/control-plane/goal-loop/config-types.ts +0 -213
  449. package/src/runtime/control-plane/goal-loop/executor-router.ts +0 -109
  450. package/src/runtime/control-plane/goal-loop/failure-taxonomy.ts +0 -149
  451. package/src/runtime/control-plane/goal-loop/goal-contract-store.ts +0 -304
  452. package/src/runtime/control-plane/goal-loop/goal-loop-engine.ts +0 -1001
  453. package/src/runtime/control-plane/goal-loop/handoff-packet.ts +0 -160
  454. package/src/runtime/control-plane/goal-loop/index.ts +0 -13
  455. package/src/runtime/control-plane/goal-loop/local-tools.ts +0 -290
  456. package/src/runtime/control-plane/goal-loop/policy-gates.ts +0 -203
  457. package/src/runtime/control-plane/goal-loop/provider-dispatch.ts +0 -93
  458. package/src/runtime/control-plane/goal-loop/provider-registry.ts +0 -545
  459. package/src/runtime/control-plane/goal-loop/types.ts +0 -378
  460. package/src/runtime/control-plane/startup-recovery.ts +0 -198
  461. package/src/runtime/gateway/mcp/resource-policy.ts +0 -186
  462. package/src/runtime/personal-assistant/gmail-triage-manager.ts +0 -231
  463. package/src/runtime/personal-assistant/reporting-runtime.ts +0 -344
  464. package/src/runtime/personal-assistant/triage-runtime.ts +0 -748
  465. package/src/runtime/workflow/findings/store.ts +0 -204
  466. package/src/runtime/workflow/findings/types.ts +0 -58
  467. package/src/runtime/workflow/portfolio/engine.ts +0 -20
  468. package/src/runtime/workflow/portfolio/store.ts +0 -185
  469. package/src/runtime/workflow/portfolio/types.ts +0 -29
@@ -13,7 +13,7 @@ export interface ToolDefinitionCacheOptions {
13
13
  maxEntriesPerSession?: number;
14
14
  }
15
15
 
16
- const CORE_TOOL_NAMES = new Set(['rh_context', 'rh_access', 'work_submit', 'work_get', 'work_list', 'controller_ready']);
16
+ const CORE_TOOL_NAMES = new Set(['rh_context', 'rh_access', 'rh_work', 'rh_status', 'rh_inbox']);
17
17
 
18
18
  export function controllerCapabilityGroupForTool(name: string): ControllerCapabilityGroup {
19
19
  if (CORE_TOOL_NAMES.has(name)) return 'core';
@@ -0,0 +1,14 @@
1
+ import type { CallToolResult as SdkCallToolResult } from '@modelcontextprotocol/sdk/types.js';
2
+
3
+ /** Transport-neutral MCP tool schema used by legacy, repository and Runtime surfaces. */
4
+ export interface McpToolDefinition {
5
+ name: string;
6
+ description: string;
7
+ inputSchema: Record<string, unknown>;
8
+ annotations?: Record<string, unknown>;
9
+ }
10
+
11
+ /** Bounded text-first result contract shared by Forge MCP adapters. */
12
+ export type CallToolResult = Omit<SdkCallToolResult, 'content'> & {
13
+ content: Array<{ type: 'text'; text: string }>;
14
+ };
@@ -8,7 +8,7 @@ export interface ControllerToolsetSelection {
8
8
  }
9
9
 
10
10
  export function normalizeConfiguredMcpToolset(value: unknown): McpToolset | undefined {
11
- return value === 'core' || value === 'advanced' || value === 'full' ? value : undefined;
11
+ return value === 'facade' || value === 'core' || value === 'advanced' || value === 'full' ? value : undefined;
12
12
  }
13
13
 
14
14
  /** Persisted Core and Advanced are compatibility-equivalent stable profiles. */
@@ -1,4 +1,4 @@
1
- import type { McpToolDefinition } from './tools';
1
+ import type { McpToolDefinition } from './tool-contract';
2
2
  import type { MultiRepositoryMcpToolContext } from './multi-repository';
3
3
  import { buildMultiRepositoryToolDefinitions } from './multi-repository';
4
4
  import { accessToolDefinitions } from './access-tools';
@@ -7,7 +7,7 @@ import {
7
7
  type ControllerAccessState,
8
8
  } from './access-mode';
9
9
  import { repositoryToolDefinitions } from './repository-tools';
10
- import { runtimeToolDefinitions } from '../../runtime/gateway/mcp/runtime-tools';
10
+ import { runtimeToolDefinitions } from '../../runtime/gateway/mcp/runtime-tool-definitions';
11
11
  import { executionToolDefinitions } from '../../runtime/gateway/mcp/execution-tools';
12
12
  import { processToolDefinitions } from '../../runtime/gateway/mcp/process-tools';
13
13
  import { injectDurableCommandFields } from '../../runtime/gateway/mcp/router';
@@ -17,7 +17,7 @@ import type { McpToolset } from './types';
17
17
  import { forgeToolSurfaceFingerprint } from '../controller/runtime-config';
18
18
 
19
19
  export type ToolExposureClass = 'facade' | 'advanced' | 'internal' | 'compatibility';
20
- export type ControllerToolProfile = 'core' | 'advanced' | 'full';
20
+ export type ControllerToolProfile = 'facade' | 'core' | 'advanced' | 'full';
21
21
 
22
22
  export interface ControllerToolInventoryEntry {
23
23
  name: string;
@@ -48,6 +48,22 @@ export interface ControllerExposureSnapshot {
48
48
  ready: boolean;
49
49
  }
50
50
 
51
+ /**
52
+ * Cached schema/readiness projection for hot paths that do not need access
53
+ * policy or a per-tool inventory. Status uses this rather than rebuilding a
54
+ * complete controller exposure response on every read.
55
+ */
56
+ export interface ControllerToolSurfaceStatus {
57
+ expectedToolNames: string[];
58
+ actualToolNames: string[];
59
+ missingToolNames: string[];
60
+ unexpectedToolNames: string[];
61
+ duplicateToolNames: string[];
62
+ fingerprint: string;
63
+ schemaStableAcrossAccessModes: true;
64
+ ready: boolean;
65
+ }
66
+
51
67
  /**
52
68
  * Core and Advanced expose the same bounded default ChatGPT surface
53
69
  * (DEFAULT_CONTROLLER_TOOL_NAMES). Full remains the exhaustive compatibility
@@ -84,7 +100,7 @@ function pruneStaticExposureCache(): void {
84
100
  }
85
101
 
86
102
  export function normalizeMcpToolset(value: unknown): McpToolset {
87
- if (value === 'full' || value === 'advanced' || value === 'core') return value;
103
+ if (value === 'full' || value === 'advanced' || value === 'core' || value === 'facade') return value;
88
104
  return 'advanced';
89
105
  }
90
106
 
@@ -97,6 +113,7 @@ export function controllerToolNamesForToolset(
97
113
  _ctx?: MultiRepositoryMcpToolContext,
98
114
  ): readonly string[] | null {
99
115
  if (toolset === 'full') return null;
116
+ if (toolset === 'facade') return PREFERRED_FACADE_TOOL_NAMES;
100
117
  return DEFAULT_CONTROLLER_TOOL_NAMES;
101
118
  }
102
119
 
@@ -158,13 +175,19 @@ function staticExposureCacheKey(ctx: MultiRepositoryMcpToolContext): string {
158
175
  function buildStaticControllerExposureSnapshot(
159
176
  ctx: MultiRepositoryMcpToolContext,
160
177
  ): StaticControllerExposureSnapshot {
161
- const rawDefinitions = runtimeToolDefinitions.concat(
178
+ const currentDefinitions = runtimeToolDefinitions.concat(
162
179
  executionToolDefinitions,
163
180
  processToolDefinitions,
164
181
  accessToolDefinitions,
165
182
  repositoryToolDefinitions,
166
- buildMultiRepositoryToolDefinitions(ctx),
167
183
  );
184
+ const rawDefinitions = ctx.toolset === 'full'
185
+ ? currentDefinitions.concat(
186
+ buildMultiRepositoryToolDefinitions(ctx).filter(
187
+ (legacy) => !currentDefinitions.some((current) => current.name === legacy.name),
188
+ ),
189
+ )
190
+ : currentDefinitions;
168
191
  const unique = uniqueDefinitions(rawDefinitions);
169
192
  const allowed = controllerToolNamesForToolset(ctx.toolset, ctx);
170
193
  const expectedToolNames = allowed === null
@@ -226,7 +249,7 @@ function capabilityForToolName(name: string): string {
226
249
  }
227
250
 
228
251
  function profileForToolset(toolset: McpToolset): ControllerToolProfile {
229
- return toolset === 'full' ? 'full' : toolset === 'core' ? 'core' : 'advanced';
252
+ return toolset === 'full' ? 'full' : toolset === 'facade' ? 'facade' : toolset === 'core' ? 'core' : 'advanced';
230
253
  }
231
254
 
232
255
  export function controllerToolInventory(
@@ -263,6 +286,20 @@ export function controllerExposureSnapshot(ctx: MultiRepositoryMcpToolContext):
263
286
  };
264
287
  }
265
288
 
289
+ export function controllerToolSurfaceStatus(ctx: MultiRepositoryMcpToolContext): ControllerToolSurfaceStatus {
290
+ const snapshot = staticControllerExposureSnapshot(ctx);
291
+ return {
292
+ expectedToolNames: snapshot.expectedToolNames,
293
+ actualToolNames: snapshot.actualToolNames,
294
+ missingToolNames: snapshot.missingToolNames,
295
+ unexpectedToolNames: snapshot.unexpectedToolNames,
296
+ duplicateToolNames: snapshot.duplicateToolNames,
297
+ fingerprint: snapshot.fingerprint,
298
+ schemaStableAcrossAccessModes: snapshot.schemaStableAcrossAccessModes,
299
+ ready: snapshot.ready,
300
+ };
301
+ }
302
+
266
303
  export function controllerExposedToolNames(ctx: MultiRepositoryMcpToolContext): string[] {
267
304
  return controllerExposureSnapshot(ctx).actualToolNames;
268
305
  }
@@ -11,9 +11,11 @@ import type { OAuthClientInformationFull } from '@modelcontextprotocol/sdk/share
11
11
  import { StreamableHTTPServerTransport } from '@modelcontextprotocol/sdk/server/streamableHttp.js';
12
12
  import {
13
13
  buildMultiRepositoryToolDefinitions,
14
+ createCanonicalRuntimeProxy,
14
15
  createMcpToolContext,
15
16
  createForgeMcpServerFromContext,
16
17
  readCanonicalRuntimeToolSchema,
18
+ type CanonicalRuntimeProxy,
17
19
  type CanonicalRuntimeToolSchema,
18
20
  type McpServerOptions,
19
21
  } from '../server';
@@ -36,6 +38,7 @@ import {
36
38
  controllerExposureSnapshot,
37
39
  } from '../toolset';
38
40
  import { readForgeRuntimeStatus } from '../../../runtime/control-plane/runtime-status-client';
41
+ import { invalidateExecutionSession } from '../../../runtime/control-plane/execution/session-store';
39
42
  import { runtimeIdentitySnapshot } from '../../../runtime/gateway/mcp/runtime-tools';
40
43
  import { projectionBlocksReadiness, readRepositoryProjectionSnapshot } from '../../../runtime/projections/materialized-view';
41
44
  import { readRuntimeGeneration } from '../../../runtime/control-plane/runtime-generation';
@@ -194,6 +197,14 @@ export async function resolveMcpSessionCurrentFingerprint(
194
197
  return await loadRuntimeFingerprint?.();
195
198
  }
196
199
 
200
+ export function isMcpToolsListRequest(body: unknown): boolean {
201
+ const messages = Array.isArray(body) ? body : [body];
202
+ return messages.length > 0 && messages.every((message) => {
203
+ if (!message || typeof message !== 'object') return false;
204
+ return (message as { method?: unknown }).method === 'tools/list';
205
+ });
206
+ }
207
+
197
208
  function toolCallOutsideSessionSchema(body: unknown, toolNames: readonly string[] | undefined): boolean {
198
209
  if (!toolNames) return false;
199
210
  const messages = Array.isArray(body) ? body : [body];
@@ -620,6 +631,11 @@ function requireMcpHttpAuth(
620
631
  resourcePath = '/mcp',
621
632
  ) {
622
633
  return (req: Request, res: Response, next: NextFunction) => {
634
+ if (mode === 'none') {
635
+ next();
636
+ return;
637
+ }
638
+
623
639
  if (mode === 'bearer') {
624
640
  if (!isAuthorizedMcpHttpRequest(req, bearerToken)) {
625
641
  sendBearerUnauthorized(res, bearerToken ? 'Missing or invalid Authorization header' : 'Bearer token is not configured', Boolean(bearerToken));
@@ -666,7 +682,7 @@ function positiveIntegerEnv(name: string, fallback: number): number {
666
682
  }
667
683
 
668
684
  const MAX_MCP_SESSIONS = positiveIntegerEnv('FORGE_MCP_MAX_SESSIONS', 64);
669
- const MAX_MCP_SESSIONS_PER_PRINCIPAL = positiveIntegerEnv('FORGE_MCP_MAX_SESSIONS_PER_PRINCIPAL', 8);
685
+ const MAX_MCP_SESSIONS_PER_PRINCIPAL = positiveIntegerEnv('FORGE_MCP_MAX_SESSIONS_PER_PRINCIPAL', MAX_MCP_SESSIONS);
670
686
  const MAX_INITIALIZING_SESSIONS = positiveIntegerEnv('FORGE_MCP_MAX_INITIALIZING_SESSIONS', 8);
671
687
  const MAX_POSTS_PER_SESSION = positiveIntegerEnv('FORGE_MCP_MAX_POSTS_PER_SESSION', 4);
672
688
  const MAX_ACTIVE_POSTS = positiveIntegerEnv('FORGE_MCP_MAX_ACTIVE_POSTS', 32);
@@ -687,6 +703,7 @@ async function handleMcpPost(
687
703
  route: McpSessionRoute,
688
704
  currentToolSurfaceFingerprint: () => string | undefined,
689
705
  resolveRuntimeSchema?: (context: McpToolContext) => Promise<CanonicalRuntimeToolSchema | undefined>,
706
+ sharedRuntimeProxy?: CanonicalRuntimeProxy,
690
707
  ): Promise<void> {
691
708
  let body: unknown;
692
709
  try {
@@ -713,7 +730,15 @@ async function handleMcpPost(
713
730
  if (stats.initializing >= MAX_INITIALIZING_SESSIONS || stats.activePosts >= MAX_ACTIVE_POSTS) {
714
731
  stats.rejectedOverload += 1;
715
732
  res.setHeader('retry-after', '1');
716
- res.status(503).json({ error: 'server_busy', message: 'Too many MCP sessions are initializing; retry shortly' });
733
+ res.status(503).json({
734
+ error: 'server_busy',
735
+ code: 'MCP_SERVER_BUSY',
736
+ message: 'Too many MCP sessions are initializing; retry shortly',
737
+ recoverable: true,
738
+ retryable: true,
739
+ sessionPreserved: true,
740
+ action: 'retry',
741
+ });
717
742
  return;
718
743
  }
719
744
  stats.initializing += 1;
@@ -733,7 +758,15 @@ async function handleMcpPost(
733
758
  if (!reservationId) {
734
759
  stats.rejectedOverload += 1;
735
760
  res.setHeader('retry-after', '1');
736
- res.status(503).json({ error: 'session_capacity', message: 'All MCP sessions are executing active work; retry shortly' });
761
+ res.status(503).json({
762
+ error: 'session_capacity',
763
+ code: 'MCP_SESSION_CAPACITY',
764
+ message: 'All MCP sessions are executing active requests; retry shortly',
765
+ recoverable: true,
766
+ retryable: true,
767
+ sessionPreserved: true,
768
+ action: 'retry',
769
+ });
737
770
  return;
738
771
  }
739
772
  const sessionContext = createMcpToolContext({
@@ -741,7 +774,7 @@ async function handleMcpPost(
741
774
  sessionId: `mcp_${randomUUID().replace(/-/g, '')}`,
742
775
  principalId,
743
776
  });
744
- const runtimeSchema = await resolveRuntimeSchema?.(sessionContext);
777
+ let runtimeSchema = await resolveRuntimeSchema?.(sessionContext);
745
778
  let server: ReturnType<typeof createForgeMcpServerFromContext> | undefined;
746
779
  transport = new StreamableHTTPServerTransport({
747
780
  sessionIdGenerator: () => randomUUID(),
@@ -756,6 +789,21 @@ async function handleMcpPost(
756
789
  toolSurfaceFingerprint: runtimeSchema?.fingerprint ?? currentToolSurfaceFingerprint(),
757
790
  toolNames: runtimeSchema?.toolNames,
758
791
  notifyToolListChanged: async () => { await server?.sendToolListChanged(); },
792
+ ...(runtimeSchema && resolveRuntimeSchema
793
+ ? {
794
+ refreshToolSurface: async () => {
795
+ const refreshed = await resolveRuntimeSchema(sessionContext);
796
+ if (!refreshed || !runtimeSchema) return undefined;
797
+ runtimeSchema.definitions = refreshed.definitions;
798
+ runtimeSchema.toolNames = refreshed.toolNames;
799
+ runtimeSchema.fingerprint = refreshed.fingerprint;
800
+ return {
801
+ toolSurfaceFingerprint: refreshed.fingerprint,
802
+ toolNames: refreshed.toolNames,
803
+ };
804
+ },
805
+ }
806
+ : {}),
759
807
  });
760
808
  initializedSessionId = newSessionId;
761
809
  },
@@ -763,7 +811,7 @@ async function handleMcpPost(
763
811
  transport.onclose = () => {
764
812
  if (transport?.sessionId) registry.detach(transport.sessionId);
765
813
  };
766
- server = createForgeMcpServerFromContext(sessionContext, runtimeSchema);
814
+ server = createForgeMcpServerFromContext(sessionContext, runtimeSchema, sharedRuntimeProxy);
767
815
  await server.connect(transport);
768
816
  await transport.handleRequest(req, res, body);
769
817
  } finally {
@@ -794,6 +842,17 @@ async function handleMcpPost(
794
842
  : undefined,
795
843
  );
796
844
  if (!mcpSessionToolSurfaceFingerprintIsCurrent(managed.toolSurfaceFingerprint, currentFingerprint)) {
845
+ // Standard MCP hot refresh: allow an explicitly requested tools/list
846
+ // to replace the live session's mutable Runtime schema snapshot. Hosts
847
+ // that ignore list_changed and call directly still hit the reset fence.
848
+ if (isMcpToolsListRequest(body)) {
849
+ const refreshed = await registry.refreshToolSurface(sessionId);
850
+ if (refreshed
851
+ && (!currentFingerprint || refreshed.toolSurfaceFingerprint === currentFingerprint)) {
852
+ await managed.transport.handleRequest(req, res, body);
853
+ return;
854
+ }
855
+ }
797
856
  // Keep the transport/session alive long enough for the host to observe
798
857
  // the recoverable reset and issue a replacement initialize request.
799
858
  // The initialize path explicitly supersedes this session afterward.
@@ -877,10 +936,15 @@ async function handleMcpDelete(req: Request, res: Response, registry: HttpSessio
877
936
  export async function startMcpHttp(opts: McpHttpOptions): Promise<void> {
878
937
  const host = opts.host ?? '127.0.0.1';
879
938
  const port = opts.port ?? 8765;
880
- const repoRoot = resolveMcpRepoRoot(opts.repo ?? '.');
881
939
  const controllerHome = resolveControllerHome(opts.controllerHome);
882
- const serviceConfig = loadMcpServiceLocalConfig(controllerHome, repoRoot);
940
+ const serviceConfig = loadMcpServiceLocalConfig(controllerHome);
883
941
  const profile = opts.profile ?? serviceConfig?.profile ?? 'controller';
942
+ // A controller Gateway can serve registered repositories without selecting
943
+ // one at startup. Do not turn its launchd working directory into an
944
+ // implicit repository, especially for package Runtime snapshots.
945
+ const repoRoot = profile === 'controller' && !opts.repo?.trim()
946
+ ? undefined
947
+ : resolveMcpRepoRoot(opts.repo ?? '.');
884
948
  const authMode = parseMcpHttpAuthMode(opts.auth ?? serviceConfig?.auth?.mode);
885
949
  const authToken = opts.authToken ?? readMcpServiceBearerToken(controllerHome, repoRoot);
886
950
  const oauthPassphrase = authMode === 'oauth'
@@ -902,6 +966,17 @@ export async function startMcpHttp(opts: McpHttpOptions): Promise<void> {
902
966
  streamLeaseMs: MCP_STREAM_LEASE_MS,
903
967
  absoluteLifetimeMs: MCP_SESSION_ABSOLUTE_LIFETIME_MS,
904
968
  activePostStallMs: MCP_ACTIVE_POST_STALL_MS,
969
+ onSessionClosed: (session, reason) => {
970
+ const context = session.toolContext;
971
+ if (!('controllerHome' in context) || typeof context.controllerHome !== 'string') return;
972
+ const executionSessionId = typeof context.sessionId === 'string' ? context.sessionId.trim() : '';
973
+ if (!executionSessionId) return;
974
+ invalidateExecutionSession(
975
+ context.controllerHome,
976
+ executionSessionId,
977
+ `mcp_transport_${reason}`,
978
+ );
979
+ },
905
980
  });
906
981
  const runtimeStats: McpRuntimeStats = { initializing: 0, activePosts: 0, rejectedOverload: 0 };
907
982
  const toolContext = createMcpToolContext({ ...opts, repo: repoRoot, controllerHome, profile });
@@ -917,6 +992,9 @@ export async function startMcpHttp(opts: McpHttpOptions): Promise<void> {
917
992
  devRunnerMaxTimeoutMs: opts.devRunnerMaxTimeoutMs,
918
993
  };
919
994
  const runtimeControllerHome = 'controllerHome' in toolContext ? toolContext.controllerHome : undefined;
995
+ const sharedRuntimeProxy = runtimeControllerHome && 'controllerHome' in toolContext && !toolContext.runtimeSourceRoot
996
+ ? createCanonicalRuntimeProxy(toolContext)
997
+ : undefined;
920
998
  const currentRuntimeGeneration = () => runtimeControllerHome ? readRuntimeGeneration(runtimeControllerHome) : undefined;
921
999
  const currentRuntimeToolSurfaceFingerprint = () => runtimeControllerHome
922
1000
  ? readRuntimeStatusSnapshot(runtimeControllerHome)?.toolSurfaceFingerprint
@@ -941,7 +1019,7 @@ export async function startMcpHttp(opts: McpHttpOptions): Promise<void> {
941
1019
  const resolveRuntimeSchema = runtimeControllerHome
942
1020
  ? async (context: McpToolContext): Promise<CanonicalRuntimeToolSchema | undefined> => {
943
1021
  if (!('controllerHome' in context)) return undefined;
944
- return await readCanonicalRuntimeToolSchema(context);
1022
+ return await readCanonicalRuntimeToolSchema(context, sharedRuntimeProxy);
945
1023
  }
946
1024
  : undefined;
947
1025
  const localControllerConfig = {
@@ -953,7 +1031,7 @@ export async function startMcpHttp(opts: McpHttpOptions): Promise<void> {
953
1031
  const toolSurface = toolContext.policy.profile === 'controller' ? FORGE_TOOL_SURFACE : `${toolContext.policy.profile}-legacy-v1`;
954
1032
  const toolSurfaceSchemaVersion = toolContext.policy.profile === 'controller' ? FORGE_MCP_SCHEMA_VERSION : 1;
955
1033
  const forgeVersion = FORGE_VERSION;
956
- const repoId = toolContext.policy.profile === 'controller' ? undefined : repositoryIdentity(repoRoot);
1034
+ const repoId = toolContext.policy.profile === 'controller' || !repoRoot ? undefined : repositoryIdentity(repoRoot);
957
1035
  const startedAt = new Date().toISOString();
958
1036
  const localOrigin = `http://${host === '::' || host === '0.0.0.0' ? '127.0.0.1' : host}:${port}`;
959
1037
  const advertisedOrigin = configuredPublicOrigin ?? localOrigin;
@@ -1027,7 +1105,11 @@ export async function startMcpHttp(opts: McpHttpOptions): Promise<void> {
1027
1105
  defaultTimeoutMs: toolContext.policy.execution.runnerTimeoutMs,
1028
1106
  maxTimeoutMs: toolContext.policy.execution.runnerMaxTimeoutMs,
1029
1107
  },
1030
- auth: authMode === 'oauth' ? (oauthPassphrase ? 'oauth' : 'missing') : (authToken ? 'required' : 'missing'),
1108
+ auth: authMode === 'oauth'
1109
+ ? (oauthPassphrase ? 'oauth' : 'missing')
1110
+ : authMode === 'bearer'
1111
+ ? (authToken ? 'required' : 'missing')
1112
+ : 'none',
1031
1113
  mcpEndpoint: `${advertisedOrigin}/mcp`,
1032
1114
  // Grok now completes standard OAuth dynamic registration + PKCE on the
1033
1115
  // canonical MCP resource. Keep /mcp-grok below only as a legacy alias.
@@ -1043,6 +1125,29 @@ export async function startMcpHttp(opts: McpHttpOptions): Promise<void> {
1043
1125
  });
1044
1126
  });
1045
1127
 
1128
+ // Recovery probes this endpoint every few seconds. Keep it strictly in-memory
1129
+ // and transport-scoped: whole-control-plane readiness below may traverse every
1130
+ // repository projection and probe the local bridge, which must never become a
1131
+ // periodic event-loop load generator for the public MCP Connector itself.
1132
+ app.get('/transport-ready', (_req, res) => {
1133
+ const sessionSnapshot = sessionRegistry.snapshot();
1134
+ const sessionCapacityReady = sessionSnapshot.acceptingNewSessions
1135
+ && runtimeStats.initializing < MAX_INITIALIZING_SESSIONS
1136
+ && runtimeStats.activePosts < MAX_ACTIVE_POSTS;
1137
+ res.status(sessionCapacityReady ? 200 : 503).json({
1138
+ ready: sessionCapacityReady,
1139
+ profile: toolContext.policy.profile,
1140
+ gateway: sessionCapacityReady ? 'ready' : 'saturated',
1141
+ sessionCapacity: sessionSnapshot,
1142
+ runtimeCapacity: {
1143
+ initializing: runtimeStats.initializing,
1144
+ maximumInitializing: MAX_INITIALIZING_SESSIONS,
1145
+ activePosts: runtimeStats.activePosts,
1146
+ maximumActivePosts: MAX_ACTIVE_POSTS,
1147
+ },
1148
+ });
1149
+ });
1150
+
1046
1151
  app.get('/ready', async (_req, res) => {
1047
1152
  const runtimeGeneration = currentRuntimeGeneration();
1048
1153
  const sessionSnapshot = sessionRegistry.snapshot();
@@ -1216,7 +1321,7 @@ export async function startMcpHttp(opts: McpHttpOptions): Promise<void> {
1216
1321
  // Primary MCP path: OAuth (or bearer when --auth bearer). Unchanged for ChatGPT.
1217
1322
  app.use('/mcp', setMcpResponseHeaders);
1218
1323
  app.post('/mcp', requireMcpHttpAuth(authMode, authToken, oauthProvider, configuredPublicOrigin), express.raw({ type: '*/*', limit: '1mb' }), (req, res) => {
1219
- handleMcpPost(req, res, baseOptions, sessionRegistry, runtimeStats, '/mcp', currentRuntimeToolSurfaceFingerprint, resolveRuntimeSchema).catch((error: unknown) => {
1324
+ handleMcpPost(req, res, baseOptions, sessionRegistry, runtimeStats, '/mcp', currentRuntimeToolSurfaceFingerprint, resolveRuntimeSchema, sharedRuntimeProxy).catch((error: unknown) => {
1220
1325
  if (!res.headersSent) sendMcpRequestError(res, error);
1221
1326
  });
1222
1327
  });
@@ -1234,7 +1339,7 @@ export async function startMcpHttp(opts: McpHttpOptions): Promise<void> {
1234
1339
  // Legacy Grok OAuth resource. New Grok connectors should use canonical /mcp.
1235
1340
  app.use('/mcp-grok', setMcpResponseHeaders);
1236
1341
  app.post('/mcp-grok', requireMcpHttpAuth(authMode, authToken, oauthProvider, configuredPublicOrigin, '/mcp-grok'), express.raw({ type: '*/*', limit: '1mb' }), (req, res) => {
1237
- handleMcpPost(req, res, baseOptions, sessionRegistry, runtimeStats, '/mcp-grok', currentRuntimeToolSurfaceFingerprint, resolveRuntimeSchema).catch((error: unknown) => {
1342
+ handleMcpPost(req, res, baseOptions, sessionRegistry, runtimeStats, '/mcp-grok', currentRuntimeToolSurfaceFingerprint, resolveRuntimeSchema, sharedRuntimeProxy).catch((error: unknown) => {
1238
1343
  if (!res.headersSent) sendMcpRequestError(res, error);
1239
1344
  });
1240
1345
  });
@@ -1252,7 +1357,7 @@ export async function startMcpHttp(opts: McpHttpOptions): Promise<void> {
1252
1357
  // Bearer-only MCP path for clients that can send Authorization headers. Never advertises OAuth resource_metadata.
1253
1358
  app.use('/mcp-bearer', setMcpResponseHeaders);
1254
1359
  app.post('/mcp-bearer', requireMcpHttpAuth('bearer', authToken, null, configuredPublicOrigin), express.raw({ type: '*/*', limit: '1mb' }), (req, res) => {
1255
- handleMcpPost(req, res, baseOptions, sessionRegistry, runtimeStats, '/mcp-bearer', currentRuntimeToolSurfaceFingerprint, resolveRuntimeSchema).catch((error: unknown) => {
1360
+ handleMcpPost(req, res, baseOptions, sessionRegistry, runtimeStats, '/mcp-bearer', currentRuntimeToolSurfaceFingerprint, resolveRuntimeSchema, sharedRuntimeProxy).catch((error: unknown) => {
1256
1361
  if (!res.headersSent) sendMcpRequestError(res, error);
1257
1362
  });
1258
1363
  });
@@ -1284,12 +1389,17 @@ export async function startMcpHttp(opts: McpHttpOptions): Promise<void> {
1284
1389
  if (toolSurfaceNotificationTimer) clearTimeout(toolSurfaceNotificationTimer);
1285
1390
  runtimeStatusWatcher?.close();
1286
1391
  void sessionRegistry.closeAll('shutdown');
1392
+ void sharedRuntimeProxy?.close();
1287
1393
  });
1288
1394
 
1289
1395
  await new Promise<void>((resolve) => {
1290
1396
  httpServer.once('listening', resolve);
1291
1397
  });
1292
- const authLabel = authMode === 'oauth' ? (oauthPassphrase ? 'oauth' : 'oauth-missing') : (authToken ? 'bearer' : 'missing');
1398
+ const authLabel = authMode === 'oauth'
1399
+ ? (oauthPassphrase ? 'oauth' : 'oauth-missing')
1400
+ : authMode === 'bearer'
1401
+ ? (authToken ? 'bearer' : 'missing')
1402
+ : 'none';
1293
1403
  console.error(
1294
1404
  `forge mcp http listening on http://${host}:${port}/mcp (auth: ${authLabel}), http://${host}:${port}/mcp-grok (auth: ${authLabel}), and http://${host}:${port}/mcp-bearer (auth: bearer)`,
1295
1405
  );
@@ -18,6 +18,11 @@ export interface ClosableMcpTransport {
18
18
  close(): Promise<void> | void;
19
19
  }
20
20
 
21
+ export interface McpToolSurfaceRefresh {
22
+ toolSurfaceFingerprint: string;
23
+ toolNames?: string[];
24
+ }
25
+
21
26
  export interface ManagedMcpSession<
22
27
  TTransport extends ClosableMcpTransport = ClosableMcpTransport,
23
28
  TContext = unknown,
@@ -33,6 +38,8 @@ export interface ManagedMcpSession<
33
38
  toolNames?: string[];
34
39
  /** Standard MCP tools/list_changed notification bound to this session's connected Server. */
35
40
  notifyToolListChanged?: () => Promise<void> | void;
41
+ /** Refreshes the mutable Runtime schema snapshot backing this live MCP session. */
42
+ refreshToolSurface?: () => Promise<McpToolSurfaceRefresh | undefined>;
36
43
  lastNotifiedToolSurfaceFingerprint?: string;
37
44
  createdAt: number;
38
45
  lastActivityAt: number;
@@ -72,7 +79,10 @@ export interface McpSessionSnapshot {
72
79
  closed: McpSessionCloseCounters;
73
80
  }
74
81
 
75
- export interface McpSessionRegistryOptions {
82
+ export interface McpSessionRegistryOptions<
83
+ TTransport extends ClosableMcpTransport = ClosableMcpTransport,
84
+ TContext = unknown,
85
+ > {
76
86
  maximumSessions?: number;
77
87
  maximumSessionsPerPrincipal?: number;
78
88
  idleTtlMs?: number;
@@ -80,6 +90,7 @@ export interface McpSessionRegistryOptions {
80
90
  absoluteLifetimeMs?: number;
81
91
  activePostStallMs?: number;
82
92
  now?: () => number;
93
+ onSessionClosed?: (session: ManagedMcpSession<TTransport, TContext>, reason: McpSessionCloseReason) => void;
83
94
  }
84
95
 
85
96
  interface RegisterMcpSession<TTransport extends ClosableMcpTransport, TContext> {
@@ -92,6 +103,7 @@ interface RegisterMcpSession<TTransport extends ClosableMcpTransport, TContext>
92
103
  toolSurfaceFingerprint?: string;
93
104
  toolNames?: string[];
94
105
  notifyToolListChanged?: () => Promise<void> | void;
106
+ refreshToolSurface?: () => Promise<McpToolSurfaceRefresh | undefined>;
95
107
  initialPost?: boolean;
96
108
  }
97
109
 
@@ -161,12 +173,13 @@ export class McpSessionRegistry<
161
173
  private readonly absoluteLifetimeMs: number;
162
174
  private readonly activePostStallMs: number;
163
175
  private readonly now: () => number;
176
+ private readonly onSessionClosed?: (session: ManagedMcpSession<TTransport, TContext>, reason: McpSessionCloseReason) => void;
164
177
  private readonly closeCounters = emptyCloseCounters();
165
178
  private readonly initializeReservations = new Map<string, InitializeReservation>();
166
179
  private admissionQueue: Promise<void> = Promise.resolve();
167
180
  private nextReservationId = 0;
168
181
 
169
- constructor(options: McpSessionRegistryOptions = {}) {
182
+ constructor(options: McpSessionRegistryOptions<TTransport, TContext> = {}) {
170
183
  this.maximumSessions = positiveInteger(options.maximumSessions, DEFAULT_MAXIMUM_SESSIONS);
171
184
  this.maximumSessionsPerPrincipal = Math.min(
172
185
  this.maximumSessions,
@@ -177,6 +190,7 @@ export class McpSessionRegistry<
177
190
  this.absoluteLifetimeMs = positiveInteger(options.absoluteLifetimeMs, DEFAULT_ABSOLUTE_LIFETIME_MS);
178
191
  this.activePostStallMs = positiveInteger(options.activePostStallMs, DEFAULT_ACTIVE_POST_STALL_MS);
179
192
  this.now = options.now ?? Date.now;
193
+ this.onSessionClosed = options.onSessionClosed;
180
194
  }
181
195
 
182
196
  get size(): number {
@@ -230,6 +244,18 @@ export class McpSessionRegistry<
230
244
  return notified;
231
245
  }
232
246
 
247
+ async refreshToolSurface(sessionId: string): Promise<McpToolSurfaceRefresh | undefined> {
248
+ const session = this.sessions.get(sessionId);
249
+ if (!session?.refreshToolSurface) return undefined;
250
+ const refreshed = await session.refreshToolSurface();
251
+ if (!refreshed?.toolSurfaceFingerprint) return undefined;
252
+ session.toolSurfaceFingerprint = refreshed.toolSurfaceFingerprint;
253
+ session.toolNames = refreshed.toolNames;
254
+ session.lastNotifiedToolSurfaceFingerprint = refreshed.toolSurfaceFingerprint;
255
+ session.lastActivityAt = this.now();
256
+ return refreshed;
257
+ }
258
+
233
259
  beginPost(sessionId: string): ManagedMcpSession<TTransport, TContext> | undefined {
234
260
  const session = this.sessions.get(sessionId);
235
261
  if (!session) return undefined;
@@ -274,9 +300,11 @@ export class McpSessionRegistry<
274
300
  detach(sessionId: string, reason: McpSessionCloseReason = 'transport_close'): boolean {
275
301
  const session = this.sessions.get(sessionId);
276
302
  if (!session) return false;
303
+ const closeReason = session.pendingCloseReason ?? reason;
277
304
  this.sessions.delete(sessionId);
278
305
  clearSessionCachesForSession(sessionId);
279
- this.incrementCloseCounter(session.pendingCloseReason ?? reason);
306
+ this.incrementCloseCounter(closeReason);
307
+ this.observeSessionClosed(session, closeReason);
280
308
  return true;
281
309
  }
282
310
 
@@ -287,6 +315,7 @@ export class McpSessionRegistry<
287
315
  clearSessionCachesForSession(sessionId);
288
316
  session.pendingCloseReason = reason;
289
317
  this.incrementCloseCounter(reason);
318
+ this.observeSessionClosed(session, reason);
290
319
  try {
291
320
  await session.transport.close();
292
321
  } catch {
@@ -296,6 +325,15 @@ export class McpSessionRegistry<
296
325
  return true;
297
326
  }
298
327
 
328
+ private observeSessionClosed(session: ManagedMcpSession<TTransport, TContext>, reason: McpSessionCloseReason): void {
329
+ try {
330
+ this.onSessionClosed?.(session, reason);
331
+ } catch {
332
+ // Session close must remain available even if liveness evidence cannot be recorded.
333
+ // The controller lease then expires normally instead of being released unsafely.
334
+ }
335
+ }
336
+
299
337
  async reserveForInitialize(request: InitializeCapacityRequest): Promise<string | undefined> {
300
338
  return await this.withAdmissionLock(async () => {
301
339
  await this.prune();
@@ -382,7 +420,7 @@ export class McpSessionRegistry<
382
420
  const reservations = [...this.initializeReservations.values()];
383
421
  const activePosts = sessions.reduce((count, session) => count + session.inFlightPosts, 0) + reservations.length;
384
422
  const activeStreams = sessions.reduce((count, session) => count + session.inFlightGets, 0);
385
- const evictable = sessions.filter((session) => session.inFlightPosts === 0).length;
423
+ const evictable = sessions.filter((session) => session.inFlightPosts === 0 && session.inFlightGets === 0).length;
386
424
  const reserved = reservations.length;
387
425
  const protectedCount = sessions.length - evictable + reserved;
388
426
  const capacityAvailable = Math.max(0, this.maximumSessions - sessions.length - reserved);
@@ -437,7 +475,7 @@ export class McpSessionRegistry<
437
475
  predicate: (session: ManagedMcpSession<TTransport, TContext>) => boolean = () => true,
438
476
  ): ManagedMcpSession<TTransport, TContext>[] {
439
477
  return [...this.sessions.values()]
440
- .filter((session) => session.inFlightPosts === 0 && predicate(session))
478
+ .filter((session) => session.inFlightPosts === 0 && session.inFlightGets === 0 && predicate(session))
441
479
  .sort((left, right) => {
442
480
  const leftAge = left.streamOpenedAt ?? left.lastActivityAt;
443
481
  const rightAge = right.streamOpenedAt ?? right.lastActivityAt;
@@ -2,11 +2,11 @@ export type McpProfileName = 'planner' | 'executor' | 'orchestrator' | 'controll
2
2
  export type McpPathIntent = 'read' | 'write';
3
3
  export type McpAgentRunnerName = 'codex' | 'claude';
4
4
  /** Controller MCP tools/list exposure profile.
5
- * - core (default): facade + repository bootstrap/selection only
6
- * - advanced: supervised controller surface (former large core set)
5
+ * - facade: explicit five-tool ChatGPT orchestration surface
6
+ * - core/advanced (default compatibility labels): bounded stable controller surface
7
7
  * - full: compatibility mode — all legacy + runtime tools
8
8
  */
9
- export type McpToolset = 'core' | 'advanced' | 'full';
9
+ export type McpToolset = 'facade' | 'core' | 'advanced' | 'full';
10
10
 
11
11
  export interface McpPolicy {
12
12
  profile: McpProfileName;