@moretea-labs/forge 1.6.0 → 1.7.0

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 (396) hide show
  1. package/AGENTS.md +2 -0
  2. package/CHANGELOG.md +26 -0
  3. package/CLAUDE.md +2 -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/03-orchestration.partial.md +1 -1
  17. package/assets/plugin-registry.v1.json +1 -1
  18. package/assets/reference-configs/document-generation.md +1 -1
  19. package/assets/reference-configs/harness-overview.md +1 -1
  20. package/assets/reference-configs/sprint-contracts.md +3 -3
  21. package/assets/skill-version.json +2 -2
  22. package/assets/templates/contract.template.md +2 -7
  23. package/assets/templates/helpers/capture-plan.sh +2 -2
  24. package/assets/templates/helpers/check-task-workflow.sh +4 -4
  25. package/assets/templates/helpers/contract-worktree.sh +1 -21
  26. package/assets/templates/helpers/ensure-task-workflow.sh +11 -36
  27. package/assets/templates/helpers/migrate-project-template.sh +22 -45
  28. package/assets/templates/helpers/new-plan.sh +1 -1
  29. package/assets/templates/helpers/plan-to-todo.sh +12 -37
  30. package/assets/templates/helpers/ship-worktrees.sh +2 -29
  31. package/assets/templates/helpers/verify-contract.sh +1 -111
  32. package/assets/templates/helpers/verify-sprint.sh +3 -180
  33. package/assets/templates/plan.template.md +1 -1
  34. package/assets/templates/review.template.md +9 -34
  35. package/assets/workflow-contract.v1.json +10 -19
  36. package/docs/README.md +10 -10
  37. package/docs/architecture/CURRENT.md +170 -0
  38. package/docs/architecture/EVOLUTION.md +42 -0
  39. package/docs/architecture/current/README.md +4 -156
  40. package/docs/architecture/decisions/20260803-release-identity-binding-and-exit-policy.md +2 -2
  41. package/docs/architecture/decisions/20260823-immediate-controller-relay.md +53 -0
  42. package/docs/architecture/decisions/20260826-browser-runtime-v2.md +73 -0
  43. package/docs/architecture/history/README.md +7 -0
  44. package/docs/architecture/{chatgpt-handoff-facade.md → history/chatgpt-handoff-facade.md} +4 -0
  45. package/docs/architecture/{global-hook-runtime.md → history/global-hook-runtime.md} +7 -3
  46. package/docs/architecture/{ios-semantic-automation-provider-v2.md → history/ios-semantic-automation-provider-v2.md} +6 -2
  47. package/docs/architecture/history.md +3 -34
  48. package/docs/architecture/index.md +15 -98
  49. package/docs/architecture/modules/controller-runtime/transport-lifecycle.md +1 -1
  50. package/docs/architecture/reviews/2026-08-22-semantic-harness-convergence-acceptance.md +39 -0
  51. package/docs/architecture/versions/1.6.md +38 -0
  52. package/docs/architecture/versions/1.7.md +41 -0
  53. package/docs/forge-chatgpt-browser-engine.md +2 -2
  54. package/docs/forge-chatgpt-mcp-setup.md +4 -28
  55. package/docs/forge-chatgpt-supervised-automation.md +3 -3
  56. package/docs/forge-github-issue-launcher.md +1 -1
  57. package/docs/forge-runtime-self-healing-loop.md +1 -1
  58. package/docs/operations/controller-browser-plugin.md +26 -6
  59. package/docs/operations/controller-performance-and-502.md +124 -0
  60. package/docs/operations/controller-reliability-runbook.md +1 -1
  61. package/docs/operations/features.md +2 -2
  62. package/docs/operations/github-repository.md +1 -1
  63. package/docs/operations/homebrew.md +2 -2
  64. package/docs/operations/mcp-tool-exposure.md +5 -3
  65. package/docs/wiki/Architecture.md +6 -6
  66. package/docs/wiki/Implementation.md +2 -2
  67. package/docs/wiki/Integrations.md +2 -2
  68. package/docs/wiki/Work-Lifecycle.md +1 -1
  69. package/package.json +29 -10
  70. package/scripts/activate-source-baseline.ts +17 -13
  71. package/scripts/benchmark-background-check-overlap.ts +228 -0
  72. package/scripts/benchmark-mcp-host.sh +117 -0
  73. package/scripts/benchmark-mcp-transport.ts +170 -0
  74. package/scripts/benchmark-quality-harness.ts +146 -0
  75. package/scripts/benchmark-route-session-concurrency.ts +207 -6
  76. package/scripts/benchmark-thin-harness-mcp-e2e.ts +7 -1
  77. package/scripts/benchmark-typescript-navigation.ts +186 -0
  78. package/scripts/benchmark-work-efficiency.ts +334 -0
  79. package/scripts/capture-plan.sh +3 -3
  80. package/scripts/check-agent-tooling.sh +8 -35
  81. package/scripts/check-architecture-sync.sh +17 -86
  82. package/scripts/check-mcp-compatibility.ts +14 -0
  83. package/scripts/check-runtime-architecture.mjs +107 -64
  84. package/scripts/check-stable-baseline.ts +92 -0
  85. package/scripts/check-task-workflow.sh +4 -4
  86. package/scripts/contract-worktree.sh +1 -21
  87. package/scripts/ensure-task-workflow.sh +22 -55
  88. package/scripts/host-temporary-cloud-mcp-e2e.sh +265 -0
  89. package/scripts/install-standalone-recovery.ts +24 -0
  90. package/scripts/lib/project-init-lib.sh +15 -44
  91. package/scripts/migrate-project-template.sh +23 -1179
  92. package/scripts/new-plan.sh +1 -1
  93. package/scripts/plan-to-todo.sh +11 -36
  94. package/scripts/run-governed-gate.ts +2 -1
  95. package/scripts/ship-worktrees.sh +2 -29
  96. package/scripts/smoke-ios-physical-device.ts +4 -2
  97. package/scripts/smoke-runtime-recovery.ts +1 -35
  98. package/scripts/smoke-schedule-engine.ts +1 -20
  99. package/scripts/verify-contract.sh +1 -111
  100. package/scripts/verify-forge-runtime.sh +0 -1
  101. package/scripts/verify-sprint.sh +3 -180
  102. package/scripts/workflow-contract.ts +1 -5
  103. package/src/cli/commands/init-hook.ts +3 -3
  104. package/src/cli/commands/mcp.ts +9 -5
  105. package/src/cli/commands/plugin.ts +1 -1
  106. package/src/cli/commands/recovery.ts +25 -3
  107. package/src/cli/commands/runtime.ts +55 -3
  108. package/src/cli/commands/security.ts +12 -1
  109. package/src/cli/commands/setup-profile.ts +31 -21
  110. package/src/cli/controller/check-runner.ts +106 -3
  111. package/src/cli/controller/composite-result.ts +1 -1
  112. package/src/cli/controller/context/focus.ts +51 -0
  113. package/src/cli/controller/context/instruction-context.ts +114 -0
  114. package/src/cli/controller/context/known-paths.ts +76 -0
  115. package/src/cli/controller/context/query-planning.ts +110 -0
  116. package/src/cli/controller/context/rule-resolution.ts +532 -0
  117. package/src/cli/controller/context/source-materializer.ts +278 -0
  118. package/src/cli/controller/context/structural.ts +16 -0
  119. package/src/cli/controller/context/types.ts +286 -0
  120. package/src/cli/controller/context-pack.ts +785 -469
  121. package/src/cli/controller/launch-agents.ts +77 -2
  122. package/src/cli/controller/operational-plan.ts +2 -2
  123. package/src/cli/controller/work-mode.ts +6 -4
  124. package/src/cli/editing/edit-session.ts +60 -7
  125. package/src/cli/github/github.ts +133 -0
  126. package/src/cli/installer/managed-entries.ts +15 -1
  127. package/src/cli/local-bridge/console-automations.ts +54 -78
  128. package/src/cli/local-bridge/console-view-models.ts +1 -35
  129. package/src/cli/local-bridge/facade-api.ts +0 -217
  130. package/src/cli/local-bridge/frontend/src/App.tsx +3 -3
  131. package/src/cli/local-bridge/frontend/src/features/automations/AutomationsView.tsx +23 -13
  132. package/src/cli/local-bridge/frontend/src/features/capabilities/CapabilitiesView.tsx +37 -4
  133. package/src/cli/local-bridge/frontend/src/features/overview/OverviewView.tsx +6 -4
  134. package/src/cli/local-bridge/frontend/src/lib/api.ts +1 -6
  135. package/src/cli/local-bridge/frontend/src/lib/routes.ts +1 -1
  136. package/src/cli/local-bridge/frontend/src/shell/Sidebar.tsx +2 -2
  137. package/src/cli/local-bridge/frontend/src/styles.css +1 -1
  138. package/src/cli/local-bridge/frontend/src/types.ts +5 -8
  139. package/src/cli/local-bridge/job-store.ts +1 -490
  140. package/src/cli/local-bridge/server.ts +0 -513
  141. package/src/cli/local-bridge/ui-dist/app.css +1 -1
  142. package/src/cli/local-bridge/ui-dist/app.js +3703 -3757
  143. package/src/cli/mcp/auth.ts +5 -5
  144. package/src/cli/mcp/instructions.ts +3 -2
  145. package/src/cli/mcp/legacy-tool-service.ts +0 -189
  146. package/src/cli/mcp/multi-repository.ts +16 -5
  147. package/src/cli/mcp/oauth.ts +175 -26
  148. package/src/cli/mcp/repository-tools.ts +247 -107
  149. package/src/cli/mcp/server.ts +537 -111
  150. package/src/cli/mcp/tool-capability-cache.ts +1 -1
  151. package/src/cli/mcp/toolset-selection.ts +1 -1
  152. package/src/cli/mcp/toolset.ts +42 -5
  153. package/src/cli/mcp/transports/http.ts +101 -14
  154. package/src/cli/mcp/transports/session-registry.ts +43 -5
  155. package/src/cli/mcp/types.ts +3 -3
  156. package/src/cli/repositories/command-classifier.ts +101 -19
  157. package/src/cli/repositories/command-executor.ts +55 -521
  158. package/src/cli/repositories/command-process.ts +108 -0
  159. package/src/cli/repositories/command-scope.ts +99 -41
  160. package/src/cli/repositories/controller-home.ts +7 -8
  161. package/src/cli/repositories/git-command-executor.ts +2 -0
  162. package/src/cli/repositories/locks.ts +53 -16
  163. package/src/cli/repositories/repository-snapshot.ts +121 -0
  164. package/src/cli/repositories/selected-path-actions.ts +17 -9
  165. package/src/cli/repositories/structured-git.ts +61 -3
  166. package/src/cli/repository/inspector.ts +553 -63
  167. package/src/cli/repository/session-cache.ts +58 -17
  168. package/src/cli/v81-entry.ts +1 -4
  169. package/src/effects/fs-transaction.ts +85 -17
  170. package/src/runtime/context/codegraph-read-provider.ts +233 -2
  171. package/src/runtime/context/codegraph-sidecar.cjs +74 -40
  172. package/src/runtime/context/generic-lsp-provider.ts +355 -0
  173. package/src/runtime/context/lsp-client.ts +283 -0
  174. package/src/runtime/context/semantic-navigation.ts +275 -0
  175. package/src/runtime/context/swift-navigation.ts +565 -0
  176. package/src/runtime/context/typescript-navigation.ts +226 -0
  177. package/src/runtime/control-plane/dispatch-priority.ts +28 -0
  178. package/src/runtime/control-plane/execution/direct-edit-work-completion.ts +47 -8
  179. package/src/runtime/control-plane/execution/edit-validation-coordinator.ts +86 -24
  180. package/src/runtime/control-plane/execution/session-store.ts +18 -0
  181. package/src/runtime/control-plane/execution/verification-evidence.ts +58 -3
  182. package/src/runtime/control-plane/execution/work-handle-store.ts +27 -2
  183. package/src/runtime/control-plane/execution/work-lifecycle-audit.ts +258 -0
  184. package/src/runtime/control-plane/execution/work-remote-delivery.ts +215 -0
  185. package/src/runtime/control-plane/execution/work-task-receipt.ts +54 -11
  186. package/src/runtime/control-plane/execution/work-terminal-cleanup.ts +143 -8
  187. package/src/runtime/control-plane/execution/work-validation-reconciler.ts +22 -14
  188. package/src/runtime/control-plane/execution/work-verification-snapshot.ts +85 -8
  189. package/src/runtime/control-plane/facade/capability-registry.ts +129 -25
  190. package/src/runtime/control-plane/facade/controller-round-relay.ts +991 -0
  191. package/src/runtime/control-plane/facade/controller-session-store.ts +132 -1
  192. package/src/runtime/control-plane/facade/goal-workloop-access.ts +2 -0
  193. package/src/runtime/control-plane/facade/goal-workloop.ts +686 -129
  194. package/src/runtime/control-plane/facade/index.ts +1 -0
  195. package/src/runtime/control-plane/facade/plan-contract-store.ts +185 -20
  196. package/src/runtime/control-plane/facade/semantic-admission.ts +205 -0
  197. package/src/runtime/control-plane/facade/suggested-actions.ts +5 -1
  198. package/src/runtime/control-plane/facade/types.ts +22 -5
  199. package/src/runtime/control-plane/facade/work-contract-store.ts +175 -73
  200. package/src/runtime/control-plane/generated-cache-retention.ts +271 -0
  201. package/src/runtime/control-plane/global-scheduler/config.ts +44 -0
  202. package/src/runtime/control-plane/global-scheduler/dispatch-capacity.ts +80 -0
  203. package/src/runtime/control-plane/global-scheduler/durable-admission.ts +46 -0
  204. package/src/runtime/control-plane/global-scheduler/maintenance.ts +145 -0
  205. package/src/runtime/control-plane/global-scheduler/projection-refresh.ts +84 -0
  206. package/src/runtime/control-plane/global-scheduler/reconciliation.ts +3 -3
  207. package/src/runtime/control-plane/global-scheduler/scheduler.ts +273 -542
  208. package/src/runtime/control-plane/global-scheduler/source-scan.ts +59 -0
  209. package/src/runtime/control-plane/global-scheduler/state.ts +88 -0
  210. package/src/runtime/control-plane/global-scheduler/worker-attachment.ts +57 -0
  211. package/src/runtime/control-plane/global-scheduler/worker-exit-decision.ts +38 -0
  212. package/src/runtime/control-plane/global-scheduler/worker-exit-reconciler.ts +175 -0
  213. package/src/runtime/control-plane/global-scheduler/worker-launch.ts +111 -0
  214. package/src/runtime/control-plane/global-scheduler/worker-lifecycle-store.ts +64 -0
  215. package/src/runtime/control-plane/global-scheduler/worker-lifecycle.ts +150 -0
  216. package/src/runtime/control-plane/global-scheduler/worker-process.ts +119 -0
  217. package/src/runtime/control-plane/global-scheduler/worker-stderr.ts +60 -0
  218. package/src/runtime/control-plane/launcher/chatgpt-work-binding-store.ts +50 -0
  219. package/src/runtime/control-plane/launcher/chatgpt-work-continuation.ts +355 -116
  220. package/src/runtime/control-plane/launcher/launch-reservation-store.ts +40 -0
  221. package/src/runtime/control-plane/launcher/thin-launcher.ts +194 -10
  222. package/src/runtime/control-plane/persistence/controller-home-migration.ts +487 -0
  223. package/src/runtime/control-plane/persistence/sqlite-store.ts +33 -2
  224. package/src/runtime/control-plane/release-retention.ts +62 -2
  225. package/src/runtime/control-plane/routing/route-policy.ts +7 -16
  226. package/src/runtime/control-plane/runtime-status-client.ts +0 -2
  227. package/src/runtime/diagnostics/mcp-timing.ts +13 -0
  228. package/src/runtime/diagnostics/mcp-transport-benchmark.ts +129 -0
  229. package/src/runtime/diagnostics/performance.ts +24 -1
  230. package/src/runtime/evidence/event-ledger.ts +1 -1
  231. package/src/runtime/execution/jobs/store.ts +58 -4
  232. package/src/runtime/execution/jobs/types.ts +1 -1
  233. package/src/runtime/execution/managed-workspace.ts +203 -1
  234. package/src/runtime/execution/process-runtime/check-facade.ts +51 -4
  235. package/src/runtime/execution/process-runtime/check-result.ts +53 -0
  236. package/src/runtime/execution/process-runtime/check-scheduling.ts +114 -0
  237. package/src/runtime/execution/process-runtime/command-facade.ts +345 -40
  238. package/src/runtime/execution/process-runtime/gc.ts +38 -6
  239. package/src/runtime/execution/process-runtime/lightweight-managed.ts +1184 -0
  240. package/src/runtime/execution/process-runtime/persisted-check.ts +47 -4
  241. package/src/runtime/execution/process-runtime/resource-claims.ts +10 -6
  242. package/src/runtime/execution/process-runtime/runtime.ts +43 -3
  243. package/src/runtime/execution/process-runtime/store.ts +1 -0
  244. package/src/runtime/execution/process-runtime/types.ts +2 -0
  245. package/src/runtime/execution/thin-harness/async-process.ts +12 -2
  246. package/src/runtime/execution/thin-harness/search-worker.ts +54 -5
  247. package/src/runtime/execution/workers/executor.ts +0 -48
  248. package/src/runtime/gateway/mcp/execution-tools.ts +1192 -114
  249. package/src/runtime/gateway/mcp/process-tools.ts +83 -37
  250. package/src/runtime/gateway/mcp/router.ts +184 -82
  251. package/src/runtime/gateway/mcp/runtime-tool-definitions.ts +546 -0
  252. package/src/runtime/gateway/mcp/runtime-tools.ts +2224 -1589
  253. package/src/runtime/plugins/app-store-connect-adapter.ts +123 -19
  254. package/src/runtime/plugins/browser-adapter.ts +2901 -241
  255. package/src/runtime/plugins/browser-automation-service.ts +10 -0
  256. package/src/runtime/plugins/browser-handoff.ts +92 -2
  257. package/src/runtime/plugins/browser-macos-bridge.ts +582 -49
  258. package/src/runtime/plugins/browser-node-bridge.ts +6 -34
  259. package/src/runtime/plugins/browser-provider-registry.ts +109 -0
  260. package/src/runtime/plugins/browser-runtime-contract.ts +152 -0
  261. package/src/runtime/plugins/browser-runtime.ts +183 -0
  262. package/src/runtime/plugins/browser-session-authority.ts +332 -0
  263. package/src/runtime/plugins/capability-authorization-grants.ts +354 -0
  264. package/src/runtime/plugins/desktop-operator-registration.ts +8 -2
  265. package/src/runtime/plugins/external-adapter.ts +324 -3
  266. package/src/runtime/plugins/external-unix-socket.ts +7 -1
  267. package/src/runtime/plugins/first-party-registry.ts +2 -0
  268. package/src/runtime/plugins/github-adapter.ts +125 -0
  269. package/src/runtime/plugins/ios/agent-device-provider.ts +1 -1
  270. package/src/runtime/plugins/ios/agent-device-typed-provider.ts +52 -9
  271. package/src/runtime/plugins/ios/remote-xpc-hid.ts +1171 -0
  272. package/src/runtime/plugins/ios-adapter.ts +106 -16
  273. package/src/runtime/plugins/ios-agent-device.ts +234 -64
  274. package/src/runtime/plugins/ios-physical-device.ts +1143 -392
  275. package/src/runtime/plugins/lightweight-action.ts +153 -0
  276. package/src/runtime/plugins/local-system-adapter.ts +123 -6
  277. package/src/runtime/plugins/macos-capability-broker.ts +55 -9
  278. package/src/runtime/plugins/plugin-action-sidecar.ts +59 -0
  279. package/src/runtime/plugins/plugin-management-adapter.ts +49 -8
  280. package/src/runtime/plugins/resend-adapter.ts +1 -1
  281. package/src/runtime/plugins/store.ts +269 -29
  282. package/src/runtime/plugins/types.ts +35 -2
  283. package/src/runtime/plugins/xiaohongshu-publish.ts +515 -0
  284. package/src/runtime/projections/git-status-sampler.ts +16 -16
  285. package/src/runtime/projections/materialized-view.ts +28 -10
  286. package/src/runtime/recovery/maintenance-executor.ts +393 -28
  287. package/src/runtime/root/mcp-transport.ts +180 -10
  288. package/src/runtime/root/package-connector-service.ts +186 -8
  289. package/src/runtime/root/package-runtime-release.ts +143 -17
  290. package/src/runtime/root/package-runtime-service.ts +430 -22
  291. package/src/runtime/root/release-manifest.ts +7 -2
  292. package/src/runtime/root/release-materialize.ts +19 -0
  293. package/src/runtime/root/release-store.ts +48 -11
  294. package/src/runtime/root/runtime.ts +23 -5
  295. package/src/runtime/root/service.ts +100 -29
  296. package/src/runtime/root/types.ts +2 -0
  297. package/src/runtime/safe-tooling/ios-development.ts +321 -63
  298. package/src/runtime/shared/trusted-executable.ts +62 -0
  299. package/src/runtime/shared/trusted-node-executable.ts +48 -0
  300. package/src/runtime/standalone-recovery/core.ts +700 -92
  301. package/src/runtime/standalone-recovery/entry.ts +99 -23
  302. package/src/runtime/standalone-recovery/installer.ts +19 -3
  303. package/src/runtime/standalone-recovery/service-labels.ts +2 -0
  304. package/src/runtime/standalone-recovery/watchdog-heartbeat.ts +160 -0
  305. package/src/runtime/workflow/schedules/browser-probe.ts +81 -3
  306. package/src/runtime/workflow/schedules/engine.ts +287 -151
  307. package/src/runtime/workflow/schedules/github-issue-watch.ts +158 -0
  308. package/src/runtime/workflow/schedules/settlement.ts +48 -4
  309. package/src/runtime/workflow/schedules/store.ts +131 -10
  310. package/src/runtime/workflow/schedules/types.ts +2 -4
  311. package/src/runtime/workflow/schedules/work-continuation.ts +26 -13
  312. package/src/testing/test-governance.ts +8 -40
  313. package/assets/reference-configs/heartbeat-triage.md +0 -57
  314. package/assets/templates/helpers/harness-trace-grade.sh +0 -150
  315. package/assets/templates/helpers/heartbeat-triage.sh +0 -361
  316. package/assets/templates/helpers/maintenance-triage.sh +0 -167
  317. package/docs/architecture/current/approved-target-architecture.zh-CN.md +0 -1501
  318. package/docs/architecture/current/architecture-invariants.md +0 -331
  319. package/docs/architecture/current/automation-and-schedule-engine.md +0 -459
  320. package/docs/architecture/current/codegraph-context-provider.md +0 -238
  321. package/docs/architecture/current/control-plane-authority-inventory.md +0 -94
  322. package/docs/architecture/current/controller-repository-decoupling.md +0 -148
  323. package/docs/architecture/current/dispatch-and-agent-strategy.md +0 -373
  324. package/docs/architecture/current/entity-model.md +0 -612
  325. package/docs/architecture/current/external-plugin-governance.md +0 -396
  326. package/docs/architecture/current/failure-recovery.md +0 -447
  327. package/docs/architecture/current/governance.md +0 -213
  328. package/docs/architecture/current/human-interaction-plane.md +0 -87
  329. package/docs/architecture/current/implementation-status.md +0 -128
  330. package/docs/architecture/current/job-and-run-lifecycle.md +0 -413
  331. package/docs/architecture/current/legacy-governance.md +0 -58
  332. package/docs/architecture/current/local-workspace-target-grants.md +0 -70
  333. package/docs/architecture/current/migration-roadmap.md +0 -105
  334. package/docs/architecture/current/multi-repository-execution.md +0 -371
  335. package/docs/architecture/current/operations-runbook.md +0 -45
  336. package/docs/architecture/current/peer-supercontroller-runtime.md +0 -32
  337. package/docs/architecture/current/personal-assistant-plugin-baseline.md +0 -206
  338. package/docs/architecture/current/repository-access-modes.md +0 -102
  339. package/docs/architecture/current/route-policy.md +0 -15
  340. package/docs/architecture/current/route-session-concurrency.md +0 -85
  341. package/docs/architecture/current/runtime-architecture-simplification.md +0 -214
  342. package/docs/architecture/current/runtime-directory-map.md +0 -49
  343. package/docs/architecture/current/runtime-health-and-resource-lifecycle.md +0 -85
  344. package/docs/architecture/current/scheduler-and-resource-claims.md +0 -422
  345. package/docs/architecture/current/session-aware-execution-and-authorization.md +0 -77
  346. package/docs/architecture/current/system-overview.md +0 -169
  347. package/docs/architecture/current/target-requirements-traceability.md +0 -202
  348. package/docs/architecture/current/thin-harness-governance-policy.md +0 -32
  349. package/docs/architecture/current/thin-harness-v1.md +0 -321
  350. package/docs/architecture/current/verification-and-release-gates.md +0 -391
  351. package/docs/forge-autonomous-goal-loop.md +0 -9
  352. package/docs/forge-provider-configuration.md +0 -7
  353. package/docs/operations/chatgpt-personal-assistant-runtime.md +0 -93
  354. package/docs/operations/gmail-assistant-routines.md +0 -186
  355. package/docs/operations/personal-assistant-operator-guide.md +0 -61
  356. package/docs/operations/provider-configuration.md +0 -31
  357. package/scripts/harness-trace-grade.sh +0 -150
  358. package/scripts/heartbeat-triage.sh +0 -361
  359. package/scripts/maintenance-triage.sh +0 -167
  360. package/src/cli/local-bridge/frontend/src/features/settings/SettingsView.tsx +0 -2
  361. package/src/cli/repositories/goal-registry.ts +0 -239
  362. package/src/runtime/assistant/action-proposals.ts +0 -279
  363. package/src/runtime/assistant/intent.ts +0 -395
  364. package/src/runtime/assistant/model-provider.ts +0 -460
  365. package/src/runtime/assistant/openapi.ts +0 -223
  366. package/src/runtime/assistant/policy.ts +0 -89
  367. package/src/runtime/assistant/readiness.ts +0 -258
  368. package/src/runtime/assistant/routine-runtime.ts +0 -477
  369. package/src/runtime/assistant/schedule-binding.ts +0 -171
  370. package/src/runtime/assistant/standing-grants.ts +0 -375
  371. package/src/runtime/assistant/store.ts +0 -243
  372. package/src/runtime/assistant/types.ts +0 -135
  373. package/src/runtime/control-plane/goal-loop/config-facade.ts +0 -700
  374. package/src/runtime/control-plane/goal-loop/config-store.ts +0 -570
  375. package/src/runtime/control-plane/goal-loop/config-types.ts +0 -213
  376. package/src/runtime/control-plane/goal-loop/executor-router.ts +0 -109
  377. package/src/runtime/control-plane/goal-loop/failure-taxonomy.ts +0 -149
  378. package/src/runtime/control-plane/goal-loop/goal-contract-store.ts +0 -304
  379. package/src/runtime/control-plane/goal-loop/goal-loop-engine.ts +0 -1001
  380. package/src/runtime/control-plane/goal-loop/handoff-packet.ts +0 -160
  381. package/src/runtime/control-plane/goal-loop/index.ts +0 -13
  382. package/src/runtime/control-plane/goal-loop/local-tools.ts +0 -290
  383. package/src/runtime/control-plane/goal-loop/policy-gates.ts +0 -203
  384. package/src/runtime/control-plane/goal-loop/provider-dispatch.ts +0 -93
  385. package/src/runtime/control-plane/goal-loop/provider-registry.ts +0 -545
  386. package/src/runtime/control-plane/goal-loop/types.ts +0 -378
  387. package/src/runtime/control-plane/startup-recovery.ts +0 -198
  388. package/src/runtime/gateway/mcp/resource-policy.ts +0 -186
  389. package/src/runtime/personal-assistant/gmail-triage-manager.ts +0 -231
  390. package/src/runtime/personal-assistant/reporting-runtime.ts +0 -344
  391. package/src/runtime/personal-assistant/triage-runtime.ts +0 -748
  392. package/src/runtime/workflow/findings/store.ts +0 -204
  393. package/src/runtime/workflow/findings/types.ts +0 -58
  394. package/src/runtime/workflow/portfolio/engine.ts +0 -20
  395. package/src/runtime/workflow/portfolio/store.ts +0 -185
  396. 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';
