@moretea-labs/forge 1.5.1 → 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.
- package/AGENTS.md +2 -0
- package/CHANGELOG.md +46 -0
- package/CLAUDE.md +2 -0
- package/DESIGN.md +7 -2
- package/README.md +4 -4
- package/README.zh-CN.md +2 -2
- 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/pre-edit-guard.sh +8 -39
- package/assets/hooks/prompt-guard.sh +7 -83
- package/assets/hooks/session-start-context.sh +56 -1
- package/assets/partials/05-workflow.partial.md +1 -1
- package/assets/partials-agents/03-orchestration.partial.md +1 -1
- package/assets/plugin-registry.v1.json +54 -3
- package/assets/reference-configs/document-generation.md +1 -1
- package/assets/reference-configs/harness-overview.md +1 -1
- package/assets/reference-configs/hook-operations.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-task-workflow.sh +4 -4
- package/assets/templates/helpers/contract-worktree.sh +1 -21
- package/assets/templates/helpers/ensure-task-workflow.sh +13 -38
- package/assets/templates/helpers/migrate-project-template.sh +22 -45
- 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/sprint-backlog.sh +6 -6
- package/assets/templates/helpers/verify-contract.sh +1 -111
- package/assets/templates/helpers/verify-sprint.sh +3 -180
- 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 +170 -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-runtime-self-healing-loop.md +1 -1
- package/docs/operations/controller-browser-plugin.md +38 -22
- package/docs/operations/controller-performance-and-502.md +124 -0
- package/docs/operations/controller-reliability-runbook.md +1 -1
- package/docs/operations/features.md +3 -3
- 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/tutorials/01-install-and-start.md +1 -1
- package/docs/tutorials/01-install-and-start.zh-CN.md +1 -1
- package/docs/wiki/Architecture.md +6 -6
- package/docs/wiki/Implementation.md +2 -2
- package/docs/wiki/Installation.md +1 -1
- package/docs/wiki/Integrations.md +2 -2
- package/docs/wiki/Quick-Start.md +1 -1
- package/docs/wiki/Work-Lifecycle.md +1 -1
- package/package.json +29 -10
- package/scripts/activate-source-baseline.ts +17 -13
- 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/capture-plan.sh +3 -3
- package/scripts/check-agent-tooling.sh +8 -35
- package/scripts/check-architecture-sync.sh +17 -86
- package/scripts/check-mcp-compatibility.ts +14 -0
- package/scripts/check-public-docs.sh +14 -1
- package/scripts/check-runtime-architecture.mjs +107 -64
- package/scripts/check-stable-baseline.ts +92 -0
- package/scripts/check-task-workflow.sh +4 -4
- package/scripts/contract-worktree.sh +1 -21
- package/scripts/ensure-task-workflow.sh +22 -55
- package/scripts/host-temporary-cloud-mcp-e2e.sh +265 -0
- package/scripts/install-standalone-recovery.ts +24 -0
- package/scripts/lib/project-init-lib.sh +15 -44
- package/scripts/migrate-chatgpt-automation-schedules.ts +64 -0
- package/scripts/migrate-project-template.sh +23 -1179
- package/scripts/new-plan.sh +1 -1
- package/scripts/plan-to-todo.sh +11 -36
- package/scripts/run-governed-gate.ts +2 -1
- package/scripts/ship-worktrees.sh +2 -29
- 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 -1
- package/scripts/verify-contract.sh +1 -111
- package/scripts/verify-forge-runtime.sh +0 -1
- package/scripts/verify-sprint.sh +3 -180
- package/scripts/workflow-contract.ts +1 -5
- package/src/cli/commands/chatgpt.ts +31 -2
- package/src/cli/commands/init-hook.ts +3 -3
- package/src/cli/commands/mcp.ts +9 -5
- package/src/cli/commands/plugin.ts +37 -10
- 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 +106 -3
- 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 +898 -430
- 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/github.ts +133 -0
- package/src/cli/hook/prompt-guard-decision.ts +17 -18
- package/src/cli/hook/prompt-intents.ts +1 -1
- package/src/cli/installer/managed-entries.ts +15 -1
- package/src/cli/local-bridge/console-automations.ts +225 -67
- package/src/cli/local-bridge/console-view-models.ts +3 -35
- package/src/cli/local-bridge/facade-api.ts +2 -217
- package/src/cli/local-bridge/frontend/src/App.tsx +3 -3
- package/src/cli/local-bridge/frontend/src/features/automations/AutomationsView.tsx +153 -3
- package/src/cli/local-bridge/frontend/src/features/capabilities/CapabilitiesView.tsx +37 -4
- package/src/cli/local-bridge/frontend/src/features/overview/OverviewView.tsx +183 -3
- package/src/cli/local-bridge/frontend/src/features/repositories/RepositoriesView.tsx +1 -1
- package/src/cli/local-bridge/frontend/src/features/work/WorkView.tsx +4 -3
- package/src/cli/local-bridge/frontend/src/lib/api.ts +18 -11
- package/src/cli/local-bridge/frontend/src/lib/routes.ts +1 -1
- package/src/cli/local-bridge/frontend/src/shell/CommandBar.tsx +1 -1
- package/src/cli/local-bridge/frontend/src/shell/Sidebar.tsx +4 -3
- package/src/cli/local-bridge/frontend/src/styles.css +27 -11
- package/src/cli/local-bridge/frontend/src/types.ts +8 -7
- package/src/cli/local-bridge/job-store.ts +1 -490
- package/src/cli/local-bridge/server.ts +29 -532
- package/src/cli/local-bridge/ui-dist/app.css +1 -1
- package/src/cli/local-bridge/ui-dist/app.js +5101 -4967
- package/src/cli/mcp/auth.ts +5 -5
- package/src/cli/mcp/instructions.ts +3 -2
- package/src/cli/mcp/legacy-tool-service.ts +0 -189
- package/src/cli/mcp/multi-repository.ts +16 -5
- package/src/cli/mcp/oauth.ts +175 -26
- package/src/cli/mcp/paths.ts +8 -2
- package/src/cli/mcp/repository-tools.ts +356 -101
- package/src/cli/mcp/server.ts +625 -54
- package/src/cli/mcp/tool-capability-cache.ts +1 -1
- package/src/cli/mcp/toolset-selection.ts +1 -1
- package/src/cli/mcp/toolset.ts +42 -5
- package/src/cli/mcp/transports/http.ts +125 -15
- package/src/cli/mcp/transports/session-registry.ts +67 -5
- package/src/cli/mcp/types.ts +3 -3
- package/src/cli/repositories/command-classifier.ts +209 -14
- package/src/cli/repositories/command-executor.ts +55 -521
- 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 +121 -0
- package/src/cli/repositories/safe-patch.ts +6 -4
- package/src/cli/repositories/selected-path-actions.ts +17 -9
- package/src/cli/repositories/structured-git.ts +110 -10
- package/src/cli/repository/inspector.ts +565 -62
- 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.ts +275 -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 +196 -2
- package/src/runtime/control-plane/execution/edit-validation-coordinator.ts +86 -24
- package/src/runtime/control-plane/execution/execution-identity.ts +65 -14
- package/src/runtime/control-plane/execution/session-store.ts +18 -0
- package/src/runtime/control-plane/execution/validation.ts +15 -2
- package/src/runtime/control-plane/execution/verification-evidence.ts +58 -3
- 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-remote-delivery.ts +215 -0
- package/src/runtime/control-plane/execution/work-task-receipt.ts +54 -11
- package/src/runtime/control-plane/execution/work-terminal-cleanup.ts +175 -8
- package/src/runtime/control-plane/execution/work-validation-reconciler.ts +28 -21
- package/src/runtime/control-plane/execution/work-verification-snapshot.ts +87 -9
- package/src/runtime/control-plane/facade/capability-registry.ts +129 -25
- package/src/runtime/control-plane/facade/controller-round-relay.ts +991 -0
- package/src/runtime/control-plane/facade/controller-session-store.ts +144 -14
- package/src/runtime/control-plane/facade/goal-workloop-access.ts +9 -2
- package/src/runtime/control-plane/facade/goal-workloop.ts +885 -105
- package/src/runtime/control-plane/facade/index.ts +1 -0
- package/src/runtime/control-plane/facade/plan-contract-store.ts +211 -26
- package/src/runtime/control-plane/facade/requirement-board.ts +24 -8
- 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 +55 -11
- package/src/runtime/control-plane/facade/work-contract-store.ts +204 -73
- 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 +145 -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 +273 -542
- 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 +50 -0
- package/src/runtime/control-plane/launcher/chatgpt-work-continuation.ts +642 -51
- package/src/runtime/control-plane/launcher/launch-reservation-store.ts +40 -0
- package/src/runtime/control-plane/launcher/thin-launcher.ts +194 -10
- package/src/runtime/control-plane/persistence/controller-home-migration.ts +487 -0
- package/src/runtime/control-plane/persistence/requirement-store.ts +15 -11
- 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/routing/route-policy.ts +7 -16
- package/src/runtime/control-plane/runtime-status-client.ts +0 -2
- package/src/runtime/diagnostics/mcp-timing.ts +19 -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/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 +52 -14
- package/src/runtime/execution/process-runtime/check-result.ts +63 -2
- package/src/runtime/execution/process-runtime/check-scheduling.ts +114 -0
- package/src/runtime/execution/process-runtime/command-facade.ts +346 -40
- package/src/runtime/execution/process-runtime/gc.ts +98 -12
- package/src/runtime/execution/process-runtime/lightweight-managed.ts +1184 -0
- package/src/runtime/execution/process-runtime/persisted-check.ts +57 -6
- package/src/runtime/execution/process-runtime/resource-claims.ts +97 -8
- package/src/runtime/execution/process-runtime/runtime.ts +59 -4
- package/src/runtime/execution/process-runtime/store.ts +7 -0
- package/src/runtime/execution/process-runtime/types.ts +2 -0
- 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/workers/executor.ts +0 -48
- package/src/runtime/gateway/mcp/execution-tools.ts +1219 -126
- package/src/runtime/gateway/mcp/process-tools.ts +83 -37
- package/src/runtime/gateway/mcp/router.ts +185 -83
- package/src/runtime/gateway/mcp/runtime-tool-definitions.ts +546 -0
- package/src/runtime/gateway/mcp/runtime-tools.ts +2555 -1616
- package/src/runtime/model-clients/deepseek-adapter.ts +0 -32
- package/src/runtime/plugins/app-store-connect-adapter.ts +123 -19
- package/src/runtime/plugins/browser-adapter.ts +2925 -318
- package/src/runtime/plugins/browser-automation-service.ts +10 -0
- package/src/runtime/plugins/browser-handoff-host.ts +6 -31
- package/src/runtime/plugins/browser-handoff.ts +92 -5
- package/src/runtime/plugins/browser-macos-bridge.ts +586 -45
- 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 +152 -0
- package/src/runtime/plugins/browser-runtime.ts +183 -0
- package/src/runtime/plugins/browser-session-authority.ts +332 -0
- package/src/runtime/plugins/capability-authorization-grants.ts +354 -0
- package/src/runtime/plugins/desktop-operator-registration.ts +15 -12
- package/src/runtime/plugins/external-adapter.ts +324 -3
- package/src/runtime/plugins/external-registration.ts +84 -5
- package/src/runtime/plugins/external-unix-socket.ts +7 -1
- package/src/runtime/plugins/first-party-registry.ts +4 -2
- package/src/runtime/plugins/github-adapter.ts +125 -0
- package/src/runtime/plugins/gmail-adapter.ts +28 -2
- 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 +125 -8
- package/src/runtime/plugins/macos-capability-broker.ts +55 -9
- package/src/runtime/plugins/plugin-action-sidecar.ts +59 -0
- package/src/runtime/plugins/plugin-management-adapter.ts +181 -0
- package/src/runtime/plugins/resend-adapter.ts +1 -1
- package/src/runtime/plugins/store.ts +366 -24
- package/src/runtime/plugins/types.ts +39 -2
- 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/actions.ts +0 -10
- package/src/runtime/recovery/classifier.ts +0 -9
- package/src/runtime/recovery/maintenance-executor.ts +415 -18
- package/src/runtime/recovery/probe.ts +0 -1
- package/src/runtime/recovery/types.ts +0 -1
- package/src/runtime/root/mcp-transport.ts +180 -10
- package/src/runtime/root/package-connector-service.ts +186 -8
- package/src/runtime/root/package-runtime-release.ts +143 -17
- package/src/runtime/root/package-runtime-service.ts +430 -22
- package/src/runtime/root/release-manifest.ts +7 -2
- package/src/runtime/root/release-materialize.ts +162 -19
- package/src/runtime/root/release-store.ts +48 -11
- package/src/runtime/root/runtime.ts +23 -5
- package/src/runtime/root/service.ts +100 -27
- package/src/runtime/root/types.ts +2 -0
- package/src/runtime/safe-tooling/index.ts +0 -1
- package/src/runtime/safe-tooling/ios-development.ts +321 -63
- package/src/runtime/safe-tooling/types.ts +0 -30
- 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 +702 -94
- package/src/runtime/standalone-recovery/entry.ts +99 -23
- package/src/runtime/standalone-recovery/installer.ts +19 -3
- 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 +258 -0
- package/src/runtime/workflow/schedules/chatgpt-automation-migration.ts +40 -0
- package/src/runtime/workflow/schedules/engine.ts +509 -80
- package/src/runtime/workflow/schedules/github-issue-watch.ts +158 -0
- package/src/runtime/workflow/schedules/settlement.ts +48 -4
- package/src/runtime/workflow/schedules/store.ts +131 -10
- package/src/runtime/workflow/schedules/types.ts +6 -3
- package/src/runtime/workflow/schedules/work-continuation.ts +120 -34
- 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/bin/forge-desktop-helper.mjs +0 -204
- 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 -453
- package/docs/architecture/current/codegraph-context-provider.md +0 -226
- 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 -354
- package/docs/architecture/current/entity-model.md +0 -592
- 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 -144
- 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 -311
- 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 -83
- package/docs/operations/controller-desktop-plugin.md +0 -112
- 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/plugins/desktop-adapter.ts +0 -374
- package/src/runtime/safe-tooling/browser-safe.ts +0 -133
- 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';
|
|
@@ -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
|
@@ -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
|
}
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import { randomUUID, timingSafeEqual } from 'crypto';
|
|
2
|
+
import { existsSync, watch } from 'fs';
|
|
3
|
+
import { dirname } from 'path';
|
|
2
4
|
import express, { type Request, type Response, type NextFunction } from 'express';
|
|
3
5
|
import { tokenHandler } from '@modelcontextprotocol/sdk/server/auth/handlers/token.js';
|
|
4
6
|
import { revocationHandler } from '@modelcontextprotocol/sdk/server/auth/handlers/revoke.js';
|
|
@@ -9,9 +11,11 @@ import type { OAuthClientInformationFull } from '@modelcontextprotocol/sdk/share
|
|
|
9
11
|
import { StreamableHTTPServerTransport } from '@modelcontextprotocol/sdk/server/streamableHttp.js';
|
|
10
12
|
import {
|
|
11
13
|
buildMultiRepositoryToolDefinitions,
|
|
14
|
+
createCanonicalRuntimeProxy,
|
|
12
15
|
createMcpToolContext,
|
|
13
16
|
createForgeMcpServerFromContext,
|
|
14
17
|
readCanonicalRuntimeToolSchema,
|
|
18
|
+
type CanonicalRuntimeProxy,
|
|
15
19
|
type CanonicalRuntimeToolSchema,
|
|
16
20
|
type McpServerOptions,
|
|
17
21
|
} from '../server';
|
|
@@ -34,10 +38,11 @@ import {
|
|
|
34
38
|
controllerExposureSnapshot,
|
|
35
39
|
} from '../toolset';
|
|
36
40
|
import { readForgeRuntimeStatus } from '../../../runtime/control-plane/runtime-status-client';
|
|
41
|
+
import { invalidateExecutionSession } from '../../../runtime/control-plane/execution/session-store';
|
|
37
42
|
import { runtimeIdentitySnapshot } from '../../../runtime/gateway/mcp/runtime-tools';
|
|
38
43
|
import { projectionBlocksReadiness, readRepositoryProjectionSnapshot } from '../../../runtime/projections/materialized-view';
|
|
39
44
|
import { readRuntimeGeneration } from '../../../runtime/control-plane/runtime-generation';
|
|
40
|
-
import { readRuntimeStatusSnapshot } from '../../../runtime/root/status';
|
|
45
|
+
import { readRuntimeStatusSnapshot, runtimeStatusPath } from '../../../runtime/root/status';
|
|
41
46
|
import { getRepository, listRepositories } from '../../repositories/registry';
|
|
42
47
|
import { buildControllerTaskLedgerProjection } from '../../controller/task-ledger';
|
|
43
48
|
import { legacyIssueAuthorityRetired } from '../../controller/legacy-issue-cutover';
|
|
@@ -192,6 +197,14 @@ export async function resolveMcpSessionCurrentFingerprint(
|
|
|
192
197
|
return await loadRuntimeFingerprint?.();
|
|
193
198
|
}
|
|
194
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
|
+
|
|
195
208
|
function toolCallOutsideSessionSchema(body: unknown, toolNames: readonly string[] | undefined): boolean {
|
|
196
209
|
if (!toolNames) return false;
|
|
197
210
|
const messages = Array.isArray(body) ? body : [body];
|
|
@@ -618,6 +631,11 @@ function requireMcpHttpAuth(
|
|
|
618
631
|
resourcePath = '/mcp',
|
|
619
632
|
) {
|
|
620
633
|
return (req: Request, res: Response, next: NextFunction) => {
|
|
634
|
+
if (mode === 'none') {
|
|
635
|
+
next();
|
|
636
|
+
return;
|
|
637
|
+
}
|
|
638
|
+
|
|
621
639
|
if (mode === 'bearer') {
|
|
622
640
|
if (!isAuthorizedMcpHttpRequest(req, bearerToken)) {
|
|
623
641
|
sendBearerUnauthorized(res, bearerToken ? 'Missing or invalid Authorization header' : 'Bearer token is not configured', Boolean(bearerToken));
|
|
@@ -664,7 +682,7 @@ function positiveIntegerEnv(name: string, fallback: number): number {
|
|
|
664
682
|
}
|
|
665
683
|
|
|
666
684
|
const MAX_MCP_SESSIONS = positiveIntegerEnv('FORGE_MCP_MAX_SESSIONS', 64);
|
|
667
|
-
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);
|
|
668
686
|
const MAX_INITIALIZING_SESSIONS = positiveIntegerEnv('FORGE_MCP_MAX_INITIALIZING_SESSIONS', 8);
|
|
669
687
|
const MAX_POSTS_PER_SESSION = positiveIntegerEnv('FORGE_MCP_MAX_POSTS_PER_SESSION', 4);
|
|
670
688
|
const MAX_ACTIVE_POSTS = positiveIntegerEnv('FORGE_MCP_MAX_ACTIVE_POSTS', 32);
|
|
@@ -685,6 +703,7 @@ async function handleMcpPost(
|
|
|
685
703
|
route: McpSessionRoute,
|
|
686
704
|
currentToolSurfaceFingerprint: () => string | undefined,
|
|
687
705
|
resolveRuntimeSchema?: (context: McpToolContext) => Promise<CanonicalRuntimeToolSchema | undefined>,
|
|
706
|
+
sharedRuntimeProxy?: CanonicalRuntimeProxy,
|
|
688
707
|
): Promise<void> {
|
|
689
708
|
let body: unknown;
|
|
690
709
|
try {
|
|
@@ -711,7 +730,15 @@ async function handleMcpPost(
|
|
|
711
730
|
if (stats.initializing >= MAX_INITIALIZING_SESSIONS || stats.activePosts >= MAX_ACTIVE_POSTS) {
|
|
712
731
|
stats.rejectedOverload += 1;
|
|
713
732
|
res.setHeader('retry-after', '1');
|
|
714
|
-
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
|
+
});
|
|
715
742
|
return;
|
|
716
743
|
}
|
|
717
744
|
stats.initializing += 1;
|
|
@@ -731,7 +758,15 @@ async function handleMcpPost(
|
|
|
731
758
|
if (!reservationId) {
|
|
732
759
|
stats.rejectedOverload += 1;
|
|
733
760
|
res.setHeader('retry-after', '1');
|
|
734
|
-
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
|
+
});
|
|
735
770
|
return;
|
|
736
771
|
}
|
|
737
772
|
const sessionContext = createMcpToolContext({
|
|
@@ -739,7 +774,8 @@ async function handleMcpPost(
|
|
|
739
774
|
sessionId: `mcp_${randomUUID().replace(/-/g, '')}`,
|
|
740
775
|
principalId,
|
|
741
776
|
});
|
|
742
|
-
|
|
777
|
+
let runtimeSchema = await resolveRuntimeSchema?.(sessionContext);
|
|
778
|
+
let server: ReturnType<typeof createForgeMcpServerFromContext> | undefined;
|
|
743
779
|
transport = new StreamableHTTPServerTransport({
|
|
744
780
|
sessionIdGenerator: () => randomUUID(),
|
|
745
781
|
onsessioninitialized: (newSessionId: string): void => {
|
|
@@ -752,6 +788,22 @@ async function handleMcpPost(
|
|
|
752
788
|
clientIdentity,
|
|
753
789
|
toolSurfaceFingerprint: runtimeSchema?.fingerprint ?? currentToolSurfaceFingerprint(),
|
|
754
790
|
toolNames: runtimeSchema?.toolNames,
|
|
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
|
+
: {}),
|
|
755
807
|
});
|
|
756
808
|
initializedSessionId = newSessionId;
|
|
757
809
|
},
|
|
@@ -759,7 +811,7 @@ async function handleMcpPost(
|
|
|
759
811
|
transport.onclose = () => {
|
|
760
812
|
if (transport?.sessionId) registry.detach(transport.sessionId);
|
|
761
813
|
};
|
|
762
|
-
|
|
814
|
+
server = createForgeMcpServerFromContext(sessionContext, runtimeSchema, sharedRuntimeProxy);
|
|
763
815
|
await server.connect(transport);
|
|
764
816
|
await transport.handleRequest(req, res, body);
|
|
765
817
|
} finally {
|
|
@@ -790,6 +842,17 @@ async function handleMcpPost(
|
|
|
790
842
|
: undefined,
|
|
791
843
|
);
|
|
792
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
|
+
}
|
|
793
856
|
// Keep the transport/session alive long enough for the host to observe
|
|
794
857
|
// the recoverable reset and issue a replacement initialize request.
|
|
795
858
|
// The initialize path explicitly supersedes this session afterward.
|
|
@@ -873,10 +936,15 @@ async function handleMcpDelete(req: Request, res: Response, registry: HttpSessio
|
|
|
873
936
|
export async function startMcpHttp(opts: McpHttpOptions): Promise<void> {
|
|
874
937
|
const host = opts.host ?? '127.0.0.1';
|
|
875
938
|
const port = opts.port ?? 8765;
|
|
876
|
-
const repoRoot = resolveMcpRepoRoot(opts.repo ?? '.');
|
|
877
939
|
const controllerHome = resolveControllerHome(opts.controllerHome);
|
|
878
|
-
const serviceConfig = loadMcpServiceLocalConfig(controllerHome
|
|
940
|
+
const serviceConfig = loadMcpServiceLocalConfig(controllerHome);
|
|
879
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 ?? '.');
|
|
880
948
|
const authMode = parseMcpHttpAuthMode(opts.auth ?? serviceConfig?.auth?.mode);
|
|
881
949
|
const authToken = opts.authToken ?? readMcpServiceBearerToken(controllerHome, repoRoot);
|
|
882
950
|
const oauthPassphrase = authMode === 'oauth'
|
|
@@ -898,6 +966,17 @@ export async function startMcpHttp(opts: McpHttpOptions): Promise<void> {
|
|
|
898
966
|
streamLeaseMs: MCP_STREAM_LEASE_MS,
|
|
899
967
|
absoluteLifetimeMs: MCP_SESSION_ABSOLUTE_LIFETIME_MS,
|
|
900
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
|
+
},
|
|
901
980
|
});
|
|
902
981
|
const runtimeStats: McpRuntimeStats = { initializing: 0, activePosts: 0, rejectedOverload: 0 };
|
|
903
982
|
const toolContext = createMcpToolContext({ ...opts, repo: repoRoot, controllerHome, profile });
|
|
@@ -913,14 +992,34 @@ export async function startMcpHttp(opts: McpHttpOptions): Promise<void> {
|
|
|
913
992
|
devRunnerMaxTimeoutMs: opts.devRunnerMaxTimeoutMs,
|
|
914
993
|
};
|
|
915
994
|
const runtimeControllerHome = 'controllerHome' in toolContext ? toolContext.controllerHome : undefined;
|
|
995
|
+
const sharedRuntimeProxy = runtimeControllerHome && 'controllerHome' in toolContext && !toolContext.runtimeSourceRoot
|
|
996
|
+
? createCanonicalRuntimeProxy(toolContext)
|
|
997
|
+
: undefined;
|
|
916
998
|
const currentRuntimeGeneration = () => runtimeControllerHome ? readRuntimeGeneration(runtimeControllerHome) : undefined;
|
|
917
999
|
const currentRuntimeToolSurfaceFingerprint = () => runtimeControllerHome
|
|
918
1000
|
? readRuntimeStatusSnapshot(runtimeControllerHome)?.toolSurfaceFingerprint
|
|
919
1001
|
: undefined;
|
|
1002
|
+
let observedRuntimeToolSurfaceFingerprint = currentRuntimeToolSurfaceFingerprint();
|
|
1003
|
+
let toolSurfaceNotificationTimer: ReturnType<typeof setTimeout> | undefined;
|
|
1004
|
+
const runtimeStatusDirectory = runtimeControllerHome ? dirname(runtimeStatusPath(runtimeControllerHome)) : undefined;
|
|
1005
|
+
const runtimeStatusWatcher = runtimeStatusDirectory && existsSync(runtimeStatusDirectory)
|
|
1006
|
+
? watch(runtimeStatusDirectory, { persistent: false }, (_event, filename) => {
|
|
1007
|
+
if (String(filename ?? '') !== 'status.json') return;
|
|
1008
|
+
if (toolSurfaceNotificationTimer) clearTimeout(toolSurfaceNotificationTimer);
|
|
1009
|
+
toolSurfaceNotificationTimer = setTimeout(() => {
|
|
1010
|
+
const currentFingerprint = currentRuntimeToolSurfaceFingerprint();
|
|
1011
|
+
if (!currentFingerprint || currentFingerprint === observedRuntimeToolSurfaceFingerprint) return;
|
|
1012
|
+
observedRuntimeToolSurfaceFingerprint = currentFingerprint;
|
|
1013
|
+
void sessionRegistry.notifyToolListChanged(currentFingerprint);
|
|
1014
|
+
}, 25);
|
|
1015
|
+
toolSurfaceNotificationTimer.unref();
|
|
1016
|
+
})
|
|
1017
|
+
: undefined;
|
|
1018
|
+
runtimeStatusWatcher?.on('error', () => undefined);
|
|
920
1019
|
const resolveRuntimeSchema = runtimeControllerHome
|
|
921
1020
|
? async (context: McpToolContext): Promise<CanonicalRuntimeToolSchema | undefined> => {
|
|
922
1021
|
if (!('controllerHome' in context)) return undefined;
|
|
923
|
-
return await readCanonicalRuntimeToolSchema(context);
|
|
1022
|
+
return await readCanonicalRuntimeToolSchema(context, sharedRuntimeProxy);
|
|
924
1023
|
}
|
|
925
1024
|
: undefined;
|
|
926
1025
|
const localControllerConfig = {
|
|
@@ -932,7 +1031,7 @@ export async function startMcpHttp(opts: McpHttpOptions): Promise<void> {
|
|
|
932
1031
|
const toolSurface = toolContext.policy.profile === 'controller' ? FORGE_TOOL_SURFACE : `${toolContext.policy.profile}-legacy-v1`;
|
|
933
1032
|
const toolSurfaceSchemaVersion = toolContext.policy.profile === 'controller' ? FORGE_MCP_SCHEMA_VERSION : 1;
|
|
934
1033
|
const forgeVersion = FORGE_VERSION;
|
|
935
|
-
const repoId = toolContext.policy.profile === 'controller' ? undefined : repositoryIdentity(repoRoot);
|
|
1034
|
+
const repoId = toolContext.policy.profile === 'controller' || !repoRoot ? undefined : repositoryIdentity(repoRoot);
|
|
936
1035
|
const startedAt = new Date().toISOString();
|
|
937
1036
|
const localOrigin = `http://${host === '::' || host === '0.0.0.0' ? '127.0.0.1' : host}:${port}`;
|
|
938
1037
|
const advertisedOrigin = configuredPublicOrigin ?? localOrigin;
|
|
@@ -1006,7 +1105,11 @@ export async function startMcpHttp(opts: McpHttpOptions): Promise<void> {
|
|
|
1006
1105
|
defaultTimeoutMs: toolContext.policy.execution.runnerTimeoutMs,
|
|
1007
1106
|
maxTimeoutMs: toolContext.policy.execution.runnerMaxTimeoutMs,
|
|
1008
1107
|
},
|
|
1009
|
-
auth: authMode === 'oauth'
|
|
1108
|
+
auth: authMode === 'oauth'
|
|
1109
|
+
? (oauthPassphrase ? 'oauth' : 'missing')
|
|
1110
|
+
: authMode === 'bearer'
|
|
1111
|
+
? (authToken ? 'required' : 'missing')
|
|
1112
|
+
: 'none',
|
|
1010
1113
|
mcpEndpoint: `${advertisedOrigin}/mcp`,
|
|
1011
1114
|
// Grok now completes standard OAuth dynamic registration + PKCE on the
|
|
1012
1115
|
// canonical MCP resource. Keep /mcp-grok below only as a legacy alias.
|
|
@@ -1195,7 +1298,7 @@ export async function startMcpHttp(opts: McpHttpOptions): Promise<void> {
|
|
|
1195
1298
|
// Primary MCP path: OAuth (or bearer when --auth bearer). Unchanged for ChatGPT.
|
|
1196
1299
|
app.use('/mcp', setMcpResponseHeaders);
|
|
1197
1300
|
app.post('/mcp', requireMcpHttpAuth(authMode, authToken, oauthProvider, configuredPublicOrigin), express.raw({ type: '*/*', limit: '1mb' }), (req, res) => {
|
|
1198
|
-
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) => {
|
|
1199
1302
|
if (!res.headersSent) sendMcpRequestError(res, error);
|
|
1200
1303
|
});
|
|
1201
1304
|
});
|
|
@@ -1213,7 +1316,7 @@ export async function startMcpHttp(opts: McpHttpOptions): Promise<void> {
|
|
|
1213
1316
|
// Legacy Grok OAuth resource. New Grok connectors should use canonical /mcp.
|
|
1214
1317
|
app.use('/mcp-grok', setMcpResponseHeaders);
|
|
1215
1318
|
app.post('/mcp-grok', requireMcpHttpAuth(authMode, authToken, oauthProvider, configuredPublicOrigin, '/mcp-grok'), express.raw({ type: '*/*', limit: '1mb' }), (req, res) => {
|
|
1216
|
-
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) => {
|
|
1217
1320
|
if (!res.headersSent) sendMcpRequestError(res, error);
|
|
1218
1321
|
});
|
|
1219
1322
|
});
|
|
@@ -1231,7 +1334,7 @@ export async function startMcpHttp(opts: McpHttpOptions): Promise<void> {
|
|
|
1231
1334
|
// Bearer-only MCP path for clients that can send Authorization headers. Never advertises OAuth resource_metadata.
|
|
1232
1335
|
app.use('/mcp-bearer', setMcpResponseHeaders);
|
|
1233
1336
|
app.post('/mcp-bearer', requireMcpHttpAuth('bearer', authToken, null, configuredPublicOrigin), express.raw({ type: '*/*', limit: '1mb' }), (req, res) => {
|
|
1234
|
-
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) => {
|
|
1235
1338
|
if (!res.headersSent) sendMcpRequestError(res, error);
|
|
1236
1339
|
});
|
|
1237
1340
|
});
|
|
@@ -1260,13 +1363,20 @@ export async function startMcpHttp(opts: McpHttpOptions): Promise<void> {
|
|
|
1260
1363
|
|
|
1261
1364
|
httpServer.on('close', () => {
|
|
1262
1365
|
clearInterval(cleanupTimer);
|
|
1366
|
+
if (toolSurfaceNotificationTimer) clearTimeout(toolSurfaceNotificationTimer);
|
|
1367
|
+
runtimeStatusWatcher?.close();
|
|
1263
1368
|
void sessionRegistry.closeAll('shutdown');
|
|
1369
|
+
void sharedRuntimeProxy?.close();
|
|
1264
1370
|
});
|
|
1265
1371
|
|
|
1266
1372
|
await new Promise<void>((resolve) => {
|
|
1267
1373
|
httpServer.once('listening', resolve);
|
|
1268
1374
|
});
|
|
1269
|
-
const authLabel = authMode === 'oauth'
|
|
1375
|
+
const authLabel = authMode === 'oauth'
|
|
1376
|
+
? (oauthPassphrase ? 'oauth' : 'oauth-missing')
|
|
1377
|
+
: authMode === 'bearer'
|
|
1378
|
+
? (authToken ? 'bearer' : 'missing')
|
|
1379
|
+
: 'none';
|
|
1270
1380
|
console.error(
|
|
1271
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)`,
|
|
1272
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,
|
|
@@ -31,6 +36,11 @@ export interface ManagedMcpSession<
|
|
|
31
36
|
toolSurfaceFingerprint?: string;
|
|
32
37
|
/** Exact tool names returned by the Canonical Runtime at initialize time. */
|
|
33
38
|
toolNames?: string[];
|
|
39
|
+
/** Standard MCP tools/list_changed notification bound to this session's connected Server. */
|
|
40
|
+
notifyToolListChanged?: () => Promise<void> | void;
|
|
41
|
+
/** Refreshes the mutable Runtime schema snapshot backing this live MCP session. */
|
|
42
|
+
refreshToolSurface?: () => Promise<McpToolSurfaceRefresh | undefined>;
|
|
43
|
+
lastNotifiedToolSurfaceFingerprint?: string;
|
|
34
44
|
createdAt: number;
|
|
35
45
|
lastActivityAt: number;
|
|
36
46
|
streamOpenedAt?: number;
|
|
@@ -69,7 +79,10 @@ export interface McpSessionSnapshot {
|
|
|
69
79
|
closed: McpSessionCloseCounters;
|
|
70
80
|
}
|
|
71
81
|
|
|
72
|
-
export interface McpSessionRegistryOptions
|
|
82
|
+
export interface McpSessionRegistryOptions<
|
|
83
|
+
TTransport extends ClosableMcpTransport = ClosableMcpTransport,
|
|
84
|
+
TContext = unknown,
|
|
85
|
+
> {
|
|
73
86
|
maximumSessions?: number;
|
|
74
87
|
maximumSessionsPerPrincipal?: number;
|
|
75
88
|
idleTtlMs?: number;
|
|
@@ -77,6 +90,7 @@ export interface McpSessionRegistryOptions {
|
|
|
77
90
|
absoluteLifetimeMs?: number;
|
|
78
91
|
activePostStallMs?: number;
|
|
79
92
|
now?: () => number;
|
|
93
|
+
onSessionClosed?: (session: ManagedMcpSession<TTransport, TContext>, reason: McpSessionCloseReason) => void;
|
|
80
94
|
}
|
|
81
95
|
|
|
82
96
|
interface RegisterMcpSession<TTransport extends ClosableMcpTransport, TContext> {
|
|
@@ -88,6 +102,8 @@ interface RegisterMcpSession<TTransport extends ClosableMcpTransport, TContext>
|
|
|
88
102
|
clientIdentity: string;
|
|
89
103
|
toolSurfaceFingerprint?: string;
|
|
90
104
|
toolNames?: string[];
|
|
105
|
+
notifyToolListChanged?: () => Promise<void> | void;
|
|
106
|
+
refreshToolSurface?: () => Promise<McpToolSurfaceRefresh | undefined>;
|
|
91
107
|
initialPost?: boolean;
|
|
92
108
|
}
|
|
93
109
|
|
|
@@ -157,12 +173,13 @@ export class McpSessionRegistry<
|
|
|
157
173
|
private readonly absoluteLifetimeMs: number;
|
|
158
174
|
private readonly activePostStallMs: number;
|
|
159
175
|
private readonly now: () => number;
|
|
176
|
+
private readonly onSessionClosed?: (session: ManagedMcpSession<TTransport, TContext>, reason: McpSessionCloseReason) => void;
|
|
160
177
|
private readonly closeCounters = emptyCloseCounters();
|
|
161
178
|
private readonly initializeReservations = new Map<string, InitializeReservation>();
|
|
162
179
|
private admissionQueue: Promise<void> = Promise.resolve();
|
|
163
180
|
private nextReservationId = 0;
|
|
164
181
|
|
|
165
|
-
constructor(options: McpSessionRegistryOptions = {}) {
|
|
182
|
+
constructor(options: McpSessionRegistryOptions<TTransport, TContext> = {}) {
|
|
166
183
|
this.maximumSessions = positiveInteger(options.maximumSessions, DEFAULT_MAXIMUM_SESSIONS);
|
|
167
184
|
this.maximumSessionsPerPrincipal = Math.min(
|
|
168
185
|
this.maximumSessions,
|
|
@@ -173,6 +190,7 @@ export class McpSessionRegistry<
|
|
|
173
190
|
this.absoluteLifetimeMs = positiveInteger(options.absoluteLifetimeMs, DEFAULT_ABSOLUTE_LIFETIME_MS);
|
|
174
191
|
this.activePostStallMs = positiveInteger(options.activePostStallMs, DEFAULT_ACTIVE_POST_STALL_MS);
|
|
175
192
|
this.now = options.now ?? Date.now;
|
|
193
|
+
this.onSessionClosed = options.onSessionClosed;
|
|
176
194
|
}
|
|
177
195
|
|
|
178
196
|
get size(): number {
|
|
@@ -206,6 +224,38 @@ export class McpSessionRegistry<
|
|
|
206
224
|
if (session) session.lastActivityAt = this.now();
|
|
207
225
|
}
|
|
208
226
|
|
|
227
|
+
async notifyToolListChanged(currentFingerprint: string | undefined): Promise<number> {
|
|
228
|
+
if (!currentFingerprint) return 0;
|
|
229
|
+
let notified = 0;
|
|
230
|
+
await Promise.all(Array.from(this.sessions.values()).map(async (session) => {
|
|
231
|
+
if (!session.toolSurfaceFingerprint
|
|
232
|
+
|| session.toolSurfaceFingerprint === currentFingerprint
|
|
233
|
+
|| session.lastNotifiedToolSurfaceFingerprint === currentFingerprint
|
|
234
|
+
|| !session.notifyToolListChanged) return;
|
|
235
|
+
try {
|
|
236
|
+
await session.notifyToolListChanged();
|
|
237
|
+
session.lastNotifiedToolSurfaceFingerprint = currentFingerprint;
|
|
238
|
+
notified += 1;
|
|
239
|
+
} catch {
|
|
240
|
+
// Fingerprint fencing remains authoritative. A broken notification
|
|
241
|
+
// stream must not mark a stale session as refreshed or close active work.
|
|
242
|
+
}
|
|
243
|
+
}));
|
|
244
|
+
return notified;
|
|
245
|
+
}
|
|
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
|
+
|
|
209
259
|
beginPost(sessionId: string): ManagedMcpSession<TTransport, TContext> | undefined {
|
|
210
260
|
const session = this.sessions.get(sessionId);
|
|
211
261
|
if (!session) return undefined;
|
|
@@ -250,9 +300,11 @@ export class McpSessionRegistry<
|
|
|
250
300
|
detach(sessionId: string, reason: McpSessionCloseReason = 'transport_close'): boolean {
|
|
251
301
|
const session = this.sessions.get(sessionId);
|
|
252
302
|
if (!session) return false;
|
|
303
|
+
const closeReason = session.pendingCloseReason ?? reason;
|
|
253
304
|
this.sessions.delete(sessionId);
|
|
254
305
|
clearSessionCachesForSession(sessionId);
|
|
255
|
-
this.incrementCloseCounter(
|
|
306
|
+
this.incrementCloseCounter(closeReason);
|
|
307
|
+
this.observeSessionClosed(session, closeReason);
|
|
256
308
|
return true;
|
|
257
309
|
}
|
|
258
310
|
|
|
@@ -263,6 +315,7 @@ export class McpSessionRegistry<
|
|
|
263
315
|
clearSessionCachesForSession(sessionId);
|
|
264
316
|
session.pendingCloseReason = reason;
|
|
265
317
|
this.incrementCloseCounter(reason);
|
|
318
|
+
this.observeSessionClosed(session, reason);
|
|
266
319
|
try {
|
|
267
320
|
await session.transport.close();
|
|
268
321
|
} catch {
|
|
@@ -272,6 +325,15 @@ export class McpSessionRegistry<
|
|
|
272
325
|
return true;
|
|
273
326
|
}
|
|
274
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
|
+
|
|
275
337
|
async reserveForInitialize(request: InitializeCapacityRequest): Promise<string | undefined> {
|
|
276
338
|
return await this.withAdmissionLock(async () => {
|
|
277
339
|
await this.prune();
|
|
@@ -358,7 +420,7 @@ export class McpSessionRegistry<
|
|
|
358
420
|
const reservations = [...this.initializeReservations.values()];
|
|
359
421
|
const activePosts = sessions.reduce((count, session) => count + session.inFlightPosts, 0) + reservations.length;
|
|
360
422
|
const activeStreams = sessions.reduce((count, session) => count + session.inFlightGets, 0);
|
|
361
|
-
const evictable = sessions.filter((session) => session.inFlightPosts === 0).length;
|
|
423
|
+
const evictable = sessions.filter((session) => session.inFlightPosts === 0 && session.inFlightGets === 0).length;
|
|
362
424
|
const reserved = reservations.length;
|
|
363
425
|
const protectedCount = sessions.length - evictable + reserved;
|
|
364
426
|
const capacityAvailable = Math.max(0, this.maximumSessions - sessions.length - reserved);
|
|
@@ -413,7 +475,7 @@ export class McpSessionRegistry<
|
|
|
413
475
|
predicate: (session: ManagedMcpSession<TTransport, TContext>) => boolean = () => true,
|
|
414
476
|
): ManagedMcpSession<TTransport, TContext>[] {
|
|
415
477
|
return [...this.sessions.values()]
|
|
416
|
-
.filter((session) => session.inFlightPosts === 0 && predicate(session))
|
|
478
|
+
.filter((session) => session.inFlightPosts === 0 && session.inFlightGets === 0 && predicate(session))
|
|
417
479
|
.sort((left, right) => {
|
|
418
480
|
const leftAge = left.streamOpenedAt ?? left.lastActivityAt;
|
|
419
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;
|