@moretea-labs/forge 1.8.0 → 1.8.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +70 -7
- package/CHANGELOG.md +14 -0
- package/CLAUDE.md +17 -2
- package/CONTRIBUTING.md +3 -2
- package/THIRD_PARTY_NOTICES.md +1 -1
- package/adapters/chatgpt/browser-delivery-host.ts +7 -1
- package/adapters/chatgpt/browser-delivery-runtime.ts +529 -56
- package/adapters/chatgpt/controller-binding-store.ts +101 -22
- package/adapters/chatgpt/controller-round-host.ts +15 -25
- package/adapters/chatgpt/controller-round-settlement-store.ts +58 -4
- package/adapters/chatgpt/provider-delivery.ts +228 -1
- package/adapters/chatgpt/work-conversation-binding-store.ts +79 -53
- package/adapters/computer/chatgpt-extension-target.ts +463 -0
- package/adapters/computer/chatgpt-target-router.ts +103 -0
- package/adapters/computer/chrome-extension/background.js +385 -0
- package/adapters/computer/chrome-extension/content.js +378 -0
- package/adapters/computer/chrome-extension/core.js +24 -0
- package/adapters/computer/chrome-extension/manifest.json +30 -0
- package/adapters/computer/desktop-operator-discovery.ts +11 -31
- package/adapters/computer/interaction-target-authority.ts +142 -18
- package/adapters/mcp/auth.ts +0 -1
- package/adapters/mcp/instructions.ts +5 -4
- package/adapters/mcp/multi-repository.ts +3 -19
- package/adapters/mcp/oauth.ts +73 -0
- package/adapters/mcp/paths.ts +4 -1
- package/adapters/mcp/runtime-gateway/automation-receipt-adapter.ts +87 -0
- package/adapters/mcp/runtime-gateway/bounded-result-runtime.ts +62 -0
- package/adapters/mcp/runtime-gateway/cognition-settlement.ts +201 -0
- package/adapters/mcp/runtime-gateway/context-adapter.ts +411 -73
- package/adapters/mcp/runtime-gateway/context-pack-sidecar.ts +91 -0
- package/adapters/mcp/runtime-gateway/controller-authority-adapter.ts +20 -5
- package/adapters/mcp/runtime-gateway/core-capability-adapter.ts +258 -0
- package/adapters/mcp/runtime-gateway/engineering-preconditions.ts +10 -27
- package/adapters/mcp/runtime-gateway/engineering-tool-contract.ts +15 -0
- package/adapters/mcp/runtime-gateway/execution-tools.ts +8 -42
- package/adapters/mcp/runtime-gateway/gateway-execution-adapter.ts +2 -1
- package/adapters/mcp/runtime-gateway/plugin-adapter.ts +117 -45
- package/adapters/mcp/runtime-gateway/process-tools.ts +190 -22
- package/adapters/mcp/runtime-gateway/protected-computer-adapter.ts +16 -4
- package/adapters/mcp/runtime-gateway/recovery-adapter.ts +69 -52
- package/adapters/mcp/runtime-gateway/repository-compat-adapter.ts +4 -35
- package/adapters/mcp/runtime-gateway/result-adapter.ts +10 -4
- package/adapters/mcp/runtime-gateway/router.ts +18 -504
- package/adapters/mcp/runtime-gateway/routing-policy.ts +499 -0
- package/adapters/mcp/runtime-gateway/runtime-observation-adapter.ts +14 -65
- package/adapters/mcp/runtime-gateway/runtime-readiness-observation.ts +218 -0
- package/adapters/mcp/runtime-gateway/runtime-tool-definitions.ts +113 -173
- package/adapters/mcp/runtime-gateway/runtime-tools.ts +15 -5
- package/adapters/mcp/runtime-gateway/scheduler-adapter.ts +1 -0
- package/adapters/mcp/runtime-gateway/shared-adapter.ts +20 -0
- package/adapters/mcp/runtime-gateway/status-inbox-adapter.ts +358 -266
- package/adapters/mcp/runtime-gateway/typescript-navigation-sidecar.ts +136 -0
- package/adapters/mcp/runtime-gateway/work-adapter.ts +261 -3122
- package/adapters/mcp/runtime-gateway/work-controller-operations.ts +257 -0
- package/adapters/mcp/runtime-gateway/work-detail-projection.ts +60 -0
- package/adapters/mcp/runtime-gateway/work-input-wire-migration.ts +246 -0
- package/adapters/mcp/runtime-gateway/work-learning-operations.ts +145 -0
- package/adapters/mcp/runtime-gateway/work-list-projection.ts +38 -0
- package/adapters/mcp/runtime-gateway/work-plan-operations.ts +382 -0
- package/adapters/mcp/runtime-gateway/work-repair-adapter.ts +308 -0
- package/adapters/mcp/runtime-gateway/work-requirement-operations.ts +148 -0
- package/adapters/mcp/runtime-gateway/work-semantic-operations.ts +263 -0
- package/adapters/mcp/runtime-gateway/work-workflow-operations.ts +113 -0
- package/adapters/mcp/runtime-gateway/workflow-supervisor-adapter.ts +156 -0
- package/adapters/mcp/server.ts +67 -23
- package/adapters/mcp/setup.ts +1 -3
- package/adapters/mcp/tool-mapping/legacy-tool-service.ts +44 -170
- package/adapters/mcp/tool-mapping/post-finalize-work-attribution.ts +4 -9
- package/adapters/mcp/tool-mapping/repository-tools.ts +133 -142
- package/adapters/mcp/toolset-names.ts +5 -0
- package/adapters/mcp/toolset.ts +6 -5
- package/adapters/mcp/transports/http-observation.ts +365 -0
- package/adapters/mcp/transports/http.ts +154 -677
- package/adapters/mcp/transports/oauth-http.ts +322 -0
- package/adapters/mcp/transports/session-registry.ts +6 -0
- package/adapters/mcp/tunnels/openai-secure-tunnel.ts +89 -5
- package/assets/plugin-registry.v1.json +6 -4
- package/assets/reference-configs/agentic-development-flow.md +25 -0
- package/assets/reference-configs/global-working-rules.md +19 -0
- package/assets/skill-version.json +2 -2
- package/docs/architecture/CURRENT.md +111 -41
- package/docs/architecture/decisions/20260803-release-identity-binding-and-exit-policy.md +14 -5
- package/docs/architecture/decisions/20260823-immediate-controller-relay.md +6 -3
- package/docs/architecture/decisions/20260907-assistant-learning-loop.md +2 -0
- package/docs/architecture/decisions/20260907-controller-round-transition-policy.md +19 -4
- package/docs/architecture/decisions/20260916-workflow-supervisor-authority.md +249 -0
- package/docs/architecture/decisions/20260917-cognitive-memory-foundation.md +82 -0
- package/docs/architecture/decisions/20260918-stable-candidate-release-lifecycle.md +221 -0
- package/docs/architecture/decisions/20260919-autonomous-work-liveness.md +62 -0
- package/docs/architecture/decisions/20260924-thin-semantic-working-context.md +72 -0
- package/docs/architecture/decisions/20261001-supervisor-turn-authority.md +237 -0
- package/docs/architecture/decisions/20261005-forge-v3-desktop-client-boundary.md +77 -0
- package/docs/architecture/domains/verification.md +1 -0
- package/docs/architecture/domains/workflow-engine.md +6 -0
- package/docs/architecture/modules/controller-runtime/transport-lifecycle.md +1 -1
- package/docs/forge-plugin-management.md +2 -2
- package/docs/operations/controller-performance-and-502.md +17 -0
- package/docs/operations/controller-reliability-runbook.md +2 -2
- package/docs/operations/features.md +1 -1
- package/docs/operations/features.zh-CN.md +1 -1
- package/docs/operations/homebrew.md +2 -2
- package/docs/operations/mcp-tool-exposure.md +2 -0
- package/docs/operations/releasing.md +2 -0
- package/docs/operations/standalone-disaster-recovery.md +14 -6
- package/docs/wiki/Implementation.md +1 -1
- package/package.json +25 -14
- package/packages/kernel/cognition/api/index.ts +6 -0
- package/packages/kernel/cognition/application/activation-service.ts +451 -0
- package/packages/kernel/cognition/application/consolidation-service.ts +185 -0
- package/packages/kernel/cognition/application/legacy-experience-adapter.ts +38 -0
- package/packages/kernel/cognition/application/memory-service.ts +64 -0
- package/packages/kernel/cognition/domain/learning.ts +106 -0
- package/packages/kernel/cognition/domain/memory.ts +254 -0
- package/packages/kernel/controller/api/index.ts +1 -0
- package/packages/kernel/controller/application/continuation-service.ts +281 -0
- package/packages/kernel/controller/application/controller-round-service.ts +12 -0
- package/packages/kernel/controller/domain/controller-round-transition-policy.ts +242 -21
- package/packages/kernel/controller/domain/controller-round.ts +4 -1
- package/packages/kernel/controller/domain/execution-quality.ts +3 -1
- package/packages/kernel/controller/infrastructure/controller-round-store.ts +689 -103
- package/packages/kernel/controller/infrastructure/controller-session-store.ts +297 -71
- package/packages/kernel/controller/ports/controller-host.ts +2 -0
- package/packages/kernel/identity/api/index.ts +10 -0
- package/packages/kernel/identity/domain/activity-projection.ts +43 -0
- package/packages/kernel/identity/domain/capability-broker.ts +60 -0
- package/packages/kernel/identity/domain/grant.ts +72 -0
- package/packages/kernel/identity/domain/owned-resource.ts +116 -0
- package/packages/kernel/identity/domain/user-request.ts +93 -0
- package/packages/kernel/identity/infrastructure/activity-projection-store.ts +77 -0
- package/packages/kernel/identity/infrastructure/capability-broker.ts +81 -0
- package/packages/kernel/identity/infrastructure/grant-store.ts +284 -0
- package/packages/kernel/identity/infrastructure/owned-resource-store.ts +259 -0
- package/packages/kernel/identity/infrastructure/user-request-store.ts +182 -0
- package/packages/kernel/scheduler/api/index.ts +0 -2
- package/packages/kernel/scheduler/application/schedule-service.ts +3 -0
- package/packages/kernel/scheduler/application/settlement.ts +0 -15
- package/packages/kernel/scheduler/domain/schedule.ts +87 -0
- package/packages/kernel/scheduler/infrastructure/schedule-store.ts +153 -133
- package/packages/kernel/work/api/index.ts +3 -2
- package/packages/kernel/work/application/work-service.ts +17 -42
- package/packages/kernel/work/domain/current-task-lineage.ts +104 -0
- package/packages/kernel/work/domain/engineering-design.ts +10 -5
- package/packages/kernel/work/domain/engineering-profile.ts +8 -12
- package/packages/kernel/work/domain/evaluation-promotion-receipt.ts +186 -0
- package/packages/kernel/work/domain/execution-concurrency.ts +19 -26
- package/packages/kernel/work/domain/execution-snapshot.ts +0 -31
- package/packages/kernel/work/domain/implementation-review.ts +14 -331
- package/packages/kernel/work/domain/objective-graph.ts +119 -0
- package/packages/kernel/work/domain/project-engineering-contract.ts +23 -1
- package/packages/kernel/work/domain/repository-completion-receipt.ts +1 -1
- package/packages/kernel/work/domain/state-machine.ts +25 -63
- package/packages/kernel/work/domain/types.ts +57 -51
- package/packages/kernel/work/infrastructure/work-contract-store.ts +819 -728
- package/packages/kernel/work/ports/work-contract-store.ts +5 -2
- package/packages/plugin-runtime/browser/session-authority.ts +2 -1
- package/packages/plugin-runtime/computer/chatgpt-identity.ts +24 -0
- package/packages/plugin-runtime/computer/conversation-target.ts +143 -0
- package/packages/plugin-runtime/computer/index.ts +2 -0
- package/packages/plugin-runtime/computer/target-authority.ts +26 -1
- package/packages/plugin-runtime/external/unix-jsonl-transport.ts +142 -18
- package/packages/protocols/computer/contract.ts +27 -1
- package/scripts/activate-source-baseline.ts +7 -9
- package/scripts/canary-controller-semantic-wait.ts +12 -24
- package/scripts/check-mcp-compatibility.ts +48 -136
- package/scripts/check-runtime-architecture.mjs +622 -217
- package/scripts/forge-local-recovery-helper.mjs +93 -15
- package/scripts/lib/project-init-lib.sh +3 -0
- package/scripts/open-source-audit-allowlist.txt +1 -2
- package/scripts/run-bounded-command.mjs +5 -0
- package/scripts/run-governed-gate.ts +0 -1
- package/scripts/run-mobile-monitor-bridge.ts +0 -1
- package/scripts/smoke-control-plane-failure-domain.ts +94 -0
- package/scripts/smoke-mcp-http-runtime.ts +5 -0
- package/scripts/smoke-runtime-recovery.ts +12 -43
- package/scripts/smoke-schedule-engine.ts +23 -15
- package/scripts/smoke-unattended-transport-recovery.ts +223 -0
- package/scripts/smoke-user-request-continuation-restart.ts +232 -0
- package/scripts/smoke-workflow-supervisor-chrome-adapter.ts +92 -0
- package/scripts/smoke-workflow-supervisor-process-restart.ts +276 -0
- package/scripts/smoke-workflow-supervisor-restart-recovery.ts +150 -0
- package/scripts/smoke-workflow-supervisor.ts +103 -0
- package/scripts/verify-forge-runtime.sh +2 -1
- package/src/cli/agent-jobs/executor-health.ts +11 -34
- package/src/cli/agent-jobs/integration.ts +18 -49
- package/src/cli/agent-jobs/job-manager.ts +7 -3
- package/src/cli/commands/brain-assistant.ts +27 -13
- package/src/cli/commands/brain.ts +13 -15
- package/src/cli/commands/chatgpt.ts +1 -163
- package/src/cli/commands/recovery.ts +135 -121
- package/src/cli/commands/runtime.ts +3 -3
- package/src/cli/commands/setup-profile.ts +8 -0
- package/src/cli/controller/check-runner.ts +13 -2
- package/src/cli/controller/completion-backlog.ts +3 -3
- package/src/cli/controller/completion-orchestrator.ts +4 -43
- package/src/cli/controller/completion-target.ts +3 -72
- package/src/cli/controller/context/source-materializer.ts +81 -100
- package/src/cli/controller/context-pack.ts +10 -8
- package/src/cli/controller/execution-completion.ts +4 -7
- package/src/cli/controller/execution-policy.ts +36 -153
- package/src/cli/controller/governance.ts +2 -3
- package/src/cli/controller/issue-store.ts +4 -99
- package/src/cli/controller/launch-agents.ts +59 -18
- package/src/cli/controller/operational-plan.ts +24 -51
- package/src/cli/controller/runtime-config.ts +5 -1
- package/src/cli/controller/stuck-state-migration.ts +2 -3
- package/src/cli/controller/systemd-user.ts +39 -1
- package/src/cli/editing/edit-session.ts +1 -7
- package/src/cli/local-bridge/console-automations.ts +18 -13
- package/src/cli/local-bridge/console-view-models.ts +3 -12
- package/src/cli/local-bridge/facade-api.ts +64 -191
- package/src/cli/local-bridge/server.ts +24 -147
- package/src/cli/local-bridge/types.ts +0 -1
- package/src/cli/mcp/oauth-client-retirement.ts +74 -0
- package/src/cli/repositories/command-executor.ts +29 -23
- package/src/cli/repositories/command-scope.ts +35 -16
- package/src/cli/repositories/controller-home.ts +48 -0
- package/src/cli/repositories/ephemeral-workspace.ts +20 -30
- package/src/cli/repositories/git-command-executor.ts +2 -2
- package/src/cli/repositories/registry.ts +77 -11
- package/src/cli/repositories/structured-git.ts +62 -2
- package/src/cli/repository/session-cache.ts +92 -6
- package/src/runtime/context/assistant-context.ts +20 -7
- package/src/runtime/context/assistant-work-context.ts +89 -27
- package/src/runtime/context/automatic-learning.ts +565 -0
- package/src/runtime/context/cognitive-attention.ts +173 -0
- package/src/runtime/context/cognitive-skill-canary.ts +158 -0
- package/src/runtime/context/context-closure.ts +46 -9
- package/src/runtime/context/context-pack-process.ts +103 -0
- package/src/runtime/context/context-plane.ts +1 -9
- package/src/runtime/context/direct-controller-learning.ts +298 -0
- package/src/runtime/context/semantic-navigation-contract.ts +9 -0
- package/src/runtime/context/semantic-navigation.ts +6 -34
- package/src/runtime/context/typescript-navigation-process.ts +145 -0
- package/src/runtime/context/typescript-navigation.ts +89 -3
- package/src/runtime/control-plane/cleanup-artifact-retention.ts +212 -9
- package/src/runtime/control-plane/concurrency/work-execution-concurrency.ts +9 -47
- package/src/runtime/control-plane/execution/controller-authority-recovery.ts +34 -4
- package/src/runtime/control-plane/execution/edit-validation-coordinator.ts +29 -20
- package/src/runtime/control-plane/execution/execution-identity.ts +23 -3
- package/src/runtime/control-plane/execution/repository-work-attribution.ts +7 -30
- package/src/runtime/control-plane/execution/retained-work-resume.ts +206 -199
- package/src/runtime/control-plane/execution/session-store.ts +31 -1
- package/src/runtime/control-plane/execution/validation.ts +6 -8
- package/src/runtime/control-plane/execution/work-authority-reconciler.ts +13 -42
- package/src/runtime/control-plane/execution/work-check-evidence.ts +137 -0
- package/src/runtime/control-plane/execution/work-completion-authority.ts +30 -85
- package/src/runtime/control-plane/execution/work-delivery-service.ts +497 -0
- package/src/runtime/control-plane/execution/work-evidence-policy.ts +12 -50
- package/src/runtime/control-plane/execution/work-execution-support.ts +50 -149
- package/src/runtime/control-plane/execution/work-handle-authority.ts +188 -109
- package/src/runtime/control-plane/execution/work-handle-store.ts +19 -43
- package/src/runtime/control-plane/execution/work-head-settlement.ts +53 -20
- package/src/runtime/control-plane/execution/work-lifecycle-audit.ts +52 -29
- package/src/runtime/control-plane/execution/work-operation-service.ts +43 -27
- package/src/runtime/control-plane/execution/work-preparation-service.ts +126 -266
- package/src/runtime/control-plane/execution/work-remote-delivery.ts +2 -3
- package/src/runtime/control-plane/execution/work-revision-diff.ts +39 -0
- package/src/runtime/control-plane/execution/work-terminal-cleanup.ts +173 -186
- package/src/runtime/control-plane/execution/work-validation-reconciler.ts +28 -84
- package/src/runtime/control-plane/execution/work-verification-service.ts +406 -50
- package/src/runtime/control-plane/execution/work-verification-snapshot.ts +5 -1
- package/src/runtime/control-plane/facade/capability-registry.ts +362 -37
- package/src/runtime/control-plane/facade/check-normalization.ts +3 -9
- package/src/runtime/control-plane/facade/codex-delegation.ts +10 -11
- package/src/runtime/control-plane/facade/controller-connection.ts +135 -0
- package/src/runtime/control-plane/facade/goal-workloop-access.ts +1 -20
- package/src/runtime/control-plane/facade/goal-workloop.ts +281 -1753
- package/src/runtime/control-plane/facade/handoff-inbox-application.ts +12 -25
- package/src/runtime/control-plane/facade/handoff-inbox-store.ts +256 -52
- package/src/runtime/control-plane/facade/index.ts +0 -1
- package/src/runtime/control-plane/facade/operation-digest.ts +12 -15
- package/src/runtime/control-plane/facade/plan-contract-store.ts +451 -991
- package/src/runtime/control-plane/facade/policy-gate.ts +0 -23
- package/src/runtime/control-plane/facade/repository-work-admission.ts +12 -22
- package/src/runtime/control-plane/facade/requirement-authority.ts +102 -199
- package/src/runtime/control-plane/facade/requirement-board.ts +3 -3
- package/src/runtime/control-plane/facade/rh-work-operation-contract.ts +51 -14
- package/src/runtime/control-plane/facade/self-healing-loop.ts +18 -53
- package/src/runtime/control-plane/facade/suggested-actions.ts +15 -18
- package/src/runtime/control-plane/facade/types.ts +49 -108
- package/src/runtime/control-plane/facade/work-continuation.ts +8 -8
- package/src/runtime/control-plane/generated-cache-retention.ts +97 -1
- package/src/runtime/control-plane/global-scheduler/autonomous-continuation.ts +248 -0
- package/src/runtime/control-plane/global-scheduler/durable-admission.ts +1 -1
- package/src/runtime/control-plane/global-scheduler/maintenance.ts +239 -112
- package/src/runtime/control-plane/global-scheduler/reconciliation.ts +2 -1
- package/src/runtime/control-plane/global-scheduler/scheduler.ts +66 -40
- package/src/runtime/control-plane/global-scheduler/wake-signal.ts +42 -2
- package/src/runtime/control-plane/governance/access-policy.ts +19 -2
- package/src/runtime/control-plane/governance/authorization.ts +20 -3
- package/src/runtime/control-plane/launcher/chatgpt-round-continuation.ts +63 -300
- package/src/runtime/control-plane/launcher/chatgpt-work-continuation.ts +28 -300
- package/src/runtime/control-plane/launcher/local-conversation-controller.ts +238 -0
- package/src/runtime/control-plane/launcher/provider-mcp-bootstrap.ts +5 -2
- package/src/runtime/control-plane/launcher/thin-launcher.ts +96 -240
- package/src/runtime/control-plane/persistence/cognition-store.ts +820 -0
- package/src/runtime/control-plane/persistence/experience-store.ts +162 -29
- package/src/runtime/control-plane/persistence/requirement-store.ts +216 -74
- package/src/runtime/control-plane/persistence/sqlite-store.ts +113 -6
- package/src/runtime/control-plane/release-retention.ts +135 -47
- package/src/runtime/control-plane/repository-namespace-retention.ts +2 -2
- package/src/runtime/control-plane/runtime-cleanup.ts +290 -21
- package/src/runtime/control-plane/workspace/project-onboarding.ts +80 -0
- package/src/runtime/control-plane/workspace/semantic-sync-service.ts +19 -5
- package/src/runtime/control-plane/workspace/workspace-store.ts +169 -0
- package/src/runtime/diagnostics/incident-repair.ts +313 -146
- package/src/runtime/diagnostics/mcp-timing.ts +114 -0
- package/src/runtime/evidence/artifact-store.ts +158 -40
- package/src/runtime/evidence/evidence-store.ts +112 -8
- package/src/runtime/evidence/output-handle-index.ts +225 -0
- package/src/runtime/evidence/result-store.ts +158 -44
- package/src/runtime/execution/jobs/store.ts +3 -4
- package/src/runtime/execution/managed-workspace.ts +57 -0
- package/src/runtime/execution/process-runtime/check-facade.ts +1 -1
- package/src/runtime/execution/process-runtime/check-result-retention.ts +2 -2
- package/src/runtime/execution/process-runtime/check-result.ts +105 -1
- package/src/runtime/execution/process-runtime/check-runner-sidecar.ts +18 -8
- package/src/runtime/execution/process-runtime/command-facade.ts +79 -27
- package/src/runtime/execution/process-runtime/gc.ts +15 -2
- package/src/runtime/execution/process-runtime/handle-index.ts +176 -0
- package/src/runtime/execution/process-runtime/host-command-lane.ts +139 -0
- package/src/runtime/execution/process-runtime/index.ts +3 -0
- package/src/runtime/execution/process-runtime/lightweight-managed.ts +251 -72
- package/src/runtime/execution/process-runtime/persisted-check.ts +3 -3
- package/src/runtime/execution/process-runtime/process-runner-entry.ts +47 -5
- package/src/runtime/execution/process-runtime/process-scope.ts +160 -0
- package/src/runtime/execution/process-runtime/resource-claims.ts +65 -61
- package/src/runtime/execution/process-runtime/runtime.ts +35 -2
- package/src/runtime/execution/process-runtime/store.ts +30 -2
- package/src/runtime/execution/process-runtime/types.ts +6 -1
- package/src/runtime/execution/workers/executor.ts +2 -6
- package/src/runtime/platform/service-inventory.ts +130 -0
- package/src/runtime/platform/service-manager.ts +8 -0
- package/src/runtime/plugins/action-application.ts +85 -28
- package/src/runtime/plugins/app-store-connect-adapter.ts +38 -14
- package/src/runtime/plugins/browser-adapter.ts +757 -34
- package/src/runtime/plugins/browser-automation-service.ts +23 -3
- package/src/runtime/plugins/browser-macos-bridge.ts +321 -29
- package/src/runtime/plugins/browser-manifest-surface.ts +45 -11
- package/src/runtime/plugins/browser-native-session-service.ts +63 -13
- package/src/runtime/plugins/browser-registration.ts +16 -0
- package/src/runtime/plugins/browser-runtime.ts +14 -1
- package/src/runtime/plugins/browser-session-authority.ts +2 -2
- package/src/runtime/plugins/browser-session-store.ts +46 -76
- package/src/runtime/plugins/capability-authorization-grants.ts +258 -62
- package/src/runtime/plugins/computer-chatgpt-browser-adapter-installer.ts +219 -0
- package/src/runtime/plugins/computer-chatgpt-macos-target.ts +891 -0
- package/src/runtime/plugins/computer-registration.ts +222 -11
- package/src/runtime/plugins/desktop-operator-external-policy.ts +36 -4
- package/src/runtime/plugins/desktop-operator-registration.ts +12 -4
- package/src/runtime/plugins/external-adapter.ts +42 -6
- package/src/runtime/plugins/external-registration.ts +21 -1
- package/src/runtime/plugins/gmail-adapter.ts +23 -2
- package/src/runtime/plugins/google-calendar-adapter.ts +2 -2
- package/src/runtime/plugins/google-shared.ts +14 -7
- package/src/runtime/plugins/google-tasks-adapter.ts +2 -2
- package/src/runtime/plugins/ios-adapter.ts +1 -1
- package/src/runtime/plugins/lightweight-action.ts +208 -2
- package/src/runtime/plugins/local-system-adapter.ts +12 -2
- package/src/runtime/plugins/managed-process-adapter.ts +12 -5
- package/src/runtime/plugins/plugin-action-sidecar.ts +17 -13
- package/src/runtime/plugins/plugin-management-adapter.ts +1 -1
- package/src/runtime/plugins/store.ts +602 -428
- package/src/runtime/plugins/types.ts +20 -0
- package/src/runtime/plugins/xiaohongshu-publish.ts +16 -0
- package/src/runtime/projections/invalidation.ts +7 -3
- package/src/runtime/projections/materialized-view.ts +80 -36
- package/src/runtime/recovery/actions.ts +3 -3
- package/src/runtime/recovery/capability-action-application.ts +46 -45
- package/src/runtime/recovery/lifecycle-inventory.ts +29 -29
- package/src/runtime/recovery/maintenance-executor.ts +374 -123
- package/src/runtime/recovery/store.ts +29 -11
- package/src/runtime/release/release-coordinator.ts +296 -0
- package/src/runtime/release/release-session.ts +716 -0
- package/src/runtime/release/release-state-migration.ts +25 -0
- package/src/runtime/resources/leases/store.ts +56 -25
- package/src/runtime/root/computer-composition.ts +191 -6
- package/src/runtime/root/controller-progression-composition.ts +192 -0
- package/src/runtime/root/controller-round-composition.ts +20 -1
- package/src/runtime/root/deployment-topology.ts +106 -0
- package/src/runtime/root/entry.ts +4 -3
- package/src/runtime/root/known-good-recovery.ts +184 -0
- package/src/runtime/root/local-bridge.ts +0 -1
- package/src/runtime/root/mcp-transport.ts +111 -18
- package/src/runtime/root/ownership.ts +261 -9
- package/src/runtime/root/package-connector-service.ts +105 -19
- package/src/runtime/root/package-runtime-release.ts +117 -18
- package/src/runtime/root/package-runtime-service.ts +17 -11
- package/src/runtime/root/release-execution-canary.ts +44 -12
- package/src/runtime/root/release-loader.ts +90 -8
- package/src/runtime/root/release-manifest.ts +80 -6
- package/src/runtime/root/release-materialize.ts +372 -28
- package/src/runtime/root/release-store.ts +395 -36
- package/src/runtime/root/runtime-lane.ts +191 -0
- package/src/runtime/root/runtime.ts +159 -27
- package/src/runtime/root/scheduled-controller-composition.ts +28 -3
- package/src/runtime/root/service-runner.ts +2 -2
- package/src/runtime/root/service.ts +36 -33
- package/src/runtime/root/status.ts +48 -0
- package/src/runtime/root/types.ts +32 -3
- package/src/runtime/root/workflow-supervisor-composition.ts +493 -0
- package/src/runtime/root/workflow-supervisor-runtime.ts +209 -0
- package/src/runtime/root/write-fence.ts +50 -2
- package/src/runtime/safe-tooling/google-credential-store.ts +76 -21
- package/src/runtime/safe-tooling/google-oauth-broker.ts +25 -7
- package/src/runtime/safe-tooling/workspace-auth.ts +1 -1
- package/src/runtime/shared/bounded-child-supervisor.ts +9 -1
- package/src/runtime/shared/process-environment.ts +20 -9
- package/src/runtime/shared/response-budget.ts +1 -3
- package/src/runtime/standalone-recovery/controller-home-migration.ts +16 -24
- package/src/runtime/standalone-recovery/core.ts +3702 -342
- package/src/runtime/standalone-recovery/entry.ts +469 -39
- package/src/runtime/standalone-recovery/installer.ts +262 -148
- package/src/runtime/standalone-recovery/mcp-server.ts +29 -193
- package/src/runtime/standalone-recovery/operation-lock.ts +1 -1
- package/src/runtime/standalone-recovery/performance.ts +54 -16
- package/src/runtime/standalone-recovery/release.ts +53 -5
- package/src/runtime/standalone-recovery/service-labels.ts +5 -2
- package/src/runtime/standalone-recovery/watchdog-heartbeat.ts +5 -2
- package/src/runtime/workflow/schedules/browser-probe.ts +17 -6
- package/src/runtime/workflow/schedules/chatgpt-automation-migration.ts +10 -3
- package/src/runtime/workflow/schedules/engine.ts +138 -172
- package/src/runtime/workflow/schedules/work-continuation.ts +44 -5
- package/src/runtime/workflows/runtime.ts +15 -19
- package/src/testing/test-governance.ts +5 -1
- package/supervisor/chatgpt-conversation.ts +23 -0
- package/supervisor/client.ts +201 -0
- package/supervisor/control-plane.ts +868 -0
- package/supervisor/entry.ts +15 -0
- package/supervisor/forge-validators.ts +80 -0
- package/supervisor/index.ts +5 -0
- package/supervisor/native-browser-adapter.ts +786 -0
- package/supervisor/native-messaging/host.ts +39 -0
- package/supervisor/native-messaging/manifest.ts +26 -0
- package/supervisor/native-messaging/protocol.ts +27 -0
- package/supervisor/paths.ts +18 -0
- package/supervisor/protocol.ts +202 -0
- package/supervisor/server.ts +404 -0
- package/supervisor/store.ts +1451 -0
- package/supervisor/tsconfig.json +8 -0
- package/supervisor/types.ts +255 -0
- package/adapters/chatgpt/controller-host.ts +0 -119
- package/adapters/mcp/controller-round-compatibility.ts +0 -184
- package/adapters/mcp/frozen-client-semantic-compatibility.ts +0 -292
- package/adapters/mcp/runtime-gateway/work-compat-adapter.ts +0 -502
- package/packages/kernel/progression/api/index.ts +0 -2
- package/packages/kernel/progression/application/projector.ts +0 -211
- package/packages/kernel/progression/domain/types.ts +0 -116
- package/packages/kernel/progression/index.ts +0 -1
- package/packages/kernel/scheduler/application/continuation-service.ts +0 -212
- package/packages/kernel/scheduler/domain/continuation.ts +0 -38
- package/packages/kernel/scheduler/infrastructure/continuation-dispatch-store.ts +0 -38
- package/packages/kernel/work/domain/admission-policy.ts +0 -34
- package/scripts/benchmark-background-check-overlap.ts +0 -228
- package/scripts/benchmark-computer-hotpath.ts +0 -255
- package/scripts/benchmark-controller-hotpath.ts +0 -212
- package/scripts/benchmark-controller-round2.ts +0 -191
- package/scripts/benchmark-ios-agent-device.ts +0 -511
- package/scripts/benchmark-mcp-host.sh +0 -117
- package/scripts/benchmark-mcp-transport.ts +0 -169
- package/scripts/benchmark-operational-memory-activation.ts +0 -235
- package/scripts/benchmark-operational-shadow.ts +0 -28
- package/scripts/benchmark-quality-harness.ts +0 -146
- package/scripts/benchmark-route-session-concurrency.ts +0 -915
- package/scripts/benchmark-thin-harness-gateway-ab.ts +0 -632
- package/scripts/benchmark-thin-harness-mcp-e2e.ts +0 -498
- package/scripts/benchmark-thin-harness.ts +0 -251
- package/scripts/benchmark-typescript-navigation.ts +0 -186
- package/scripts/benchmark-work-efficiency.ts +0 -334
- package/scripts/build-controller-ui.ts +0 -28
- package/scripts/check-npm-release.sh +0 -32
- package/scripts/check-public-release-surface.sh +0 -19
- package/scripts/check-release-published.sh +0 -57
- package/scripts/check-release-readiness.sh +0 -37
- package/scripts/check-release-version.mjs +0 -74
- package/scripts/check-tarball-install-smoke.sh +0 -150
- package/scripts/package-source-archive.sh +0 -147
- package/scripts/public-release-files.txt +0 -39
- package/scripts/public-release.ts +0 -174
- package/scripts/publish-release-tarball.sh +0 -27
- package/scripts/route-nl-vs-ts-eval.ts +0 -679
- package/scripts/stage-runtime-release.ts +0 -44
- package/src/cli/controller/progress.ts +0 -656
- package/src/cli/controller/work-mode.ts +0 -181
- package/src/cli/local-bridge/console-assets.ts +0 -17
- package/src/cli/local-bridge/dashboard.ts +0 -17
- package/src/cli/local-bridge/frontend/src/App.tsx +0 -10
- package/src/cli/local-bridge/frontend/src/components/Button.tsx +0 -1
- package/src/cli/local-bridge/frontend/src/components/DetailPane.tsx +0 -3
- package/src/cli/local-bridge/frontend/src/components/SearchField.tsx +0 -1
- package/src/cli/local-bridge/frontend/src/components/SectionHeader.tsx +0 -1
- package/src/cli/local-bridge/frontend/src/components/Segmented.tsx +0 -1
- package/src/cli/local-bridge/frontend/src/components/StatusText.tsx +0 -3
- package/src/cli/local-bridge/frontend/src/design/icons.tsx +0 -11
- package/src/cli/local-bridge/frontend/src/design/tokens.css +0 -8
- package/src/cli/local-bridge/frontend/src/features/automations/AutomationsView.tsx +0 -153
- package/src/cli/local-bridge/frontend/src/features/capabilities/CapabilitiesView.tsx +0 -37
- package/src/cli/local-bridge/frontend/src/features/overview/OverviewView.tsx +0 -183
- package/src/cli/local-bridge/frontend/src/features/repositories/RepositoriesView.tsx +0 -2
- package/src/cli/local-bridge/frontend/src/features/system/SystemView.tsx +0 -2
- package/src/cli/local-bridge/frontend/src/features/work/WorkView.tsx +0 -4
- package/src/cli/local-bridge/frontend/src/lib/api.ts +0 -30
- package/src/cli/local-bridge/frontend/src/lib/format.ts +0 -4
- package/src/cli/local-bridge/frontend/src/lib/routes.ts +0 -7
- package/src/cli/local-bridge/frontend/src/main.tsx +0 -1
- package/src/cli/local-bridge/frontend/src/shell/AppShell.tsx +0 -1
- package/src/cli/local-bridge/frontend/src/shell/CommandBar.tsx +0 -2
- package/src/cli/local-bridge/frontend/src/shell/Sidebar.tsx +0 -4
- package/src/cli/local-bridge/frontend/src/styles.css +0 -28
- package/src/cli/local-bridge/frontend/src/types.ts +0 -15
- package/src/cli/local-bridge/frontend/src/vite-env.d.ts +0 -1
- package/src/cli/local-bridge/frontend/vite.config.ts +0 -27
- package/src/cli/local-bridge/ui-dist/app.css +0 -1
- package/src/cli/local-bridge/ui-dist/app.js +0 -11228
- package/src/runtime/control-plane/execution/content-equivalent-commit-authority.ts +0 -169
- package/src/runtime/control-plane/execution/direct-canonical-work-reconciliation.ts +0 -85
- package/src/runtime/control-plane/execution/direct-edit-work-completion.ts +0 -655
- package/src/runtime/control-plane/execution/work-finalization-service.ts +0 -2850
- package/src/runtime/control-plane/execution/work-path-scope.ts +0 -37
- package/src/runtime/control-plane/execution/work-task-receipt.ts +0 -468
- package/src/runtime/control-plane/facade/controller-round-relay.ts +0 -3
- package/src/runtime/control-plane/facade/work-admission-policy.ts +0 -142
- package/src/runtime/control-plane/facade/work-implementation-review.ts +0 -2
- package/src/runtime/control-plane/facade/work-state-machine.ts +0 -2
- package/src/runtime/control-plane/facade/work-task-projection.ts +0 -66
- package/src/runtime/control-plane/routing/index.ts +0 -1
- package/src/runtime/control-plane/routing/route-policy.ts +0 -401
- package/src/runtime/control-plane/routing/workspace-admission.ts +0 -70
|
@@ -19,8 +19,7 @@ import {
|
|
|
19
19
|
} from '../repositories/controller-home';
|
|
20
20
|
import { FORGE_VERSION } from '../../version';
|
|
21
21
|
import {
|
|
22
|
-
|
|
23
|
-
RECOVERY_WATCHDOG_LABEL,
|
|
22
|
+
RECOVERY_DAEMON_LABEL,
|
|
24
23
|
inspectRecoveryTunnelLaunchdContract,
|
|
25
24
|
installStandaloneRecovery,
|
|
26
25
|
recoveryLaunchdPid,
|
|
@@ -37,6 +36,7 @@ import {
|
|
|
37
36
|
activateRuntimeRelease,
|
|
38
37
|
defaultPrimaryRuntimeServiceConfig,
|
|
39
38
|
loadRecoveryConfig,
|
|
39
|
+
normalizeRecoveryInstallProfile,
|
|
40
40
|
recoverPrimaryRuntime,
|
|
41
41
|
recoveryMachineIdentity,
|
|
42
42
|
restartPrimaryConnector,
|
|
@@ -149,12 +149,57 @@ export type { RecoveryControllerHomeMigrationPreflight };
|
|
|
149
149
|
export interface RecoveryConnectorDependencies {
|
|
150
150
|
platform?: NodeJS.Platform;
|
|
151
151
|
pathExists?: (path: string) => boolean;
|
|
152
|
-
launchdPid?: (role: '
|
|
153
|
-
systemdPid?: (role: '
|
|
152
|
+
launchdPid?: (role: 'daemon') => number | undefined;
|
|
153
|
+
systemdPid?: (role: 'daemon') => number | undefined;
|
|
154
154
|
tunnelLaunchdPid?: (label: string) => number | undefined;
|
|
155
155
|
tunnelSystemdPid?: (unitName: string) => number | undefined;
|
|
156
156
|
openAiTunnelStatus?: (service: OpenAiSecureTunnelServiceConfig) => OpenAiSecureTunnelRuntimeObservation;
|
|
157
157
|
processAlive?: (pid: number) => boolean;
|
|
158
|
+
processParentPid?: (pid: number) => number | undefined;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
function recoveryProcessParentPid(pid: number): number | undefined {
|
|
162
|
+
if (process.platform === 'win32' || !Number.isInteger(pid) || pid <= 1) return undefined;
|
|
163
|
+
const result = spawnSync('ps', ['-o', 'ppid=', '-p', String(pid)], {
|
|
164
|
+
encoding: 'utf8',
|
|
165
|
+
timeout: 2_000,
|
|
166
|
+
maxBuffer: 8 * 1024,
|
|
167
|
+
});
|
|
168
|
+
if (result.status !== 0) return undefined;
|
|
169
|
+
const parent = Number.parseInt((result.stdout ?? '').trim(), 10);
|
|
170
|
+
return Number.isInteger(parent) && parent > 0 ? parent : undefined;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
/**
|
|
174
|
+
* launchd may own a tiny wrapper (/usr/bin/env) while Recovery records the
|
|
175
|
+
* compiled child PID in its runtime identity. Treat only that bounded process
|
|
176
|
+
* lineage as the same managed service; unrelated live PIDs still fail closed.
|
|
177
|
+
*/
|
|
178
|
+
export function recoveryManagedServiceOwnsRuntimeProcess(
|
|
179
|
+
managedPid: number | undefined,
|
|
180
|
+
runtimePid: number | undefined,
|
|
181
|
+
dependencies: {
|
|
182
|
+
processAlive?: (pid: number) => boolean;
|
|
183
|
+
processParentPid?: (pid: number) => number | undefined;
|
|
184
|
+
maxDepth?: number;
|
|
185
|
+
} = {},
|
|
186
|
+
): boolean {
|
|
187
|
+
if (!managedPid || !runtimePid || managedPid <= 0 || runtimePid <= 0) return false;
|
|
188
|
+
const processAlive = dependencies.processAlive ?? isProcessAlive;
|
|
189
|
+
if (!processAlive(managedPid) || !processAlive(runtimePid)) return false;
|
|
190
|
+
if (managedPid === runtimePid) return true;
|
|
191
|
+
const parentPid = dependencies.processParentPid ?? recoveryProcessParentPid;
|
|
192
|
+
const maxDepth = Math.max(1, Math.min(Math.trunc(dependencies.maxDepth ?? 8), 32));
|
|
193
|
+
const visited = new Set<number>([runtimePid]);
|
|
194
|
+
let current = runtimePid;
|
|
195
|
+
for (let depth = 0; depth < maxDepth; depth += 1) {
|
|
196
|
+
const parent = parentPid(current);
|
|
197
|
+
if (!parent || parent <= 0 || visited.has(parent)) return false;
|
|
198
|
+
if (parent === managedPid) return true;
|
|
199
|
+
visited.add(parent);
|
|
200
|
+
current = parent;
|
|
201
|
+
}
|
|
202
|
+
return false;
|
|
158
203
|
}
|
|
159
204
|
|
|
160
205
|
export interface RecoveryConnectorDescriptor {
|
|
@@ -174,8 +219,7 @@ export interface RecoveryConnectorDescriptor {
|
|
|
174
219
|
};
|
|
175
220
|
healthUrl: string;
|
|
176
221
|
services: {
|
|
177
|
-
|
|
178
|
-
watchdog: { label: string; platform: 'launchd' | 'systemd-user'; serviceInstalled: boolean; plistInstalled: boolean; running: boolean; pid?: number };
|
|
222
|
+
recovery: { label: string; platform: 'launchd' | 'systemd-user'; serviceInstalled: boolean; plistInstalled: boolean; running: boolean; pid?: number };
|
|
179
223
|
tunnel: {
|
|
180
224
|
configured: boolean;
|
|
181
225
|
platform?: 'launchd' | 'systemd-user' | 'openai-secure-tunnel';
|
|
@@ -208,15 +252,19 @@ export function recoveryConnectorDescriptor(
|
|
|
208
252
|
const url = configuredUrl ?? `${localOrigin}/recovery/mcp`;
|
|
209
253
|
const origin = new URL(url).origin;
|
|
210
254
|
const passphraseConfigured = Boolean(readMcpServiceOAuthPassphrase(home));
|
|
211
|
-
const
|
|
212
|
-
const watchdogIdentity = readRecoveryRuntimeIdentity(home, 'watchdog');
|
|
255
|
+
const recoveryIdentity = readRecoveryRuntimeIdentity(home, 'daemon');
|
|
213
256
|
const platform = dependencies.platform ?? process.platform;
|
|
214
257
|
const servicePlatform: 'launchd' | 'systemd-user' = platform === 'linux' ? 'systemd-user' : 'launchd';
|
|
215
258
|
const pathExists = dependencies.pathExists ?? existsSync;
|
|
216
259
|
const launchdPid = dependencies.launchdPid ?? recoveryLaunchdPid;
|
|
217
|
-
const systemdPid = dependencies.systemdPid ?? ((
|
|
218
|
-
const managedPid = (
|
|
260
|
+
const systemdPid = dependencies.systemdPid ?? ((_role: 'daemon') => systemdUserServicePid(RECOVERY_DAEMON_LABEL));
|
|
261
|
+
const managedPid = () => servicePlatform === 'systemd-user' ? systemdPid('daemon') : launchdPid('daemon');
|
|
219
262
|
const processAlive = dependencies.processAlive ?? isProcessAlive;
|
|
263
|
+
const serviceOwnsRuntimeProcess = (managedPid: number | undefined, runtimePid: number | undefined) =>
|
|
264
|
+
recoveryManagedServiceOwnsRuntimeProcess(managedPid, runtimePid, {
|
|
265
|
+
processAlive,
|
|
266
|
+
processParentPid: dependencies.processParentPid,
|
|
267
|
+
});
|
|
220
268
|
const configuredTunnel = config.recoveryTunnelService;
|
|
221
269
|
const tunnelService = configuredTunnel?.platform === 'launchd' ? configuredTunnel : undefined;
|
|
222
270
|
const systemdTunnelService = configuredTunnel?.platform === 'systemd-user' ? configuredTunnel : undefined;
|
|
@@ -256,40 +304,24 @@ export function recoveryConnectorDescriptor(
|
|
|
256
304
|
: Boolean(tunnelLaunchdPid && processAlive(tunnelLaunchdPid));
|
|
257
305
|
const tunnelHealthy = openAiTunnelService ? openAiTunnelStatus?.healthy === true : tunnelRunning;
|
|
258
306
|
const tunnelReady = openAiTunnelService ? openAiTunnelStatus?.ok === true : tunnelRestartSafe && tunnelRunning;
|
|
259
|
-
const
|
|
260
|
-
const
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
const
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
const gatewayManagedPid = managedPid('gateway');
|
|
268
|
-
const watchdogManagedPid = managedPid('watchdog');
|
|
269
|
-
const gatewayRunning = Boolean(
|
|
270
|
-
gatewayIdentity
|
|
271
|
-
&& gatewayManagedPid
|
|
272
|
-
&& gatewayIdentity.pid === gatewayManagedPid
|
|
273
|
-
&& processAlive(gatewayIdentity.pid)
|
|
307
|
+
const recoveryPlistInstalled = pathExists(authority.daemonLaunchAgent);
|
|
308
|
+
const recoveryServiceInstalled = servicePlatform === 'systemd-user'
|
|
309
|
+
? pathExists(systemdUserUnitPath(RECOVERY_DAEMON_LABEL))
|
|
310
|
+
: recoveryPlistInstalled;
|
|
311
|
+
const recoveryManagedPid = managedPid();
|
|
312
|
+
const recoveryRunning = Boolean(
|
|
313
|
+
recoveryIdentity
|
|
314
|
+
&& serviceOwnsRuntimeProcess(recoveryManagedPid, recoveryIdentity.pid)
|
|
274
315
|
&& authority.current
|
|
275
|
-
&&
|
|
276
|
-
&&
|
|
316
|
+
&& recoveryIdentity.releaseRevision === authority.current.releaseRevision
|
|
317
|
+
&& recoveryIdentity.manifestSha256 === authority.current.manifestSha256,
|
|
277
318
|
);
|
|
278
|
-
const
|
|
279
|
-
watchdogIdentity
|
|
280
|
-
&& watchdogManagedPid
|
|
281
|
-
&& watchdogIdentity.pid === watchdogManagedPid
|
|
282
|
-
&& processAlive(watchdogIdentity.pid)
|
|
283
|
-
&& authority.current
|
|
284
|
-
&& watchdogIdentity.releaseRevision === authority.current.releaseRevision
|
|
285
|
-
&& watchdogIdentity.manifestSha256 === authority.current.manifestSha256,
|
|
286
|
-
);
|
|
287
|
-
const installed = Boolean(authority.current && gatewayServiceInstalled && watchdogServiceInstalled);
|
|
319
|
+
const installed = Boolean(authority.current && recoveryServiceInstalled);
|
|
288
320
|
const publicEndpoint = Boolean(configuredUrl?.startsWith('https://'));
|
|
289
321
|
const warnings: string[] = [];
|
|
290
322
|
if (!authority.current) warnings.push('No current immutable Forge Recovery release is installed. Run forge recovery install.');
|
|
291
|
-
if (!
|
|
292
|
-
if (!
|
|
323
|
+
if (!recoveryServiceInstalled) warnings.push(`Forge Recovery ${servicePlatform} service is not installed. Run forge recovery install.`);
|
|
324
|
+
if (!recoveryRunning) warnings.push('Forge Recovery service is not running on the current Recovery release.');
|
|
293
325
|
if (!configuredTunnel) warnings.push('Recovery is loopback-only. Configure a dedicated OpenAI Secure MCP Tunnel or an HTTPS tunnel service before adding it to ChatGPT.');
|
|
294
326
|
else if (openAiTunnelService) {
|
|
295
327
|
if (!tunnelRestartSafe) warnings.push('The dedicated OpenAI Recovery tunnel must use a valid alias, tunnel id, loopback MCP endpoint, and env:/file: runtime API key reference.');
|
|
@@ -310,7 +342,7 @@ export function recoveryConnectorDescriptor(
|
|
|
310
342
|
transport: 'streamable_http',
|
|
311
343
|
url,
|
|
312
344
|
public: publicEndpoint,
|
|
313
|
-
readyForChatGPT: installed &&
|
|
345
|
+
readyForChatGPT: installed && recoveryRunning && tunnelReady && (openAiTunnelService ? true : publicEndpoint) && passphraseConfigured,
|
|
314
346
|
installed,
|
|
315
347
|
currentRelease: authority.current?.releaseRevision,
|
|
316
348
|
previousRelease: authority.previous?.releaseRevision,
|
|
@@ -321,21 +353,13 @@ export function recoveryConnectorDescriptor(
|
|
|
321
353
|
},
|
|
322
354
|
healthUrl: `${origin}/recovery/health`,
|
|
323
355
|
services: {
|
|
324
|
-
|
|
325
|
-
label:
|
|
326
|
-
platform: servicePlatform,
|
|
327
|
-
serviceInstalled: gatewayServiceInstalled,
|
|
328
|
-
plistInstalled: gatewayPlistInstalled,
|
|
329
|
-
running: gatewayRunning,
|
|
330
|
-
...(gatewayIdentity ? { pid: gatewayIdentity.pid } : {}),
|
|
331
|
-
},
|
|
332
|
-
watchdog: {
|
|
333
|
-
label: RECOVERY_WATCHDOG_LABEL,
|
|
356
|
+
recovery: {
|
|
357
|
+
label: RECOVERY_DAEMON_LABEL,
|
|
334
358
|
platform: servicePlatform,
|
|
335
|
-
serviceInstalled:
|
|
336
|
-
plistInstalled:
|
|
337
|
-
running:
|
|
338
|
-
...(
|
|
359
|
+
serviceInstalled: recoveryServiceInstalled,
|
|
360
|
+
plistInstalled: recoveryPlistInstalled,
|
|
361
|
+
running: recoveryRunning,
|
|
362
|
+
...(recoveryIdentity ? { pid: recoveryIdentity.pid } : {}),
|
|
339
363
|
},
|
|
340
364
|
tunnel: {
|
|
341
365
|
configured: Boolean(configuredTunnel),
|
|
@@ -603,7 +627,6 @@ export async function verifyRecoveryConnector(
|
|
|
603
627
|
credentialRetirement: 'shared_recovery_token_not_individually_revocable',
|
|
604
628
|
};
|
|
605
629
|
|
|
606
|
-
let mcpSessionId: string | undefined;
|
|
607
630
|
const rpc = async (id: number | undefined, method: string, params?: Record<string, unknown>) => {
|
|
608
631
|
const response = await request(connector.url, {
|
|
609
632
|
method: 'POST',
|
|
@@ -612,10 +635,12 @@ export async function verifyRecoveryConnector(
|
|
|
612
635
|
accept: 'application/json, text/event-stream',
|
|
613
636
|
'content-type': 'application/json',
|
|
614
637
|
'mcp-protocol-version': '2025-06-18',
|
|
615
|
-
...(mcpSessionId ? { 'mcp-session-id': mcpSessionId } : {}),
|
|
616
638
|
},
|
|
617
639
|
body: JSON.stringify({ jsonrpc: '2.0', ...(id === undefined ? {} : { id }), method, ...(params ? { params } : {}) }),
|
|
618
640
|
});
|
|
641
|
+
if (response.headers.get('mcp-session-id')?.trim()) {
|
|
642
|
+
throw new Error(`${method} unexpectedly established transport session state`);
|
|
643
|
+
}
|
|
619
644
|
if (method === 'notifications/initialized') {
|
|
620
645
|
if (response.status !== 202) throw new Error(`${method} HTTP ${response.status}`);
|
|
621
646
|
return { response, result: {} as Record<string, unknown> };
|
|
@@ -625,71 +650,44 @@ export async function verifyRecoveryConnector(
|
|
|
625
650
|
if (response.status !== 200 || Object.keys(rpcError).length > 0) {
|
|
626
651
|
throw new Error(`${method} HTTP ${response.status}${typeof rpcError.message === 'string' ? `: ${rpcError.message}` : ''}`);
|
|
627
652
|
}
|
|
628
|
-
if (method === 'initialize') {
|
|
629
|
-
const returnedSessionId = response.headers.get('mcp-session-id')?.trim();
|
|
630
|
-
if (!returnedSessionId) throw new Error('initialize HTTP 200: Mcp-Session-Id missing');
|
|
631
|
-
mcpSessionId = returnedSessionId;
|
|
632
|
-
}
|
|
633
653
|
return { response, result: jsonObject(body.result) };
|
|
634
654
|
};
|
|
635
|
-
const closeMcpSession = async (): Promise<void> => {
|
|
636
|
-
const sessionId = mcpSessionId;
|
|
637
|
-
if (!sessionId) return;
|
|
638
|
-
mcpSessionId = undefined;
|
|
639
|
-
try {
|
|
640
|
-
await request(connector.url, {
|
|
641
|
-
method: 'DELETE',
|
|
642
|
-
headers: {
|
|
643
|
-
authorization: `Bearer ${accessToken}`,
|
|
644
|
-
accept: 'application/json, text/event-stream',
|
|
645
|
-
'mcp-protocol-version': '2025-06-18',
|
|
646
|
-
'mcp-session-id': sessionId,
|
|
647
|
-
},
|
|
648
|
-
});
|
|
649
|
-
} catch {
|
|
650
|
-
// Session cleanup is best-effort and must not hide the verifier result.
|
|
651
|
-
}
|
|
652
|
-
};
|
|
653
655
|
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
if (!mcpOk) failures.push('mcp: initialize, Forge version, tool surface, or read-only calls did not match the Recovery contract.');
|
|
690
|
-
} finally {
|
|
691
|
-
await closeMcpSession();
|
|
692
|
-
}
|
|
656
|
+
const initialized = await rpc(11, 'initialize', {
|
|
657
|
+
protocolVersion: '2025-06-18',
|
|
658
|
+
capabilities: {},
|
|
659
|
+
clientInfo: { name: 'forge-recovery-verifier', version: FORGE_VERSION },
|
|
660
|
+
});
|
|
661
|
+
const initializedNotification = await rpc(undefined, 'notifications/initialized');
|
|
662
|
+
const listed = await rpc(12, 'tools/list');
|
|
663
|
+
const tools = Array.isArray(listed.result.tools)
|
|
664
|
+
? listed.result.tools.map((tool) => jsonObject(tool).name).filter((name): name is string => typeof name === 'string')
|
|
665
|
+
: [];
|
|
666
|
+
const expectedTools = RECOVERY_TOOLS.map((tool) => tool.name);
|
|
667
|
+
const runtimeStatusCall = await rpc(13, 'tools/call', { name: 'runtime_status', arguments: {} });
|
|
668
|
+
const listReleasesCall = await rpc(14, 'tools/call', { name: 'list_releases', arguments: {} });
|
|
669
|
+
const initializedResult = initialized.result;
|
|
670
|
+
const serverInfo = jsonObject(initializedResult.serverInfo);
|
|
671
|
+
const mcpOk = initialized.response.status === 200
|
|
672
|
+
&& initializedNotification.response.status === 202
|
|
673
|
+
&& initializedResult.protocolVersion === '2025-06-18'
|
|
674
|
+
&& serverInfo.name === 'forge-standalone-recovery'
|
|
675
|
+
&& serverInfo.version === FORGE_VERSION
|
|
676
|
+
&& JSON.stringify(tools) === JSON.stringify(expectedTools)
|
|
677
|
+
&& runtimeStatusCall.response.status === 200
|
|
678
|
+
&& listReleasesCall.response.status === 200;
|
|
679
|
+
probes.mcp = {
|
|
680
|
+
ok: mcpOk,
|
|
681
|
+
initializeStatus: initialized.response.status,
|
|
682
|
+
initializedNotificationStatus: initializedNotification.response.status,
|
|
683
|
+
protocolVersion: typeof initializedResult.protocolVersion === 'string' ? initializedResult.protocolVersion : undefined,
|
|
684
|
+
serverName: typeof serverInfo.name === 'string' ? serverInfo.name : undefined,
|
|
685
|
+
serverVersion: typeof serverInfo.version === 'string' ? serverInfo.version : undefined,
|
|
686
|
+
tools,
|
|
687
|
+
runtimeStatusCall: runtimeStatusCall.response.status === 200,
|
|
688
|
+
listReleasesCall: listReleasesCall.response.status === 200,
|
|
689
|
+
};
|
|
690
|
+
if (!mcpOk) failures.push('mcp: stateless initialize, Forge version, tool surface, or read-only calls did not match the Recovery contract.');
|
|
693
691
|
} catch (error) {
|
|
694
692
|
failures.push(`oauthPkce/mcp: ${error instanceof Error ? error.message : String(error)}`);
|
|
695
693
|
}
|
|
@@ -761,6 +759,10 @@ export function buildRecoveryCommand(): Command {
|
|
|
761
759
|
}) => {
|
|
762
760
|
const home = resolveControllerHome(opts.controllerHome);
|
|
763
761
|
const repoRoot = resolve(opts.repo);
|
|
762
|
+
const primaryRuntimeSourceRepository = findRegisteredRepositoryByCheckoutRoot(repoRoot, home);
|
|
763
|
+
if (!primaryRuntimeSourceRepository) {
|
|
764
|
+
throw new Error(`RECOVERY_PRIMARY_RUNTIME_SOURCE_REPOSITORY_NOT_REGISTERED: ${repoRoot}`);
|
|
765
|
+
}
|
|
764
766
|
const current = loadRecoveryConfig(home);
|
|
765
767
|
const primaryConnectorBase = launchdService(
|
|
766
768
|
opts.primaryConnectorServiceLabel,
|
|
@@ -774,6 +776,7 @@ export function buildRecoveryCommand(): Command {
|
|
|
774
776
|
const installed = await installStandaloneRecovery({
|
|
775
777
|
controllerHome: home,
|
|
776
778
|
repoRoot,
|
|
779
|
+
primaryRuntimeSourceRepositoryId: primaryRuntimeSourceRepository.repoId,
|
|
777
780
|
port: current.gateway?.port ?? 8787,
|
|
778
781
|
publicMcpUrl: current.publicMcpUrl,
|
|
779
782
|
recoveryPublicUrl: current.recoveryPublicUrl,
|
|
@@ -781,6 +784,7 @@ export function buildRecoveryCommand(): Command {
|
|
|
781
784
|
primaryPublicTunnelService: current.primaryPublicTunnelService,
|
|
782
785
|
primaryRuntimeService: current.primaryRuntimeService ?? defaultPrimaryRuntimeServiceConfig(),
|
|
783
786
|
primaryConnectorService,
|
|
787
|
+
profile: 'self-healing',
|
|
784
788
|
});
|
|
785
789
|
const refreshed = loadRecoveryConfig(home);
|
|
786
790
|
const runtime = await stageAndActivateConfiguredRuntimeRelease(refreshed);
|
|
@@ -952,8 +956,9 @@ export function buildRecoveryCommand(): Command {
|
|
|
952
956
|
});
|
|
953
957
|
|
|
954
958
|
command.command('install')
|
|
955
|
-
.description('Build and activate the
|
|
959
|
+
.description('Build Forge Recovery artifacts and activate only the explicitly selected persistent Recovery profile')
|
|
956
960
|
.requiredOption('--controller-home <path>', 'Explicit Controller Home')
|
|
961
|
+
.option('--profile <profile>', 'Recovery install profile: manual, gateway, or self-healing', 'manual')
|
|
957
962
|
.option('--port <port>', 'Loopback Recovery Gateway port', '8787')
|
|
958
963
|
.option('--public-mcp-url <url>', 'Primary Forge MCP public URL')
|
|
959
964
|
.option('--recovery-public-url <url>', 'Dedicated Forge Recovery MCP public URL')
|
|
@@ -978,7 +983,7 @@ export function buildRecoveryCommand(): Command {
|
|
|
978
983
|
.option('--primary-openai-profile-dir <path>', 'Optional absolute tunnel-client profile directory for primary Forge')
|
|
979
984
|
.option('--primary-openai-admin-profile <profile>', 'Optional tunnel-client admin profile used for primary runtime connect')
|
|
980
985
|
.option('--primary-runtime-source-root <path>', 'Stable canonical/package source used by Recovery for future Runtime staging')
|
|
981
|
-
.option('--stage-only', '
|
|
986
|
+
.option('--stage-only', 'Compatibility alias: build/canary only and do not mutate installed Recovery config or services')
|
|
982
987
|
.action(async (opts: {
|
|
983
988
|
controllerHome: string;
|
|
984
989
|
port: string;
|
|
@@ -1005,9 +1010,12 @@ export function buildRecoveryCommand(): Command {
|
|
|
1005
1010
|
primaryOpenaiProfileDir?: string;
|
|
1006
1011
|
primaryOpenaiAdminProfile?: string;
|
|
1007
1012
|
primaryRuntimeSourceRoot?: string;
|
|
1013
|
+
profile: string;
|
|
1008
1014
|
stageOnly?: boolean;
|
|
1009
1015
|
}) => {
|
|
1010
1016
|
const home = resolveControllerHome(opts.controllerHome);
|
|
1017
|
+
const profile = normalizeRecoveryInstallProfile(opts.stageOnly ? 'manual' : opts.profile, 'manual');
|
|
1018
|
+
if (opts.stageOnly && opts.profile !== 'manual') throw new Error('RECOVERY_STAGE_ONLY_PROFILE_CONFLICT');
|
|
1011
1019
|
const port = Number(opts.port);
|
|
1012
1020
|
if (!Number.isInteger(port) || port < 1024 || port > 65535) throw new Error('RECOVERY_PORT_INVALID');
|
|
1013
1021
|
const recoveryLaunchdTunnel = launchdService(opts.recoveryTunnelServiceLabel, opts.recoveryTunnelServicePlist, 'RECOVERY_TUNNEL') as PublicTunnelServiceConfig | undefined;
|
|
@@ -1063,6 +1071,7 @@ export function buildRecoveryCommand(): Command {
|
|
|
1063
1071
|
assertDistinctRecoveryOpenAiTunnelIdentity(recoveryTunnelService, primaryPublicTunnelService);
|
|
1064
1072
|
|
|
1065
1073
|
const recoveryPublicUrl = endpoint(opts.recoveryPublicUrl, 'RECOVERY_PUBLIC_URL');
|
|
1074
|
+
if (profile === 'manual' && (recoveryTunnelService || recoveryPublicUrl)) throw new Error('RECOVERY_PROFILE_GATEWAY_REQUIRED');
|
|
1066
1075
|
if (recoveryOpenAiTunnel && recoveryPublicUrl) throw new Error('RECOVERY_OPENAI_TUNNEL_PUBLIC_URL_CONFLICT');
|
|
1067
1076
|
if ((recoveryLaunchdTunnel || recoverySystemdTunnel) && !recoveryPublicUrl) throw new Error('RECOVERY_PUBLIC_URL_AND_TUNNEL_SERVICE_MUST_BE_CONFIGURED_TOGETHER');
|
|
1068
1077
|
if (!recoveryTunnelService && recoveryPublicUrl) throw new Error('RECOVERY_PUBLIC_URL_AND_TUNNEL_SERVICE_MUST_BE_CONFIGURED_TOGETHER');
|
|
@@ -1080,8 +1089,12 @@ export function buildRecoveryCommand(): Command {
|
|
|
1080
1089
|
controllerHome: home,
|
|
1081
1090
|
repoRoot: primaryRuntimeSourceRoot,
|
|
1082
1091
|
...(primaryRuntimeSourceRepository ? { primaryRuntimeSourceRepositoryId: primaryRuntimeSourceRepository.repoId } : {}),
|
|
1083
|
-
|
|
1092
|
+
// The package root is only the CLI's location. A package installation
|
|
1093
|
+
// is not a Git checkout, while the explicitly registered primary
|
|
1094
|
+
// Runtime source is the immutable Recovery release's provenance.
|
|
1095
|
+
sourceRoot: primaryRuntimeSourceRoot,
|
|
1084
1096
|
port,
|
|
1097
|
+
profile,
|
|
1085
1098
|
stageOnly: opts.stageOnly === true,
|
|
1086
1099
|
primaryRuntimeService: defaultPrimaryRuntimeServiceConfig(),
|
|
1087
1100
|
publicMcpUrl: endpoint(opts.publicMcpUrl, 'PUBLIC_MCP_URL'),
|
|
@@ -1092,6 +1105,7 @@ export function buildRecoveryCommand(): Command {
|
|
|
1092
1105
|
});
|
|
1093
1106
|
output({
|
|
1094
1107
|
status: opts.stageOnly ? 'staged' : 'installed',
|
|
1108
|
+
profile: result.profile,
|
|
1095
1109
|
staged: result.staged.release,
|
|
1096
1110
|
activation: result.activated,
|
|
1097
1111
|
connector: recoveryConnectorDescriptor(home),
|
|
@@ -12,6 +12,7 @@ import { listOccurrences, listSchedules } from '../../../packages/kernel/schedul
|
|
|
12
12
|
import { observeRuntimeStatus } from '../../runtime/root/status';
|
|
13
13
|
import { readMcpServiceBearerToken } from '../../../adapters/mcp/auth';
|
|
14
14
|
import { createSetupBootstrapControlApi } from './bootstrap-control';
|
|
15
|
+
import { readSetupProfile, runtimeDeploymentTopologyForSetupProfile } from './setup-profile';
|
|
15
16
|
import { publishRuntimeRelease } from '../../runtime/root/release-store';
|
|
16
17
|
import { installForgeRuntimeService } from '../../runtime/root/service';
|
|
17
18
|
import { activateScheduledPackageRuntimeServiceFromPath, installPackageRuntimeService, readPackageRuntimeActivationReceipt } from '../../runtime/root/package-runtime-service';
|
|
@@ -73,12 +74,14 @@ export function buildRuntimeCommand(): Command {
|
|
|
73
74
|
writeFileSync(tokenPath, `${token}\n`, { mode: 0o600 });
|
|
74
75
|
}
|
|
75
76
|
const packageRoot = resolve(dirname(fileURLToPath(import.meta.url)), '..', '..', '..');
|
|
77
|
+
const setupProfile = readSetupProfile();
|
|
76
78
|
const result = await installPackageRuntimeService({
|
|
77
79
|
controllerHome: home,
|
|
78
80
|
packageRoot,
|
|
79
81
|
host: opts.host,
|
|
80
82
|
port,
|
|
81
83
|
authTokenFile: tokenPath,
|
|
84
|
+
...(setupProfile ? { topology: runtimeDeploymentTopologyForSetupProfile(setupProfile) } : {}),
|
|
82
85
|
forcePortable: opts.portable === true,
|
|
83
86
|
refreshConnector: opts.refreshConnector === true,
|
|
84
87
|
});
|
|
@@ -116,7 +119,6 @@ export function buildRuntimeCommand(): Command {
|
|
|
116
119
|
.option('--port <port>', 'MCP listener port', '8765')
|
|
117
120
|
.option('--stage-only', 'Build and validate the immutable Runtime release without publishing or activating it')
|
|
118
121
|
.option('--auth-token-file <path>', 'Raw bearer token file (defaults to controllerHome/mcp/runtime-token, created from the MCP bearer token when missing)')
|
|
119
|
-
.option('--exclusive-work-id <id>', 'Persistently admit only this P0 Work while migration is active')
|
|
120
122
|
.option('--node-executable <path>', 'Executable launchd uses to run the Forge Runtime service runner', process.execPath)
|
|
121
123
|
.option('--runner-path <path>', 'Forge Runtime service runner entry', join(resolve(dirname(fileURLToPath(import.meta.url)), '..', '..', '..'), 'bin', 'forge-runtime-service.mjs'))
|
|
122
124
|
.action(async (opts: {
|
|
@@ -125,7 +127,6 @@ export function buildRuntimeCommand(): Command {
|
|
|
125
127
|
host: string;
|
|
126
128
|
port: string;
|
|
127
129
|
authTokenFile?: string;
|
|
128
|
-
exclusiveWorkId?: string;
|
|
129
130
|
nodeExecutable: string;
|
|
130
131
|
runnerPath: string;
|
|
131
132
|
stageOnly?: boolean;
|
|
@@ -171,7 +172,6 @@ export function buildRuntimeCommand(): Command {
|
|
|
171
172
|
host: opts.host,
|
|
172
173
|
port,
|
|
173
174
|
authTokenFile: tokenPath,
|
|
174
|
-
...(opts.exclusiveWorkId?.trim() ? { exclusiveWorkId: opts.exclusiveWorkId.trim() } : {}),
|
|
175
175
|
},
|
|
176
176
|
runnerPath: resolve(opts.runnerPath),
|
|
177
177
|
nodeExecutable: resolve(opts.nodeExecutable),
|
|
@@ -8,6 +8,7 @@ import { dirname, join, resolve } from 'path';
|
|
|
8
8
|
import { openAiSecureTunnelStatusArgs, parseOpenAiSecureTunnelRuntimeStatus, tunnelRuntimeProfileTargetsEndpoint } from '../../../adapters/mcp/tunnels/openai-secure-tunnel';
|
|
9
9
|
import { discoverExecutable, type ExecutableDiscoveryResult } from '../../runtime/platform/executable-discovery';
|
|
10
10
|
import { resolvePlatformServiceManager, type PlatformServiceManagerKind } from '../../runtime/platform/service-manager';
|
|
11
|
+
import { deriveRuntimeDeploymentTopology, type RuntimeDeploymentTopology } from '../../runtime/root/deployment-topology';
|
|
11
12
|
|
|
12
13
|
export type SetupControllerKind = 'chatgpt' | 'codex' | 'claude' | 'mcp';
|
|
13
14
|
export type SetupTunnelProvider = 'auto' | 'openai' | 'cloudflare' | 'tailscale' | 'existing' | 'none';
|
|
@@ -187,6 +188,13 @@ export function setupNeedsRemoteAccess(profile: SetupProfile | undefined): boole
|
|
|
187
188
|
return Boolean(profile?.controllers.some((entry) => entry === 'chatgpt' || entry === 'mcp'));
|
|
188
189
|
}
|
|
189
190
|
|
|
191
|
+
export function runtimeDeploymentTopologyForSetupProfile(profile: SetupProfile): RuntimeDeploymentTopology {
|
|
192
|
+
return deriveRuntimeDeploymentTopology({
|
|
193
|
+
controllers: profile.controllers,
|
|
194
|
+
capabilityIntents: profile.capabilityIntents,
|
|
195
|
+
});
|
|
196
|
+
}
|
|
197
|
+
|
|
190
198
|
export type SetupConnectorAuthMode = 'oauth' | 'none';
|
|
191
199
|
|
|
192
200
|
export function setupConnectorAuthMode(profile: SetupProfile | undefined): SetupConnectorAuthMode {
|
|
@@ -280,8 +280,19 @@ function inferredPackageCheckEffects(name: string): ControllerCheckEffects | und
|
|
|
280
280
|
// and persist only content-bound receipts/caches outside repository source.
|
|
281
281
|
return { reads: ['.'], cache: 'write', temp: 'isolated', git: 'read' };
|
|
282
282
|
}
|
|
283
|
-
|
|
284
|
-
|
|
283
|
+
if (normalized === 'check:type' || normalized === 'check:runtime-architecture') {
|
|
284
|
+
// These canonical gates are source readers: TypeScript runs with --noEmit,
|
|
285
|
+
// while runtime-architecture only inspects source/AST structure. Neither
|
|
286
|
+
// owns the shared repository build cache.
|
|
287
|
+
return { reads: ['.'] };
|
|
288
|
+
}
|
|
289
|
+
if (normalized === 'check:architecture-sync') {
|
|
290
|
+
// Architecture sync runs the queue in --check mode and inspects Git state.
|
|
291
|
+
// Its scratch space is check-local; it never mutates repository source.
|
|
292
|
+
return { reads: ['.'], temp: 'isolated', git: 'read' };
|
|
293
|
+
}
|
|
294
|
+
const cachedStaticAnalysis = /(?:^|:)(?:typecheck|lint|format:check|mcp-compatibility|forge-runtime)$/.test(normalized);
|
|
295
|
+
if (cachedStaticAnalysis) return { reads: ['.'], cache: 'write' };
|
|
285
296
|
const isolatedReadOnlyCheck = /(?:^|:)(?:quality-harness|evaluation-framework|background-check-overlap|typescript-navigation|check-scheduling|bootstrap-files)$/.test(normalized);
|
|
286
297
|
if (isolatedReadOnlyCheck) return { reads: ['.'], temp: 'isolated', git: 'read' };
|
|
287
298
|
const browserLive = /(?:^|:)browser-live$/.test(normalized);
|
|
@@ -145,11 +145,11 @@ function classifyTask(repoRoot: string, issue: ControllerIssue, task: Controller
|
|
|
145
145
|
}
|
|
146
146
|
|
|
147
147
|
if (run && FINISHABLE_RUN_STATUSES.has(run.status)) {
|
|
148
|
-
if (
|
|
148
|
+
if (task.acceptanceCriteria.length > 0) {
|
|
149
149
|
return {
|
|
150
150
|
...base,
|
|
151
151
|
action: 'needs_human_review',
|
|
152
|
-
reason:
|
|
152
|
+
reason: `Task declares acceptance criteria that require an explicit acceptance decision before finishing ${run.runId}.`,
|
|
153
153
|
canAutoFinish: false,
|
|
154
154
|
suggestedDecision: 'approve_and_finish',
|
|
155
155
|
};
|
|
@@ -157,7 +157,7 @@ function classifyTask(repoRoot: string, issue: ControllerIssue, task: Controller
|
|
|
157
157
|
return {
|
|
158
158
|
...base,
|
|
159
159
|
action: 'auto_finish',
|
|
160
|
-
reason: `Run ${run.runId} is ${run.status} and
|
|
160
|
+
reason: `Run ${run.runId} is ${run.status} and the Task declares no semantic acceptance criteria, so automatic finish may proceed.`,
|
|
161
161
|
canAutoFinish: true,
|
|
162
162
|
suggestedDecision: 'auto',
|
|
163
163
|
};
|
|
@@ -11,7 +11,7 @@ import { resolveRepoPreferredControllerHome } from '../repositories/controller-h
|
|
|
11
11
|
import { withControllerLock } from '../repositories/locks';
|
|
12
12
|
import { listActiveLeases } from '../../runtime/resources/leases/store';
|
|
13
13
|
import { acceptVerifiedTask, getIssue, projectIssueEffectiveView, recordTaskVerification, updateTask } from './issue-store';
|
|
14
|
-
import { cleanupEvidenceResourceBlockers, completionEvidenceComplete
|
|
14
|
+
import { cleanupEvidenceResourceBlockers, completionEvidenceComplete } from './execution-policy';
|
|
15
15
|
import { currentCompletionTarget, resolveCompletionTargetBranch } from './completion-target';
|
|
16
16
|
import { runControllerCheck } from './check-runner';
|
|
17
17
|
import type { CleanupEvidence, ControllerIssue, ControllerTask, IntegrationEvidence, TaskCommandEvidence, TaskVerification } from './types';
|
|
@@ -183,7 +183,6 @@ function verificationForRun(
|
|
|
183
183
|
reviewer: string,
|
|
184
184
|
evidence: { integrationEvidence?: IntegrationEvidence; cleanupEvidence?: CleanupEvidence; completionReceipt?: CompletionReceipt; acceptanceConfirmed?: boolean } = {},
|
|
185
185
|
): TaskVerification {
|
|
186
|
-
const policy = taskExecutionPolicy(task);
|
|
187
186
|
const acceptanceResults = task.acceptanceCriteria.map((criterion) => evidence.acceptanceConfirmed
|
|
188
187
|
? {
|
|
189
188
|
criterion,
|
|
@@ -204,8 +203,7 @@ function verificationForRun(
|
|
|
204
203
|
integratedRevision: evidence.integrationEvidence?.targetRevision,
|
|
205
204
|
reviewedDiffHash: hashArtifact(repoRoot, run.diffArtifactPath),
|
|
206
205
|
reviewer,
|
|
207
|
-
checkResults:
|
|
208
|
-
? task.checks.map((checkId) => {
|
|
206
|
+
checkResults: task.checks.map((checkId) => {
|
|
209
207
|
try {
|
|
210
208
|
const result = runControllerCheck(repoRoot, checkId);
|
|
211
209
|
return {
|
|
@@ -218,8 +216,7 @@ function verificationForRun(
|
|
|
218
216
|
} catch (error) {
|
|
219
217
|
return { checkId, ok: false, summary: error instanceof Error ? error.message : String(error) };
|
|
220
218
|
}
|
|
221
|
-
})
|
|
222
|
-
: [],
|
|
219
|
+
}),
|
|
223
220
|
commandEvidence: commandEvidenceForRun(run),
|
|
224
221
|
acceptanceResults,
|
|
225
222
|
verifiedAt: nowIso(),
|
|
@@ -233,8 +230,7 @@ function result(repoRoot: string, input: Omit<FinishTaskRunResult, 'issue'>): Fi
|
|
|
233
230
|
}
|
|
234
231
|
|
|
235
232
|
function canAutoFinish(task: ControllerTask): boolean {
|
|
236
|
-
|
|
237
|
-
return policy.autoCompleteAfterSuccessfulRun && !policy.requiresHumanAcceptance;
|
|
233
|
+
return task.acceptanceCriteria.length === 0;
|
|
238
234
|
}
|
|
239
235
|
|
|
240
236
|
function verifyAndMaybeAccept(input: {
|
|
@@ -247,16 +243,7 @@ function verifyAndMaybeAccept(input: {
|
|
|
247
243
|
allowCompletion?: boolean;
|
|
248
244
|
}): { issue: ControllerIssue; taskStatus: string } {
|
|
249
245
|
const { repoRoot, run, task, decision, reviewer } = input;
|
|
250
|
-
const policy = taskExecutionPolicy(task);
|
|
251
246
|
const allowHumanAcceptance = decision === 'approve_and_finish';
|
|
252
|
-
if (policy.requiresHumanAcceptance && !allowHumanAcceptance) {
|
|
253
|
-
updateTask(repoRoot, run.issueId, run.taskId, {
|
|
254
|
-
status: task.status === 'verified' ? 'verified' : task.status,
|
|
255
|
-
note: input.note ?? `Run ${run.runId} is ready but ${policy.executionClass} requires an explicit review decision.`,
|
|
256
|
-
});
|
|
257
|
-
const waiting = getIssue(repoRoot, run.issueId);
|
|
258
|
-
return { issue: waiting, taskStatus: taskForRun(waiting, run.taskId).status };
|
|
259
|
-
}
|
|
260
247
|
|
|
261
248
|
const current = getIssue(repoRoot, run.issueId);
|
|
262
249
|
const currentTask = taskForRun(current, run.taskId);
|
|
@@ -438,19 +425,6 @@ function finishEditSessionUnlocked(repoRoot: string, options: FinishEditSessionO
|
|
|
438
425
|
});
|
|
439
426
|
}
|
|
440
427
|
|
|
441
|
-
const policy = taskExecutionPolicy(task);
|
|
442
|
-
if (policy.requiresHumanAcceptance && decision !== 'approve_and_finish') {
|
|
443
|
-
return editResult(repoRoot, {
|
|
444
|
-
action: 'needs_decision',
|
|
445
|
-
sessionId: initialSession.sessionId,
|
|
446
|
-
issueId: issue.id,
|
|
447
|
-
taskId: task.id,
|
|
448
|
-
decision,
|
|
449
|
-
taskStatus: task.status,
|
|
450
|
-
reason: `${policy.executionClass} requires approve_and_finish, request_changes, or discard.`,
|
|
451
|
-
});
|
|
452
|
-
}
|
|
453
|
-
|
|
454
428
|
const completionTarget = currentCompletionTarget(repoRoot);
|
|
455
429
|
if (!completionTarget.onTargetBranch) {
|
|
456
430
|
return editResult(repoRoot, {
|
|
@@ -1165,19 +1139,6 @@ function finishTaskRunUnlocked(repoRoot: string, options: FinishTaskRunOptions):
|
|
|
1165
1139
|
});
|
|
1166
1140
|
}
|
|
1167
1141
|
|
|
1168
|
-
const policy = taskExecutionPolicy(task);
|
|
1169
|
-
if (policy.requiresHumanAcceptance && decision !== 'approve_and_finish') {
|
|
1170
|
-
return result(repoRoot, {
|
|
1171
|
-
action: 'needs_decision',
|
|
1172
|
-
runId: run.runId,
|
|
1173
|
-
issueId: issue.id,
|
|
1174
|
-
taskId: task.id,
|
|
1175
|
-
decision,
|
|
1176
|
-
taskStatus: task.status,
|
|
1177
|
-
reason: `${policy.executionClass} requires approve_and_finish, request_changes, or discard.`,
|
|
1178
|
-
});
|
|
1179
|
-
}
|
|
1180
|
-
|
|
1181
1142
|
const ownedAutoFinalization = run.status === 'running'
|
|
1182
1143
|
&& run.autoIntegrate === true
|
|
1183
1144
|
&& run.executionMode === 'worktree'
|