@@ -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. */
@@ -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.
@@ -1216,7 +1298,7 @@ export async function startMcpHttp(opts: McpHttpOptions): Promise<void> {
1216
1298
  // Primary MCP path: OAuth (or bearer when --auth bearer). Unchanged for ChatGPT.
1217
1299
  app.use('/mcp', setMcpResponseHeaders);
1218
1300
  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) => {
1301
+ handleMcpPost(req, res, baseOptions, sessionRegistry, runtimeStats, '/mcp', currentRuntimeToolSurfaceFingerprint, resolveRuntimeSchema, sharedRuntimeProxy).catch((error: unknown) => {
1220
1302
  if (!res.headersSent) sendMcpRequestError(res, error);
1221
1303
  });
1222
1304
  });
@@ -1234,7 +1316,7 @@ export async function startMcpHttp(opts: McpHttpOptions): Promise<void> {
1234
1316
  // Legacy Grok OAuth resource. New Grok connectors should use canonical /mcp.
1235
1317
  app.use('/mcp-grok', setMcpResponseHeaders);
1236
1318
  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) => {
1319
+ handleMcpPost(req, res, baseOptions, sessionRegistry, runtimeStats, '/mcp-grok', currentRuntimeToolSurfaceFingerprint, resolveRuntimeSchema, sharedRuntimeProxy).catch((error: unknown) => {
1238
1320
  if (!res.headersSent) sendMcpRequestError(res, error);
1239
1321
  });
1240
1322
  });
