@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.
- package/AGENTS.md +4 -0
- package/CHANGELOG.md +39 -0
- package/CLAUDE.md +4 -0
- package/README.md +2 -2
- package/README.zh-CN.md +1 -1
- package/SKILL.md +2 -2
- package/THIRD_PARTY_NOTICES.md +1 -1
- package/agents/openai.yaml +1 -1
- package/assets/hooks/hook-input.sh +11 -8
- package/assets/hooks/lib/session-state.sh +10 -7
- package/assets/hooks/lib/workflow-state.sh +13 -177
- package/assets/hooks/post-tool-observer.sh +8 -2
- package/assets/hooks/prompt-guard.sh +5 -81
- package/assets/hooks/session-start-context.sh +56 -1
- package/assets/partials/05-workflow.partial.md +1 -1
- package/assets/partials-agents/02-operating-mode.partial.md +2 -0
- package/assets/partials-agents/03-orchestration.partial.md +1 -1
- package/assets/plugin-registry.v1.json +3 -3
- package/assets/reference-configs/document-generation.md +1 -1
- package/assets/reference-configs/harness-overview.md +1 -1
- package/assets/reference-configs/sprint-contracts.md +3 -3
- package/assets/skill-version.json +2 -2
- package/assets/templates/contract.template.md +2 -7
- package/assets/templates/helpers/capture-plan.sh +2 -2
- package/assets/templates/helpers/check-architecture-sync.sh +17 -0
- package/assets/templates/helpers/check-task-workflow.sh +4 -4
- package/assets/templates/helpers/contract-worktree.sh +1 -21
- package/assets/templates/helpers/ensure-task-workflow.sh +11 -36
- package/assets/templates/helpers/inspect-project-state.ts +8 -6
- package/assets/templates/helpers/migrate-project-template.sh +22 -45
- package/assets/templates/helpers/migrate-workflow-docs.ts +9 -7
- package/assets/templates/helpers/new-plan.sh +1 -1
- package/assets/templates/helpers/plan-to-todo.sh +12 -37
- package/assets/templates/helpers/ship-worktrees.sh +2 -29
- package/assets/templates/helpers/verify-contract.sh +1 -111
- package/assets/templates/helpers/verify-sprint.sh +3 -180
- package/assets/templates/helpers/workflow-contract.ts +5 -1
- package/assets/templates/plan.template.md +1 -1
- package/assets/templates/review.template.md +9 -34
- package/assets/workflow-contract.v1.json +10 -19
- package/docs/README.md +10 -10
- package/docs/architecture/CURRENT.md +178 -0
- package/docs/architecture/EVOLUTION.md +42 -0
- package/docs/architecture/current/README.md +4 -156
- package/docs/architecture/decisions/20260803-release-identity-binding-and-exit-policy.md +2 -2
- package/docs/architecture/decisions/20260823-immediate-controller-relay.md +53 -0
- package/docs/architecture/decisions/20260826-browser-runtime-v2.md +73 -0
- package/docs/architecture/history/README.md +7 -0
- package/docs/architecture/{chatgpt-handoff-facade.md → history/chatgpt-handoff-facade.md} +4 -0
- package/docs/architecture/{global-hook-runtime.md → history/global-hook-runtime.md} +7 -3
- package/docs/architecture/{ios-semantic-automation-provider-v2.md → history/ios-semantic-automation-provider-v2.md} +6 -2
- package/docs/architecture/history.md +3 -34
- package/docs/architecture/index.md +15 -98
- package/docs/architecture/modules/controller-runtime/transport-lifecycle.md +1 -1
- package/docs/architecture/reviews/2026-08-22-semantic-harness-convergence-acceptance.md +39 -0
- package/docs/architecture/versions/1.6.md +38 -0
- package/docs/architecture/versions/1.7.md +41 -0
- package/docs/forge-chatgpt-browser-engine.md +2 -2
- package/docs/forge-chatgpt-mcp-setup.md +4 -28
- package/docs/forge-chatgpt-supervised-automation.md +3 -3
- package/docs/forge-github-issue-launcher.md +1 -1
- package/docs/forge-plugin-management.md +1 -1
- package/docs/forge-runtime-self-healing-loop.md +1 -1
- package/docs/operations/controller-browser-plugin.md +26 -6
- package/docs/operations/controller-performance-and-502.md +143 -0
- package/docs/operations/controller-reliability-runbook.md +1 -1
- package/docs/operations/features.md +2 -2
- package/docs/operations/github-repository.md +1 -1
- package/docs/operations/homebrew.md +2 -2
- package/docs/operations/mcp-tool-exposure.md +5 -3
- package/docs/wiki/Architecture.md +6 -6
- package/docs/wiki/Implementation.md +2 -2
- package/docs/wiki/Integrations.md +2 -2
- package/docs/wiki/Work-Lifecycle.md +1 -1
- package/package.json +33 -11
- package/scripts/activate-source-baseline.ts +17 -13
- package/scripts/architecture-event.ts +2 -820
- package/scripts/architecture-queue.sh +2 -645
- package/scripts/archive-architecture-request.sh +2 -242
- package/scripts/archive-workflow.sh +1 -291
- package/scripts/benchmark-background-check-overlap.ts +228 -0
- package/scripts/benchmark-mcp-host.sh +117 -0
- package/scripts/benchmark-mcp-transport.ts +170 -0
- package/scripts/benchmark-quality-harness.ts +146 -0
- package/scripts/benchmark-route-session-concurrency.ts +207 -6
- package/scripts/benchmark-thin-harness-mcp-e2e.ts +7 -1
- package/scripts/benchmark-typescript-navigation.ts +186 -0
- package/scripts/benchmark-work-efficiency.ts +334 -0
- package/scripts/capability-config.ts +2 -392
- package/scripts/capability-resolver.ts +2 -503
- package/scripts/capture-plan.sh +1 -332
- package/scripts/check-agent-tooling.sh +2 -1558
- package/scripts/check-architecture-sync.sh +2 -371
- package/scripts/check-brain-manifest.sh +2 -253
- package/scripts/check-context-files.sh +2 -47
- package/scripts/check-deploy-sql-order.sh +2 -115
- package/scripts/check-mcp-compatibility.ts +14 -0
- package/scripts/check-runtime-architecture.mjs +349 -79
- package/scripts/check-skill-version.ts +3 -191
- package/scripts/check-source-duplication.mjs +61 -0
- package/scripts/check-stable-baseline.ts +92 -0
- package/scripts/check-task-sync.sh +2 -63
- package/scripts/check-task-workflow.sh +2 -1000
- package/scripts/codex-handoff-resume.sh +2 -267
- package/scripts/context-contract-sync.sh +2 -514
- package/scripts/contract-run.ts +2 -463
- package/scripts/contract-worktree.sh +1 -722
- package/scripts/ensure-task-workflow.sh +1 -1225
- package/scripts/host-temporary-cloud-mcp-e2e.sh +265 -0
- package/scripts/inspect-project-state.ts +4 -279
- package/scripts/install-standalone-recovery.ts +24 -0
- package/scripts/lib/project-init-lib.sh +22 -46
- package/scripts/lib/run-forge-helper.sh +19 -0
- package/scripts/lib/run-forge-helper.ts +26 -0
- package/scripts/migrate-project-template.sh +1 -1189
- package/scripts/migrate-workflow-docs.ts +4 -412
- package/scripts/new-plan.sh +1 -180
- package/scripts/new-spec.sh +1 -47
- package/scripts/new-sprint.sh +1 -46
- package/scripts/plan-to-todo.sh +1 -796
- package/scripts/prepare-codex-handoff.sh +2 -201
- package/scripts/prepare-handoff.sh +1 -78
- package/scripts/refresh-current-status.sh +2 -467
- package/scripts/run-governed-gate.ts +5 -1
- package/scripts/select-agent-context-blocks.sh +2 -64
- package/scripts/ship-worktrees.sh +1 -558
- package/scripts/smoke-ios-physical-device.ts +4 -2
- package/scripts/smoke-runtime-recovery.ts +1 -35
- package/scripts/smoke-schedule-engine.ts +1 -20
- package/scripts/sprint-backlog.sh +1 -834
- package/scripts/stage-runtime-release.ts +2 -1
- package/scripts/summarize-failures.sh +2 -123
- package/scripts/switch-plan.sh +1 -150
- package/scripts/sync-brain-docs.sh +2 -379
- package/scripts/sync-generated-authority.mjs +175 -0
- package/scripts/verify-contract.sh +2 -703
- package/scripts/verify-forge-runtime.sh +0 -1
- package/scripts/verify-sprint.sh +1 -677
- package/scripts/workflow-contract.ts +4 -205
- package/scripts/workstream-sync.sh +2 -261
- package/src/cli/agent-jobs/executor-health.ts +1 -1
- package/src/cli/commands/init-hook.ts +3 -3
- package/src/cli/commands/mcp.ts +9 -5
- package/src/cli/commands/plugin.ts +12 -3
- package/src/cli/commands/recovery.ts +25 -3
- package/src/cli/commands/runtime.ts +55 -3
- package/src/cli/commands/security.ts +12 -1
- package/src/cli/commands/setup-profile.ts +31 -21
- package/src/cli/controller/check-runner.ts +113 -5
- package/src/cli/controller/composite-result.ts +1 -1
- package/src/cli/controller/context/focus.ts +51 -0
- package/src/cli/controller/context/instruction-context.ts +114 -0
- package/src/cli/controller/context/known-paths.ts +76 -0
- package/src/cli/controller/context/query-planning.ts +110 -0
- package/src/cli/controller/context/rule-resolution.ts +532 -0
- package/src/cli/controller/context/source-materializer.ts +278 -0
- package/src/cli/controller/context/structural.ts +16 -0
- package/src/cli/controller/context/types.ts +286 -0
- package/src/cli/controller/context-pack.ts +828 -487
- package/src/cli/controller/launch-agents.ts +77 -2
- package/src/cli/controller/operational-plan.ts +2 -2
- package/src/cli/controller/work-mode.ts +6 -4
- package/src/cli/editing/edit-session.ts +60 -7
- package/src/cli/github/contracts.ts +16 -0
- package/src/cli/github/github.ts +135 -16
- package/src/cli/github/session.ts +2 -1
- package/src/cli/installer/managed-entries.ts +15 -1
- package/src/cli/local-bridge/console-automations.ts +54 -78
- package/src/cli/local-bridge/console-view-models.ts +1 -35
- package/src/cli/local-bridge/facade-api.ts +37 -264
- package/src/cli/local-bridge/frontend/src/App.tsx +3 -3
- package/src/cli/local-bridge/frontend/src/features/automations/AutomationsView.tsx +23 -13
- package/src/cli/local-bridge/frontend/src/features/capabilities/CapabilitiesView.tsx +37 -4
- package/src/cli/local-bridge/frontend/src/features/overview/OverviewView.tsx +6 -4
- package/src/cli/local-bridge/frontend/src/lib/api.ts +1 -6
- package/src/cli/local-bridge/frontend/src/lib/routes.ts +1 -1
- package/src/cli/local-bridge/frontend/src/shell/Sidebar.tsx +2 -2
- package/src/cli/local-bridge/frontend/src/styles.css +1 -1
- package/src/cli/local-bridge/frontend/src/types.ts +5 -8
- package/src/cli/local-bridge/job-store.ts +1 -490
- package/src/cli/local-bridge/server.ts +2 -515
- package/src/cli/local-bridge/ui-dist/app.css +1 -1
- package/src/cli/local-bridge/ui-dist/app.js +3703 -3757
- package/src/cli/mcp/auth.ts +5 -5
- package/src/cli/mcp/instructions.ts +3 -2
- package/src/cli/mcp/legacy-tool-service.ts +10 -222
- package/src/cli/mcp/multi-repository.ts +16 -5
- package/src/cli/mcp/oauth.ts +175 -26
- package/src/cli/mcp/post-finalize-work-attribution.ts +150 -0
- package/src/cli/mcp/repository-tools.ts +282 -146
- package/src/cli/mcp/server.ts +586 -116
- package/src/cli/mcp/tool-capability-cache.ts +1 -1
- package/src/cli/mcp/tool-contract.ts +14 -0
- package/src/cli/mcp/toolset-selection.ts +1 -1
- package/src/cli/mcp/toolset.ts +44 -7
- package/src/cli/mcp/transports/http.ts +124 -14
- package/src/cli/mcp/transports/session-registry.ts +43 -5
- package/src/cli/mcp/types.ts +3 -3
- package/src/cli/repositories/command-classifier.ts +103 -21
- package/src/cli/repositories/command-executor.ts +78 -526
- package/src/cli/repositories/command-process.ts +108 -0
- package/src/cli/repositories/command-scope.ts +99 -41
- package/src/cli/repositories/controller-home.ts +7 -8
- package/src/cli/repositories/git-command-executor.ts +2 -0
- package/src/cli/repositories/locks.ts +53 -16
- package/src/cli/repositories/repository-snapshot.ts +124 -0
- package/src/cli/repositories/selected-path-actions.ts +17 -9
- package/src/cli/repositories/structured-git.ts +118 -6
- package/src/cli/repository/inspector.ts +563 -65
- package/src/cli/repository/session-cache.ts +58 -17
- package/src/cli/v81-entry.ts +1 -4
- package/src/effects/fs-transaction.ts +85 -17
- package/src/runtime/context/codegraph-read-provider.ts +233 -2
- package/src/runtime/context/codegraph-sidecar.cjs +74 -40
- package/src/runtime/context/generic-lsp-provider.ts +355 -0
- package/src/runtime/context/lsp-client.ts +283 -0
- package/src/runtime/context/semantic-navigation-contract.ts +61 -0
- package/src/runtime/context/semantic-navigation.ts +223 -0
- package/src/runtime/context/swift-navigation.ts +565 -0
- package/src/runtime/context/typescript-navigation.ts +226 -0
- package/src/runtime/control-plane/dispatch-priority.ts +28 -0
- package/src/runtime/control-plane/execution/direct-edit-work-completion.ts +48 -16
- package/src/runtime/control-plane/execution/edit-validation-coordinator.ts +86 -24
- package/src/runtime/control-plane/execution/repository-work-attribution.ts +106 -0
- package/src/runtime/control-plane/execution/retained-work-resume.ts +203 -0
- package/src/runtime/control-plane/execution/session-store.ts +18 -0
- package/src/runtime/control-plane/execution/verification-evidence.ts +58 -3
- package/src/runtime/control-plane/execution/work-completion-authority.ts +58 -0
- package/src/runtime/control-plane/execution/work-evidence-policy.ts +200 -0
- package/src/runtime/control-plane/execution/work-execution-support.ts +386 -0
- package/src/runtime/control-plane/execution/work-finalization-service.ts +1913 -0
- package/src/runtime/control-plane/execution/work-handle-authority.ts +96 -0
- package/src/runtime/control-plane/execution/work-handle-store.ts +27 -2
- package/src/runtime/control-plane/execution/work-lifecycle-audit.ts +258 -0
- package/src/runtime/control-plane/execution/work-operation-service.ts +468 -0
- package/src/runtime/control-plane/execution/work-path-scope.ts +37 -0
- package/src/runtime/control-plane/execution/work-preparation-service.ts +479 -0
- package/src/runtime/control-plane/execution/work-process-evidence.ts +129 -0
- package/src/runtime/control-plane/execution/work-remote-delivery.ts +215 -0
- package/src/runtime/control-plane/execution/work-task-receipt.ts +22 -18
- package/src/runtime/control-plane/execution/work-terminal-cleanup.ts +156 -11
- package/src/runtime/control-plane/execution/work-validation-reconciler.ts +22 -14
- package/src/runtime/control-plane/execution/work-verification-context.ts +56 -0
- package/src/runtime/control-plane/execution/work-verification-service.ts +388 -0
- package/src/runtime/control-plane/execution/work-verification-snapshot.ts +90 -9
- package/src/runtime/control-plane/facade/capability-registry.ts +129 -25
- package/src/runtime/control-plane/facade/controller-round-relay.ts +1118 -0
- package/src/runtime/control-plane/facade/controller-session-store.ts +302 -12
- package/src/runtime/control-plane/facade/goal-workloop-access.ts +17 -1
- package/src/runtime/control-plane/facade/goal-workloop.ts +928 -190
- package/src/runtime/control-plane/facade/index.ts +3 -0
- package/src/runtime/control-plane/facade/plan-contract-store.ts +275 -42
- package/src/runtime/control-plane/facade/repository-work-admission.ts +147 -0
- package/src/runtime/control-plane/facade/requirement-authority.ts +83 -0
- package/src/runtime/control-plane/facade/semantic-admission.ts +205 -0
- package/src/runtime/control-plane/facade/suggested-actions.ts +5 -1
- package/src/runtime/control-plane/facade/types.ts +90 -10
- package/src/runtime/control-plane/facade/work-contract-store.ts +157 -261
- package/src/runtime/control-plane/facade/work-state-machine.ts +250 -0
- package/src/runtime/control-plane/generated-cache-retention.ts +271 -0
- package/src/runtime/control-plane/global-scheduler/config.ts +44 -0
- package/src/runtime/control-plane/global-scheduler/dispatch-capacity.ts +80 -0
- package/src/runtime/control-plane/global-scheduler/durable-admission.ts +46 -0
- package/src/runtime/control-plane/global-scheduler/maintenance.ts +152 -0
- package/src/runtime/control-plane/global-scheduler/projection-refresh.ts +84 -0
- package/src/runtime/control-plane/global-scheduler/reconciliation.ts +3 -3
- package/src/runtime/control-plane/global-scheduler/scheduler.ts +278 -543
- package/src/runtime/control-plane/global-scheduler/source-scan.ts +59 -0
- package/src/runtime/control-plane/global-scheduler/state.ts +88 -0
- package/src/runtime/control-plane/global-scheduler/worker-attachment.ts +57 -0
- package/src/runtime/control-plane/global-scheduler/worker-exit-decision.ts +38 -0
- package/src/runtime/control-plane/global-scheduler/worker-exit-reconciler.ts +175 -0
- package/src/runtime/control-plane/global-scheduler/worker-launch.ts +111 -0
- package/src/runtime/control-plane/global-scheduler/worker-lifecycle-store.ts +64 -0
- package/src/runtime/control-plane/global-scheduler/worker-lifecycle.ts +150 -0
- package/src/runtime/control-plane/global-scheduler/worker-process.ts +119 -0
- package/src/runtime/control-plane/global-scheduler/worker-stderr.ts +60 -0
- package/src/runtime/control-plane/launcher/chatgpt-work-binding-store.ts +63 -0
- package/src/runtime/control-plane/launcher/chatgpt-work-continuation.ts +365 -117
- package/src/runtime/control-plane/launcher/launch-reservation-store.ts +89 -0
- package/src/runtime/control-plane/launcher/thin-launcher.ts +244 -11
- package/src/runtime/control-plane/persistence/controller-home-migration.ts +487 -0
- package/src/runtime/control-plane/persistence/requirement-store.ts +0 -12
- package/src/runtime/control-plane/persistence/sqlite-store.ts +33 -2
- package/src/runtime/control-plane/release-retention.ts +62 -2
- package/src/runtime/control-plane/repo-actor/registry.ts +4 -2
- package/src/runtime/control-plane/routing/route-policy.ts +24 -21
- package/src/runtime/control-plane/routing/workspace-admission.ts +70 -0
- package/src/runtime/control-plane/runtime-status-client.ts +0 -2
- package/src/runtime/diagnostics/mcp-timing.ts +13 -0
- package/src/runtime/diagnostics/mcp-transport-benchmark.ts +129 -0
- package/src/runtime/diagnostics/performance.ts +24 -1
- package/src/runtime/evidence/event-ledger.ts +1 -1
- package/src/runtime/evidence/process-check-execution.ts +18 -0
- package/src/runtime/execution/jobs/child-reference.ts +6 -2
- package/src/runtime/execution/jobs/store.ts +58 -4
- package/src/runtime/execution/jobs/types.ts +1 -1
- package/src/runtime/execution/managed-workspace.ts +203 -1
- package/src/runtime/execution/process-runtime/check-facade.ts +51 -4
- package/src/runtime/execution/process-runtime/check-result.ts +88 -0
- package/src/runtime/execution/process-runtime/check-runner-sidecar.ts +7 -1
- package/src/runtime/execution/process-runtime/check-scheduling.ts +114 -0
- package/src/runtime/execution/process-runtime/command-facade.ts +367 -40
- package/src/runtime/execution/process-runtime/gc.ts +38 -6
- package/src/runtime/execution/process-runtime/lightweight-managed.ts +1201 -0
- package/src/runtime/execution/process-runtime/persisted-check.ts +51 -5
- package/src/runtime/execution/process-runtime/resource-claims.ts +10 -6
- package/src/runtime/execution/process-runtime/runtime.ts +53 -3
- package/src/runtime/execution/process-runtime/store.ts +1 -0
- package/src/runtime/execution/process-runtime/types.ts +4 -12
- package/src/runtime/execution/thin-harness/async-process.ts +12 -2
- package/src/runtime/execution/thin-harness/search-worker.ts +54 -5
- package/src/runtime/execution/work-activity.ts +21 -0
- package/src/runtime/execution/workers/executor.ts +18 -61
- package/src/runtime/gateway/mcp/execution-tools.ts +35 -1852
- package/src/runtime/gateway/mcp/legacy-ios-tool-adapter.ts +61 -0
- package/src/runtime/gateway/mcp/process-tools.ts +83 -37
- package/src/runtime/gateway/mcp/router.ts +186 -84
- package/src/runtime/gateway/mcp/runtime-tool-definitions.ts +565 -0
- package/src/runtime/gateway/mcp/runtime-tools.ts +2378 -1947
- package/src/runtime/plugins/app-store-connect-adapter.ts +216 -47
- package/src/runtime/plugins/browser-adapter.ts +2662 -829
- package/src/runtime/plugins/browser-automation-service.ts +10 -0
- package/src/runtime/plugins/browser-handoff-host.ts +2 -25
- package/src/runtime/plugins/browser-handoff.ts +110 -5
- package/src/runtime/plugins/browser-macos-bridge.ts +701 -63
- package/src/runtime/plugins/browser-manifest-surface.ts +603 -0
- package/src/runtime/plugins/browser-native-session-service.ts +222 -0
- package/src/runtime/plugins/browser-node-bridge.ts +6 -34
- package/src/runtime/plugins/browser-provider-registry.ts +109 -0
- package/src/runtime/plugins/browser-runtime-contract.ts +154 -0
- package/src/runtime/plugins/browser-runtime.ts +193 -0
- package/src/runtime/plugins/browser-session-authority.ts +332 -0
- package/src/runtime/plugins/browser-session-store.ts +121 -0
- package/src/runtime/plugins/browser-session-types.ts +98 -0
- package/src/runtime/plugins/capability-authorization-grants.ts +354 -0
- package/src/runtime/plugins/desktop-operator-registration.ts +10 -4
- package/src/runtime/plugins/external-adapter.ts +358 -3
- package/src/runtime/plugins/external-unix-socket.ts +7 -1
- package/src/runtime/plugins/first-party-registry.ts +2 -0
- package/src/runtime/plugins/github-adapter.ts +125 -0
- package/src/runtime/plugins/ios/agent-device-provider.ts +1 -1
- package/src/runtime/plugins/ios/agent-device-typed-provider.ts +52 -9
- package/src/runtime/plugins/ios/remote-xpc-hid.ts +1171 -0
- package/src/runtime/plugins/ios-adapter.ts +106 -16
- package/src/runtime/plugins/ios-agent-device.ts +234 -64
- package/src/runtime/plugins/ios-physical-device.ts +1143 -392
- package/src/runtime/plugins/lightweight-action.ts +153 -0
- package/src/runtime/plugins/local-system-adapter.ts +123 -6
- package/src/runtime/plugins/macos-capability-broker.ts +47 -9
- package/src/runtime/plugins/plugin-action-sidecar.ts +59 -0
- package/src/runtime/plugins/plugin-management-adapter.ts +49 -8
- package/src/runtime/plugins/resend-adapter.ts +1 -1
- package/src/runtime/plugins/store.ts +330 -33
- package/src/runtime/plugins/types.ts +38 -3
- package/src/runtime/plugins/xiaohongshu-publish.ts +515 -0
- package/src/runtime/projections/git-status-sampler.ts +16 -16
- package/src/runtime/projections/materialized-view.ts +28 -10
- package/src/runtime/recovery/maintenance-executor.ts +426 -25
- package/src/runtime/root/mcp-transport.ts +180 -10
- package/src/runtime/root/package-connector-service.ts +230 -10
- package/src/runtime/root/package-runtime-release.ts +143 -17
- package/src/runtime/root/package-runtime-service.ts +461 -22
- package/src/runtime/root/release-manifest.ts +144 -18
- package/src/runtime/root/release-materialize.ts +125 -32
- package/src/runtime/root/release-store.ts +48 -11
- package/src/runtime/root/runtime.ts +23 -5
- package/src/runtime/root/service.ts +100 -29
- package/src/runtime/root/types.ts +12 -0
- package/src/runtime/safe-tooling/ios-development.ts +321 -63
- package/src/runtime/shared/trusted-executable.ts +62 -0
- package/src/runtime/shared/trusted-node-executable.ts +48 -0
- package/src/runtime/standalone-recovery/core.ts +1079 -240
- package/src/runtime/standalone-recovery/entry.ts +100 -24
- package/src/runtime/standalone-recovery/installer.ts +20 -4
- package/src/runtime/standalone-recovery/service-labels.ts +2 -0
- package/src/runtime/standalone-recovery/watchdog-heartbeat.ts +160 -0
- package/src/runtime/workflow/schedules/browser-probe.ts +81 -3
- package/src/runtime/workflow/schedules/engine.ts +364 -202
- package/src/runtime/workflow/schedules/github-issue-watch.ts +158 -0
- package/src/runtime/workflow/schedules/settlement.ts +64 -17
- package/src/runtime/workflow/schedules/store.ts +209 -19
- package/src/runtime/workflow/schedules/types.ts +2 -4
- package/src/runtime/workflow/schedules/work-continuation.ts +26 -13
- package/src/testing/test-governance.ts +8 -40
- package/assets/reference-configs/heartbeat-triage.md +0 -57
- package/assets/templates/helpers/harness-trace-grade.sh +0 -150
- package/assets/templates/helpers/heartbeat-triage.sh +0 -361
- package/assets/templates/helpers/maintenance-triage.sh +0 -167
- package/docs/architecture/current/approved-target-architecture.zh-CN.md +0 -1501
- package/docs/architecture/current/architecture-invariants.md +0 -331
- package/docs/architecture/current/automation-and-schedule-engine.md +0 -459
- package/docs/architecture/current/codegraph-context-provider.md +0 -238
- package/docs/architecture/current/control-plane-authority-inventory.md +0 -94
- package/docs/architecture/current/controller-repository-decoupling.md +0 -148
- package/docs/architecture/current/dispatch-and-agent-strategy.md +0 -373
- package/docs/architecture/current/entity-model.md +0 -612
- package/docs/architecture/current/external-plugin-governance.md +0 -396
- package/docs/architecture/current/failure-recovery.md +0 -447
- package/docs/architecture/current/governance.md +0 -213
- package/docs/architecture/current/human-interaction-plane.md +0 -87
- package/docs/architecture/current/implementation-status.md +0 -128
- package/docs/architecture/current/job-and-run-lifecycle.md +0 -413
- package/docs/architecture/current/legacy-governance.md +0 -58
- package/docs/architecture/current/local-workspace-target-grants.md +0 -70
- package/docs/architecture/current/migration-roadmap.md +0 -105
- package/docs/architecture/current/multi-repository-execution.md +0 -371
- package/docs/architecture/current/operations-runbook.md +0 -45
- package/docs/architecture/current/peer-supercontroller-runtime.md +0 -32
- package/docs/architecture/current/personal-assistant-plugin-baseline.md +0 -206
- package/docs/architecture/current/repository-access-modes.md +0 -102
- package/docs/architecture/current/route-policy.md +0 -15
- package/docs/architecture/current/route-session-concurrency.md +0 -85
- package/docs/architecture/current/runtime-architecture-simplification.md +0 -214
- package/docs/architecture/current/runtime-directory-map.md +0 -49
- package/docs/architecture/current/runtime-health-and-resource-lifecycle.md +0 -85
- package/docs/architecture/current/scheduler-and-resource-claims.md +0 -422
- package/docs/architecture/current/session-aware-execution-and-authorization.md +0 -77
- package/docs/architecture/current/system-overview.md +0 -169
- package/docs/architecture/current/target-requirements-traceability.md +0 -202
- package/docs/architecture/current/thin-harness-governance-policy.md +0 -32
- package/docs/architecture/current/thin-harness-v1.md +0 -321
- package/docs/architecture/current/verification-and-release-gates.md +0 -391
- package/docs/forge-autonomous-goal-loop.md +0 -9
- package/docs/forge-provider-configuration.md +0 -7
- package/docs/operations/chatgpt-personal-assistant-runtime.md +0 -93
- package/docs/operations/gmail-assistant-routines.md +0 -186
- package/docs/operations/personal-assistant-operator-guide.md +0 -61
- package/docs/operations/provider-configuration.md +0 -31
- package/scripts/harness-trace-grade.sh +0 -150
- package/scripts/heartbeat-triage.sh +0 -361
- package/scripts/maintenance-triage.sh +0 -167
- package/src/cli/local-bridge/frontend/src/features/settings/SettingsView.tsx +0 -2
- package/src/cli/repositories/goal-registry.ts +0 -239
- package/src/runtime/assistant/action-proposals.ts +0 -279
- package/src/runtime/assistant/intent.ts +0 -395
- package/src/runtime/assistant/model-provider.ts +0 -460
- package/src/runtime/assistant/openapi.ts +0 -223
- package/src/runtime/assistant/policy.ts +0 -89
- package/src/runtime/assistant/readiness.ts +0 -258
- package/src/runtime/assistant/routine-runtime.ts +0 -477
- package/src/runtime/assistant/schedule-binding.ts +0 -171
- package/src/runtime/assistant/standing-grants.ts +0 -375
- package/src/runtime/assistant/store.ts +0 -243
- package/src/runtime/assistant/types.ts +0 -135
- package/src/runtime/control-plane/goal-loop/config-facade.ts +0 -700
- package/src/runtime/control-plane/goal-loop/config-store.ts +0 -570
- package/src/runtime/control-plane/goal-loop/config-types.ts +0 -213
- package/src/runtime/control-plane/goal-loop/executor-router.ts +0 -109
- package/src/runtime/control-plane/goal-loop/failure-taxonomy.ts +0 -149
- package/src/runtime/control-plane/goal-loop/goal-contract-store.ts +0 -304
- package/src/runtime/control-plane/goal-loop/goal-loop-engine.ts +0 -1001
- package/src/runtime/control-plane/goal-loop/handoff-packet.ts +0 -160
- package/src/runtime/control-plane/goal-loop/index.ts +0 -13
- package/src/runtime/control-plane/goal-loop/local-tools.ts +0 -290
- package/src/runtime/control-plane/goal-loop/policy-gates.ts +0 -203
- package/src/runtime/control-plane/goal-loop/provider-dispatch.ts +0 -93
- package/src/runtime/control-plane/goal-loop/provider-registry.ts +0 -545
- package/src/runtime/control-plane/goal-loop/types.ts +0 -378
- package/src/runtime/control-plane/startup-recovery.ts +0 -198
- package/src/runtime/gateway/mcp/resource-policy.ts +0 -186
- package/src/runtime/personal-assistant/gmail-triage-manager.ts +0 -231
- package/src/runtime/personal-assistant/reporting-runtime.ts +0 -344
- package/src/runtime/personal-assistant/triage-runtime.ts +0 -748
- package/src/runtime/workflow/findings/store.ts +0 -204
- package/src/runtime/workflow/findings/types.ts +0 -58
- package/src/runtime/workflow/portfolio/engine.ts +0 -20
- package/src/runtime/workflow/portfolio/store.ts +0 -185
- 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', '
|
|
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. */
|
package/src/cli/mcp/toolset.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { McpToolDefinition } from './
|
|
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-
|
|
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
|
|
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',
|
|
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({
|
|
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({
|
|
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
|
-
|
|
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
|
|
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'
|
|
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'
|
|
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(
|
|
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;
|
package/src/cli/mcp/types.ts
CHANGED
|
@@ -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
|
-
* -
|
|
6
|
-
* - advanced
|
|
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;
|