@@ -1252,7 +1334,7 @@ export async function startMcpHttp(opts: McpHttpOptions): Promise<void> {
1252
1334
  // Bearer-only MCP path for clients that can send Authorization headers. Never advertises OAuth resource_metadata.
1253
1335
  app.use('/mcp-bearer', setMcpResponseHeaders);
1254
1336
  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) => {
1337
+ handleMcpPost(req, res, baseOptions, sessionRegistry, runtimeStats, '/mcp-bearer', currentRuntimeToolSurfaceFingerprint, resolveRuntimeSchema, sharedRuntimeProxy).catch((error: unknown) => {
1256
1338
  if (!res.headersSent) sendMcpRequestError(res, error);
1257
1339
  });
1258
1340
  });
@@ -1284,12 +1366,17 @@ export async function startMcpHttp(opts: McpHttpOptions): Promise<void> {
1284
1366
  if (toolSurfaceNotificationTimer) clearTimeout(toolSurfaceNotificationTimer);
1285
1367
  runtimeStatusWatcher?.close();
1286
1368
  void sessionRegistry.closeAll('shutdown');
1369
+ void sharedRuntimeProxy?.close();
1287
1370
  });
1288
1371
 
1289
1372
  await new Promise<void>((resolve) => {
1290
1373
  httpServer.once('listening', resolve);
1291
1374
  });
1292
- const authLabel = authMode === 'oauth' ? (oauthPassphrase ? 'oauth' : 'oauth-missing') : (authToken ? 'bearer' : 'missing');
1375
+ const authLabel = authMode === 'oauth'
1376
+ ? (oauthPassphrase ? 'oauth' : 'oauth-missing')
1377
+ : authMode === 'bearer'
1378
+ ? (authToken ? 'bearer' : 'missing')
1379
+ : 'none';
1293
1380
  console.error(
1294
1381
  `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
1382
  );
@@ -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;