@moretea-labs/forge 1.7.2 → 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 +121 -62
- package/CHANGELOG.md +40 -0
- package/CLAUDE.md +57 -62
- package/CONTRIBUTING.md +3 -2
- package/README.md +2 -2
- package/SKILL.md +0 -1
- package/THIRD_PARTY_NOTICES.md +5 -2
- package/adapters/browser/index.ts +2 -0
- package/adapters/chatgpt/browser-delivery-host.ts +77 -0
- package/adapters/chatgpt/browser-delivery-runtime.ts +1256 -0
- package/adapters/chatgpt/controller-binding-store.ts +134 -0
- package/adapters/chatgpt/controller-round-host.ts +68 -0
- package/adapters/chatgpt/controller-round-settlement-store.ts +99 -0
- package/adapters/chatgpt/provider-delivery.ts +340 -0
- package/adapters/chatgpt/work-conversation-binding-store.ts +218 -0
- package/adapters/chatgpt/wsl-bridge-delivery-host.ts +63 -0
- 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-contract.ts +7 -0
- package/adapters/computer/desktop-operator-discovery.ts +181 -0
- package/adapters/computer/desktop-operator-negotiation.ts +174 -0
- package/adapters/computer/desktop-operator-provider.ts +312 -0
- package/adapters/computer/index.ts +1 -0
- package/adapters/computer/interaction-target-authority.ts +1068 -0
- package/adapters/controller-process/binding-store.ts +34 -0
- package/adapters/controller-process/controller-host.ts +26 -0
- package/adapters/mcp/access-mode.ts +132 -0
- package/adapters/mcp/audit.ts +32 -0
- package/adapters/mcp/auth.ts +406 -0
- package/adapters/mcp/instructions.ts +37 -0
- package/adapters/mcp/legacy-context.ts +18 -0
- package/adapters/mcp/multi-repository.ts +421 -0
- package/adapters/mcp/oauth.ts +464 -0
- package/adapters/mcp/paths.ts +143 -0
- package/adapters/mcp/policy.ts +232 -0
- package/adapters/mcp/proxy-env.ts +62 -0
- package/adapters/mcp/readiness-projection.ts +24 -0
- package/adapters/mcp/redaction.ts +21 -0
- package/adapters/mcp/repo.ts +24 -0
- package/adapters/mcp/runtime-gateway/artifact-adapter.ts +52 -0
- 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 +1167 -0
- package/adapters/mcp/runtime-gateway/context-pack-sidecar.ts +91 -0
- package/adapters/mcp/runtime-gateway/controller-authority-adapter.ts +206 -0
- package/adapters/mcp/runtime-gateway/core-capability-adapter.ts +258 -0
- package/adapters/mcp/runtime-gateway/engineering-preconditions.ts +130 -0
- package/adapters/mcp/runtime-gateway/engineering-tool-contract.ts +15 -0
- package/adapters/mcp/runtime-gateway/execution-control-adapter.ts +28 -0
- package/adapters/mcp/runtime-gateway/execution-tools.ts +173 -0
- package/adapters/mcp/runtime-gateway/filesystem-adapter.ts +38 -0
- package/adapters/mcp/runtime-gateway/gateway-execution-adapter.ts +412 -0
- package/adapters/mcp/runtime-gateway/legacy-ios-tool-adapter.ts +105 -0
- package/adapters/mcp/runtime-gateway/maintenance-adapter.ts +44 -0
- package/adapters/mcp/runtime-gateway/model-adapter.ts +63 -0
- package/adapters/mcp/runtime-gateway/persisted-check-process.ts +3 -0
- package/adapters/mcp/runtime-gateway/plugin-adapter.ts +380 -0
- package/adapters/mcp/runtime-gateway/process-tools.ts +457 -0
- package/adapters/mcp/runtime-gateway/protected-computer-adapter.ts +88 -0
- package/adapters/mcp/runtime-gateway/recovery-adapter.ts +285 -0
- package/adapters/mcp/runtime-gateway/recovery-client-adapter.ts +70 -0
- package/adapters/mcp/runtime-gateway/recovery-tool-contract.ts +99 -0
- package/adapters/mcp/runtime-gateway/repository-compat-adapter.ts +79 -0
- package/adapters/mcp/runtime-gateway/result-adapter.ts +114 -0
- package/adapters/mcp/runtime-gateway/router.ts +242 -0
- package/adapters/mcp/runtime-gateway/routing-policy.ts +499 -0
- package/adapters/mcp/runtime-gateway/runtime-observation-adapter.ts +1200 -0
- package/adapters/mcp/runtime-gateway/runtime-readiness-observation.ts +218 -0
- package/adapters/mcp/runtime-gateway/runtime-tool-definitions.ts +574 -0
- package/adapters/mcp/runtime-gateway/runtime-tool-shared.ts +27 -0
- package/adapters/mcp/runtime-gateway/runtime-tools.ts +78 -0
- package/adapters/mcp/runtime-gateway/scheduler-adapter.ts +187 -0
- package/adapters/mcp/runtime-gateway/shared-adapter.ts +45 -0
- package/adapters/mcp/runtime-gateway/status-inbox-adapter.ts +962 -0
- package/adapters/mcp/runtime-gateway/typescript-navigation-sidecar.ts +136 -0
- package/adapters/mcp/runtime-gateway/work-adapter.ts +325 -0
- 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-validation-reconciler.ts +1 -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 +1092 -0
- package/adapters/mcp/setup.ts +789 -0
- package/adapters/mcp/tool-capability-cache.ts +87 -0
- package/adapters/mcp/tool-mapping/access-tools.ts +387 -0
- package/adapters/mcp/tool-mapping/legacy-tool-service.ts +5139 -0
- package/adapters/mcp/tool-mapping/post-finalize-work-attribution.ts +145 -0
- package/adapters/mcp/tool-mapping/repository-tools.ts +1682 -0
- package/adapters/mcp/tool-mapping/tools.ts +9 -0
- package/adapters/mcp/tool-mapping/umbrella-tools.ts +117 -0
- package/adapters/mcp/toolset-names.ts +79 -0
- package/adapters/mcp/toolset-selection.ts +41 -0
- package/adapters/mcp/toolset.ts +337 -0
- package/adapters/mcp/transports/http-observation.ts +365 -0
- package/adapters/mcp/transports/http.ts +933 -0
- package/adapters/mcp/transports/oauth-http.ts +322 -0
- package/adapters/mcp/transports/session-registry.ts +519 -0
- package/adapters/mcp/transports/stdio.ts +8 -0
- package/adapters/mcp/tunnels/openai-secure-tunnel.ts +223 -0
- package/adapters/mcp/types.ts +41 -0
- package/assets/AGENTS.md +2 -16
- package/assets/CLAUDE.md +2 -16
- package/assets/hooks/AGENTS.md +3 -14
- package/assets/hooks/CLAUDE.md +3 -14
- package/assets/hooks/hook-input.sh +9 -2
- package/assets/hooks/lib/workflow-state.sh +28 -10
- package/assets/hooks/prompt-guard.sh +63 -37
- package/assets/hooks/security-sentinel.sh +2 -1
- package/assets/hooks/session-start-context.sh +7 -5
- package/assets/hooks/stop-orchestrator.sh +13 -3
- package/assets/initializer-question-pack.v4.json +11 -7
- package/assets/partials/05-workflow.partial.md +18 -73
- package/assets/partials/07-footer.partial.md +1 -1
- package/assets/partials-agents/02-operating-mode.partial.md +1 -2
- package/assets/partials-agents/04-task-protocol.partial.md +14 -59
- package/assets/partials-agents/06-quality-safety.partial.md +11 -16
- package/assets/partials-agents/08-deep-docs.partial.md +1 -2
- package/assets/plan-map.json +11 -11
- package/assets/plugin-registry.v1.json +11 -3
- package/assets/plugin-trust-policy.v1.json +6 -0
- package/assets/recovery/ForgeRecovery.ps1 +100 -0
- package/assets/recovery/forge-wsl-rescue +271 -0
- package/assets/reference-configs/agentic-development-flow.md +25 -0
- package/assets/reference-configs/development-protocol.md +11 -15
- package/assets/reference-configs/document-generation.md +1 -1
- package/assets/reference-configs/global-working-rules.md +28 -1
- package/assets/reference-configs/harness-overview.md +22 -112
- package/assets/reference-configs/hook-operations.md +1 -1
- package/assets/reference-configs/sprint-contracts.md +2 -2
- package/assets/skill-version.json +2 -2
- package/assets/templates/helpers/architecture-event.ts +3 -34
- package/assets/templates/helpers/architecture-queue.sh +61 -10
- package/assets/templates/helpers/archive-workflow.sh +90 -180
- package/assets/templates/helpers/capability-config.ts +8 -11
- package/assets/templates/helpers/capability-resolver.ts +37 -19
- package/assets/templates/helpers/capture-plan.sh +2 -2
- package/assets/templates/helpers/check-architecture-sync.sh +1 -9
- package/assets/templates/helpers/check-task-sync.sh +82 -11
- package/assets/templates/helpers/check-task-workflow.sh +1 -3
- package/assets/templates/helpers/context-contract-sync.sh +1 -12
- package/assets/templates/helpers/contract-worktree.sh +26 -24
- package/assets/templates/helpers/ensure-task-workflow.sh +6 -8
- package/assets/templates/helpers/inspect-project-state.ts +1 -1
- package/assets/templates/helpers/migrate-project-template.sh +1 -1
- package/assets/templates/helpers/migrate-workflow-docs.ts +53 -239
- package/assets/templates/helpers/new-plan.sh +2 -2
- package/assets/templates/helpers/plan-to-todo.sh +3 -31
- package/assets/templates/helpers/sprint-backlog.sh +1 -1
- package/assets/templates/helpers/switch-plan.sh +1 -1
- package/assets/templates/helpers/workflow-contract.ts +1 -0
- package/assets/workflow-contract.v1.json +63 -171
- package/assets/workflows/xiaohongshu/xiaohongshu.collect-metrics.v1.draft.json +118 -0
- package/assets/workflows/xiaohongshu/xiaohongshu.publish-image-note.v1.draft.json +316 -0
- package/assets/workflows/xiaohongshu/xiaohongshu.publish-long-text.v1.draft.json +324 -0
- package/docs/architecture/CURRENT.md +233 -28
- package/docs/architecture/EVOLUTION.md +13 -0
- package/docs/architecture/decisions/20260801-controller-home-sqlite-state.md +2 -1
- 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/20260831-independent-windows-wsl-host-rescue.md +59 -0
- package/docs/architecture/decisions/20260904-ios-device-migration-baseline.md +120 -0
- package/docs/architecture/decisions/20260904-repository-runtime-data-boundary.md +42 -0
- package/docs/architecture/decisions/20260907-assistant-learning-loop.md +37 -0
- package/docs/architecture/decisions/20260907-controller-round-transition-policy.md +311 -0
- package/docs/architecture/decisions/20260907-maintenance-diagnosis-bounded-read.md +39 -0
- 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 +8 -0
- package/docs/architecture/domains/workflow-engine.md +7 -1
- package/docs/architecture/index.md +3 -3
- package/docs/architecture/modules/controller-runtime/transport-lifecycle.md +19 -8
- package/docs/architecture/requests/2026-09-04-computer-plugin-workflow-taxonomy.md +124 -0
- package/docs/forge-chatgpt-mcp-setup.md +5 -3
- package/docs/forge-plugin-management.md +20 -4
- package/docs/forge-runtime-self-healing-loop.md +2 -0
- package/docs/operations/benchmark-cross-version-freeze.md +38 -0
- package/docs/operations/controller-browser-plugin.md +3 -1
- 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/platform-support.md +16 -8
- package/docs/operations/platform-support.zh-CN.md +2 -2
- package/docs/operations/releasing.md +2 -0
- package/docs/operations/standalone-disaster-recovery.md +38 -5
- package/docs/operations/uu-remote-rescue.md +41 -0
- package/docs/operations/windows-wsl-host-rescue.md +133 -0
- package/docs/public-usage-guide.md +1 -1
- package/docs/public-usage-guide.zh-CN.md +1 -1
- package/docs/tutorials/01-install-and-start.md +1 -1
- package/docs/tutorials/01-install-and-start.zh-CN.md +1 -1
- package/docs/tutorials/02-connect-chatgpt.md +4 -4
- package/docs/tutorials/02-connect-chatgpt.zh-CN.md +4 -4
- package/docs/wiki/Implementation.md +1 -1
- package/package.json +46 -26
- 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 +3 -0
- package/packages/kernel/controller/application/continuation-service.ts +281 -0
- package/packages/kernel/controller/application/controller-round-service.ts +41 -0
- package/packages/kernel/controller/application/controller-service.ts +30 -0
- package/packages/kernel/controller/domain/controller-round-transition-policy.ts +529 -0
- package/packages/kernel/controller/domain/controller-round.ts +110 -0
- package/packages/kernel/controller/domain/execution-quality.ts +135 -0
- package/packages/kernel/controller/domain/types.ts +56 -0
- package/packages/kernel/controller/index.ts +1 -0
- package/packages/kernel/controller/infrastructure/controller-binding-store.ts +84 -0
- package/packages/kernel/controller/infrastructure/controller-round-store.ts +1970 -0
- package/packages/kernel/controller/infrastructure/controller-session-store.ts +804 -0
- package/packages/kernel/controller/ports/controller-host.ts +18 -0
- package/packages/kernel/goal/api/index.ts +1 -0
- package/packages/kernel/goal/domain/types.ts +40 -0
- package/packages/kernel/goal/index.ts +1 -0
- package/packages/kernel/identity/api/index.ts +15 -0
- package/packages/kernel/identity/application/identity-service.ts +67 -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/scope.ts +63 -0
- package/packages/kernel/identity/domain/semantic-sync.ts +81 -0
- package/packages/kernel/identity/domain/types.ts +44 -0
- package/packages/kernel/identity/domain/user-request.ts +93 -0
- package/packages/kernel/identity/domain/workspace.ts +56 -0
- package/packages/kernel/identity/index.ts +1 -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/identity-store.ts +75 -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/memory/api/index.ts +5 -0
- package/packages/kernel/memory/application/experience-service.ts +118 -0
- package/packages/kernel/memory/application/outcome-service.ts +77 -0
- package/packages/kernel/memory/domain/experience.ts +103 -0
- package/packages/kernel/memory/domain/operational-prior.ts +92 -0
- package/packages/kernel/memory/index.ts +1 -0
- package/packages/kernel/scheduler/api/index.ts +4 -0
- package/packages/kernel/scheduler/application/eligibility.ts +252 -0
- package/packages/kernel/scheduler/application/schedule-service.ts +27 -0
- package/packages/kernel/scheduler/application/settlement.ts +182 -0
- package/packages/kernel/scheduler/domain/schedule.ts +236 -0
- package/packages/kernel/scheduler/index.ts +1 -0
- package/packages/kernel/scheduler/infrastructure/schedule-store.ts +805 -0
- package/packages/kernel/work/api/index.ts +16 -0
- package/packages/kernel/work/application/work-service.ts +123 -0
- package/packages/kernel/work/domain/check-receipt.ts +43 -0
- package/packages/kernel/work/domain/context-closure-receipt.ts +32 -0
- package/packages/kernel/work/domain/current-task-lineage.ts +104 -0
- package/packages/kernel/work/domain/engineering-contracts.ts +157 -0
- package/packages/kernel/work/domain/engineering-design.ts +286 -0
- package/packages/kernel/work/domain/engineering-profile.ts +238 -0
- package/packages/kernel/work/domain/evaluation-promotion-receipt.ts +186 -0
- package/packages/kernel/work/domain/execution-concurrency.ts +247 -0
- package/packages/kernel/work/domain/execution-snapshot.ts +2 -0
- package/packages/kernel/work/domain/implementation-review.ts +193 -0
- package/packages/kernel/work/domain/objective-graph.ts +119 -0
- package/packages/kernel/work/domain/project-engineering-contract.ts +224 -0
- package/packages/kernel/work/domain/repository-completion-receipt.ts +73 -0
- package/{src/runtime/control-plane/facade/work-state-machine.ts → packages/kernel/work/domain/state-machine.ts} +37 -66
- package/packages/kernel/work/domain/types.ts +534 -0
- package/packages/kernel/work/index.ts +1 -0
- package/packages/kernel/work/infrastructure/work-contract-store.ts +1967 -0
- package/packages/kernel/work/ports/work-contract-store.ts +21 -0
- package/packages/plugin-runtime/browser/index.ts +3 -0
- package/packages/plugin-runtime/browser/provider-registry.ts +110 -0
- package/packages/plugin-runtime/browser/runtime-contract.ts +150 -0
- package/packages/plugin-runtime/browser/session-authority.ts +62 -0
- 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 +8 -0
- package/packages/plugin-runtime/computer/provider-error.ts +26 -0
- package/packages/plugin-runtime/computer/provider-registration.ts +52 -0
- package/packages/plugin-runtime/computer/provider-registry.ts +63 -0
- package/packages/plugin-runtime/computer/provider.ts +19 -0
- package/packages/plugin-runtime/computer/target-authority.ts +215 -0
- package/packages/plugin-runtime/computer/target-persistence.ts +54 -0
- package/packages/plugin-runtime/external/index.ts +1 -0
- package/packages/plugin-runtime/external/unix-jsonl-transport.ts +581 -0
- package/packages/plugin-runtime/index.ts +3 -0
- package/packages/protocols/browser/index.ts +1 -0
- package/packages/protocols/browser/session.ts +98 -0
- package/packages/protocols/computer/contract.ts +225 -0
- package/packages/protocols/computer/index.ts +1 -0
- package/packages/protocols/failure/contract.ts +158 -0
- package/packages/protocols/failure/index.ts +1 -0
- package/packages/protocols/handoff/index.ts +1 -0
- package/packages/protocols/handoff/status.ts +22 -0
- package/packages/protocols/mcp/execution-context.ts +11 -0
- package/packages/protocols/mcp/index.ts +2 -0
- package/packages/protocols/mcp/tool-contract.ts +42 -0
- package/packages/workflow-runtime/api/index.ts +2 -0
- package/packages/workflow-runtime/application/interpreter.ts +342 -0
- package/packages/workflow-runtime/domain/workflow-asset.ts +223 -0
- package/packages/workflow-runtime/index.ts +1 -0
- package/scripts/activate-source-baseline.ts +7 -9
- package/scripts/assemble-template.ts +1 -1
- package/scripts/bootstrap-runtime-maintenance-recovery.sh +4 -1
- package/scripts/canary-chatgpt-provider-delivery.ts +97 -0
- package/scripts/canary-controller-semantic-wait.ts +183 -0
- package/scripts/canary-global-hook.sh +2 -2
- package/scripts/check-mcp-compatibility.ts +85 -7
- package/scripts/check-platform-support.mjs +28 -2
- package/scripts/check-public-docs.sh +1 -1
- package/scripts/check-repository-hygiene.mjs +92 -0
- package/scripts/check-runtime-architecture.mjs +1643 -127
- package/scripts/check-source-duplication.mjs +9 -1
- package/scripts/controller-ngrok-rotation.sh +5 -4
- package/scripts/create-project-dirs.sh +10 -74
- package/scripts/forge-local-recovery-helper.mjs +282 -0
- package/scripts/forge-uu-remote-rescue-helper.d.mts +31 -0
- package/scripts/forge-uu-remote-rescue-helper.mjs +409 -0
- package/scripts/forge-windows-host-recovery-helper.mjs +136 -0
- package/scripts/hook-shim.sh +2 -2
- package/scripts/init-project.sh +12 -70
- package/scripts/install-desktop-operator-registration.ts +4 -2
- package/scripts/install-independent-windows-wsl-recovery.ts +125 -0
- package/scripts/install-standalone-recovery.ts +122 -10
- package/scripts/install-uu-remote-rescue-registration.ts +74 -0
- package/scripts/install-windows-host-recovery-registration.ts +22 -0
- package/scripts/lib/controller-home-env.sh +6 -3
- package/scripts/lib/project-init-lib.sh +42 -582
- package/scripts/migrate-chatgpt-automation-schedules.ts +2 -2
- package/scripts/migrate-windows-wsl-controller-home.ts +306 -0
- package/scripts/open-source-audit-allowlist.txt +11 -1
- package/scripts/portability-bindings.mjs +70 -0
- package/scripts/run-bounded-command.mjs +60 -0
- package/scripts/run-bun-test-file.ts +22 -6
- package/scripts/run-governed-gate.ts +4 -2
- 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 +6 -1
- package/scripts/smoke-runtime-recovery.ts +13 -11
- package/scripts/smoke-schedule-engine.ts +24 -16
- 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/test-governance.ts +51 -2
- 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 +17 -4
- package/src/cli/chatgpt-browser/bind-server.ts +2 -1
- package/src/cli/chatgpt-browser/binding.ts +20 -10
- package/src/cli/chatgpt-browser/bridge-extension.ts +75 -0
- package/src/cli/chatgpt-browser/bridge-provider.ts +376 -11
- package/src/cli/chatgpt-browser/engine.ts +10 -11
- package/src/cli/chatgpt-browser/native-provider.ts +24 -83
- package/src/cli/chatgpt-browser/oracle-provider.ts +5 -3
- package/src/cli/chatgpt-browser/types.ts +1 -0
- package/src/cli/commands/bootstrap-control.ts +334 -0
- package/src/cli/commands/brain-assistant.ts +52 -0
- package/src/cli/commands/brain.ts +191 -40
- package/src/cli/commands/chatgpt.ts +32 -67
- package/src/cli/commands/computer.ts +437 -0
- package/src/cli/commands/doctor.ts +18 -1
- package/src/cli/commands/init-hook.ts +71 -61
- package/src/cli/commands/init.ts +3 -1
- package/src/cli/commands/mcp.ts +16 -10
- package/src/cli/commands/plugin.ts +38 -12
- package/src/cli/commands/recovery.ts +507 -80
- package/src/cli/commands/runtime.ts +12 -7
- package/src/cli/commands/setup-profile.ts +97 -39
- package/src/cli/commands/status.ts +2 -1
- package/src/cli/controller/check-runner.ts +500 -100
- 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/types.ts +7 -1
- package/src/cli/controller/context-pack.ts +28 -6
- 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 +148 -0
- package/src/cli/controller/types.ts +10 -70
- package/src/cli/controller/worklog.ts +67 -13
- package/src/cli/editing/edit-operation-contract.ts +92 -0
- package/src/cli/editing/edit-session.ts +290 -20
- package/src/cli/github/plugin.ts +17 -12
- package/src/cli/hook/route-registry.ts +3 -5
- package/src/cli/hook/runtime.ts +49 -3
- package/src/cli/index.ts +3 -0
- package/src/cli/local-bridge/connector-freshness.ts +2 -2
- package/src/cli/local-bridge/console-automations.ts +20 -15
- package/src/cli/local-bridge/console-view-models.ts +3 -12
- package/src/cli/local-bridge/facade-api.ts +105 -205
- package/src/cli/local-bridge/job-store.ts +1 -1
- package/src/cli/local-bridge/server.ts +48 -174
- package/src/cli/local-bridge/types.ts +0 -1
- package/src/cli/mcp/access-mode.ts +2 -132
- package/src/cli/mcp/access-tools.ts +2 -387
- package/src/cli/mcp/audit.ts +2 -32
- package/src/cli/mcp/auth.ts +2 -404
- package/src/cli/mcp/instructions.ts +2 -34
- package/src/cli/mcp/legacy-context.ts +2 -16
- package/src/cli/mcp/legacy-tool-service.ts +2 -5308
- package/src/cli/mcp/multi-repository.ts +2 -436
- package/src/cli/mcp/oauth-client-retirement.ts +74 -0
- package/src/cli/mcp/oauth.ts +2 -375
- package/src/cli/mcp/openai-secure-tunnel.ts +2 -0
- package/src/cli/mcp/paths.ts +2 -140
- package/src/cli/mcp/policy.ts +2 -232
- package/src/cli/mcp/post-finalize-work-attribution.ts +2 -150
- package/src/cli/mcp/proxy-env.ts +2 -62
- package/src/cli/mcp/readiness-projection.ts +2 -24
- package/src/cli/mcp/redaction.ts +2 -21
- package/src/cli/mcp/repo.ts +2 -24
- package/src/cli/mcp/repository-tools.ts +2 -1613
- package/src/cli/mcp/server.ts +2 -951
- package/src/cli/mcp/setup.ts +2 -737
- package/src/cli/mcp/tool-capability-cache.ts +2 -87
- package/src/cli/mcp/tool-contract.ts +2 -14
- package/src/cli/mcp/tools.ts +2 -9
- package/src/cli/mcp/toolset-names.ts +2 -70
- package/src/cli/mcp/toolset-selection.ts +2 -41
- package/src/cli/mcp/toolset.ts +2 -336
- package/src/cli/mcp/transports/AGENTS.md +1 -10
- package/src/cli/mcp/transports/CLAUDE.md +1 -10
- package/src/cli/mcp/transports/http.ts +2 -1414
- package/src/cli/mcp/transports/session-registry.ts +2 -490
- package/src/cli/mcp/transports/stdio.ts +2 -8
- package/src/cli/mcp/types.ts +2 -41
- package/src/cli/mcp/umbrella-tools.ts +2 -117
- package/src/cli/repositories/command-executor.ts +91 -39
- package/src/cli/repositories/command-scope.ts +139 -4
- package/src/cli/repositories/controller-home.ts +167 -1
- package/src/cli/repositories/ephemeral-workspace.ts +20 -30
- package/src/cli/repositories/git-command-executor.ts +2 -2
- package/src/cli/repositories/identity.ts +13 -0
- package/src/cli/repositories/registry.ts +145 -60
- package/src/cli/repositories/repository-snapshot.ts +53 -7
- package/src/cli/repositories/runtime-storage.ts +27 -2
- package/src/cli/repositories/safe-patch.ts +34 -38
- package/src/cli/repositories/selected-path-actions.ts +22 -2
- package/src/cli/repositories/structured-git.ts +167 -27
- package/src/cli/repository/session-cache.ts +92 -6
- package/src/cli/runtime/helper-runner.ts +7 -0
- package/src/cli/runtime-invocation.ts +8 -1
- package/src/cli/tools/codegraph.ts +44 -25
- package/src/core/adoption/manifest-templates.ts +1 -1
- package/src/core/adoption/plan.ts +3 -26
- package/src/core/adoption/workflow-contract-plan.ts +17 -9
- package/src/effects/process-runner.ts +8 -14
- package/src/runtime/context/assistant-context.ts +167 -0
- package/src/runtime/context/assistant-work-context.ts +209 -0
- package/src/runtime/context/automatic-learning.ts +565 -0
- package/src/runtime/context/codegraph-cache-boundary.ts +255 -0
- package/src/runtime/context/codegraph-read-provider.ts +55 -22
- package/src/runtime/context/codegraph-sidecar.cjs +8 -1
- 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 +305 -0
- package/src/runtime/context/context-pack-process.ts +103 -0
- package/src/runtime/context/context-plane.ts +203 -0
- package/src/runtime/context/direct-controller-learning.ts +298 -0
- package/src/runtime/context/project-engineering-contract.ts +60 -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/bootstrap/capability-provider.ts +74 -0
- package/src/runtime/control-plane/bootstrap/control-api.ts +57 -0
- package/src/runtime/control-plane/bootstrap/index.ts +5 -0
- package/src/runtime/control-plane/bootstrap/state-machine.ts +141 -0
- package/src/runtime/control-plane/bootstrap/store.ts +21 -0
- package/src/runtime/control-plane/bootstrap/types.ts +87 -0
- package/src/runtime/control-plane/cleanup-artifact-retention.ts +531 -0
- package/src/runtime/control-plane/codegraph-cache-retention.ts +164 -0
- package/src/runtime/control-plane/concurrency/work-execution-concurrency.ts +282 -0
- package/src/runtime/control-plane/execution/controller-authority-recovery.ts +380 -0
- package/src/runtime/control-plane/execution/edit-validation-coordinator.ts +113 -16
- package/src/runtime/control-plane/execution/execution-identity.ts +23 -3
- package/src/runtime/control-plane/execution/implementation-review-content.ts +95 -0
- package/src/runtime/control-plane/execution/repository-work-attribution.ts +7 -30
- package/src/runtime/control-plane/execution/retained-work-resume.ts +439 -102
- package/src/runtime/control-plane/execution/session-store.ts +31 -1
- package/src/runtime/control-plane/execution/validation.ts +34 -11
- package/src/runtime/control-plane/execution/work-authority-reconciler.ts +87 -0
- package/src/runtime/control-plane/execution/work-check-evidence.ts +137 -0
- package/src/runtime/control-plane/execution/work-completion-authority.ts +31 -44
- package/src/runtime/control-plane/execution/work-delivery-service.ts +497 -0
- package/src/runtime/control-plane/execution/work-evidence-policy.ts +46 -53
- package/src/runtime/control-plane/execution/work-execution-support.ts +85 -164
- package/src/runtime/control-plane/execution/work-handle-authority.ts +349 -73
- package/src/runtime/control-plane/execution/work-handle-store.ts +55 -2
- package/src/runtime/control-plane/execution/work-head-settlement.ts +108 -0
- package/src/runtime/control-plane/execution/work-lifecycle-audit.ts +173 -28
- package/src/runtime/control-plane/execution/work-operation-service.ts +92 -40
- package/src/runtime/control-plane/execution/work-preparation-service.ts +145 -269
- 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 +543 -225
- package/src/runtime/control-plane/execution/work-validation-reconciler.ts +59 -45
- package/src/runtime/control-plane/execution/work-verification-context.ts +1 -1
- package/src/runtime/control-plane/execution/work-verification-service.ts +662 -52
- package/src/runtime/control-plane/execution/work-verification-snapshot.ts +205 -16
- package/src/runtime/control-plane/facade/capability-registry.ts +380 -44
- 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/controller-session-store.ts +2 -488
- package/src/runtime/control-plane/facade/goal-workloop-access.ts +6 -22
- package/src/runtime/control-plane/facade/goal-workloop.ts +565 -1202
- package/src/runtime/control-plane/facade/handoff-inbox-application.ts +145 -0
- package/src/runtime/control-plane/facade/handoff-inbox-store.ts +266 -52
- package/src/runtime/control-plane/facade/index.ts +4 -3
- package/src/runtime/control-plane/facade/operation-digest.ts +34 -73
- package/src/runtime/control-plane/facade/plan-contract-store.ts +671 -245
- package/src/runtime/control-plane/facade/policy-gate.ts +0 -23
- package/src/runtime/control-plane/facade/repository-work-admission.ts +31 -23
- package/src/runtime/control-plane/facade/requirement-authority.ts +121 -0
- package/src/runtime/control-plane/facade/requirement-board.ts +9 -4
- package/src/runtime/control-plane/facade/rh-work-operation-contract.ts +85 -0
- package/src/runtime/control-plane/facade/self-healing-loop.ts +18 -53
- package/src/runtime/control-plane/facade/semantic-admission.ts +8 -16
- package/src/runtime/control-plane/facade/suggested-actions.ts +15 -15
- package/src/runtime/control-plane/facade/types.ts +218 -620
- package/src/runtime/control-plane/facade/work-continuation.ts +8 -8
- package/src/runtime/control-plane/facade/work-contract-store.ts +2 -1043
- package/src/runtime/control-plane/generated-cache-retention.ts +336 -19
- package/src/runtime/control-plane/global-scheduler/autonomous-continuation.ts +248 -0
- package/src/runtime/control-plane/global-scheduler/durable-admission.ts +13 -2
- package/src/runtime/control-plane/global-scheduler/maintenance.ts +274 -84
- package/src/runtime/control-plane/global-scheduler/periodic-cleanup-entry.ts +55 -0
- package/src/runtime/control-plane/global-scheduler/periodic-cleanup-process.ts +98 -0
- package/src/runtime/control-plane/global-scheduler/reconciliation.ts +3 -2
- package/src/runtime/control-plane/global-scheduler/scheduler-worker-entry.ts +10 -0
- package/src/runtime/control-plane/global-scheduler/scheduler.ts +227 -109
- package/src/runtime/control-plane/global-scheduler/wake-signal.ts +42 -2
- package/src/runtime/control-plane/global-scheduler/worker-launch.ts +18 -6
- 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 +160 -0
- package/src/runtime/control-plane/launcher/chatgpt-work-binding-store.ts +2 -177
- package/src/runtime/control-plane/launcher/chatgpt-work-continuation.ts +139 -670
- package/src/runtime/control-plane/launcher/local-conversation-controller.ts +238 -0
- package/src/runtime/control-plane/launcher/provider-mcp-bootstrap.ts +25 -6
- package/src/runtime/control-plane/launcher/thin-launcher.ts +96 -194
- package/src/runtime/control-plane/lifecycle-retention-metrics.ts +60 -0
- package/src/runtime/control-plane/persistence/cognition-store.ts +820 -0
- package/src/runtime/control-plane/persistence/experience-store.ts +302 -0
- package/src/runtime/control-plane/persistence/operational-prior-store.ts +348 -0
- package/src/runtime/control-plane/persistence/requirement-store.ts +230 -80
- package/src/runtime/control-plane/persistence/sqlite-store.ts +654 -78
- package/src/runtime/control-plane/persistence/workflow-content-store.ts +98 -0
- package/src/runtime/control-plane/persistence/workflow-registry-store.ts +186 -0
- package/src/runtime/control-plane/persistence/workflow-run-store.ts +123 -0
- package/src/runtime/control-plane/release-retention.ts +154 -26
- package/src/runtime/control-plane/repository-namespace-retention.ts +208 -0
- package/src/runtime/control-plane/runtime-cleanup.ts +844 -38
- package/src/runtime/control-plane/runtime-generation.ts +6 -0
- package/src/runtime/control-plane/workspace/project-onboarding.ts +80 -0
- package/src/runtime/control-plane/workspace/semantic-sync-service.ts +479 -0
- package/src/runtime/control-plane/workspace/workspace-store.ts +249 -0
- package/src/runtime/diagnostics/incident-repair.ts +573 -0
- package/src/runtime/diagnostics/mcp-timing.ts +239 -6
- package/src/runtime/diagnostics/performance.ts +6 -14
- package/src/runtime/diagnostics/read-only-tool.ts +1 -1
- package/src/runtime/evidence/artifact-store.ts +216 -35
- package/src/runtime/evidence/evidence-store.ts +112 -8
- package/src/runtime/evidence/operational-shadow.ts +38 -0
- package/src/runtime/evidence/output-handle-index.ts +225 -0
- package/src/runtime/evidence/process-check-receipt.ts +5 -43
- package/src/runtime/evidence/result-store.ts +158 -44
- package/src/runtime/evidence/sensitive-output.ts +4 -4
- package/src/runtime/execution/jobs/receipt-recovery.ts +1 -1
- package/src/runtime/execution/jobs/store.ts +124 -6
- package/src/runtime/execution/managed-workspace.ts +112 -5
- package/src/runtime/execution/process-runtime/canary.ts +19 -5
- package/src/runtime/execution/process-runtime/check-classification.ts +48 -0
- package/src/runtime/execution/process-runtime/check-facade.ts +24 -10
- package/src/runtime/execution/process-runtime/check-receipt.ts +1 -1
- package/src/runtime/execution/process-runtime/check-result-retention.ts +132 -0
- package/src/runtime/execution/process-runtime/check-result.ts +177 -2
- package/src/runtime/execution/process-runtime/check-runner-sidecar.ts +58 -9
- package/src/runtime/execution/process-runtime/check-storage.ts +187 -0
- package/src/runtime/execution/process-runtime/command-facade.ts +117 -114
- 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 +4 -0
- package/src/runtime/execution/process-runtime/interactive-admission.ts +2 -1
- package/src/runtime/execution/process-runtime/lightweight-managed.ts +283 -73
- package/src/runtime/execution/process-runtime/persisted-check.ts +130 -23
- 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 +125 -64
- package/src/runtime/execution/process-runtime/runtime.ts +167 -17
- package/src/runtime/execution/process-runtime/store.ts +30 -2
- package/src/runtime/execution/process-runtime/types.ts +27 -0
- package/src/runtime/execution/workers/executor.ts +18 -19
- package/src/runtime/execution/workers/worker-entry.ts +1 -1
- package/src/runtime/gateway/mcp/execution-tools.ts +2 -207
- package/src/runtime/gateway/mcp/legacy-ios-tool-adapter.ts +2 -61
- package/src/runtime/gateway/mcp/persisted-check-process.ts +2 -3
- package/src/runtime/gateway/mcp/process-tools.ts +2 -289
- package/src/runtime/gateway/mcp/router.ts +2 -1125
- package/src/runtime/gateway/mcp/runtime-tool-definitions.ts +2 -565
- package/src/runtime/gateway/mcp/runtime-tools.ts +2 -6655
- package/src/runtime/gateway/mcp/work-validation-reconciler.ts +2 -1
- package/src/runtime/maintenance/cleanup.ts +38 -24
- package/src/runtime/platform/browser-product-discovery.ts +174 -0
- package/src/runtime/platform/computer-platform.ts +14 -0
- package/src/runtime/platform/executable-discovery.ts +54 -0
- package/src/runtime/platform/fetch-http-server.ts +90 -0
- package/src/runtime/platform/service-inventory.ts +130 -0
- package/src/runtime/platform/service-manager.ts +146 -0
- package/src/runtime/platform/windows-host-discovery.ts +118 -0
- package/src/runtime/platform/windows-recovery-deployment.ts +67 -0
- package/src/runtime/plugins/action-application.ts +192 -0
- package/src/runtime/plugins/app-store-connect-adapter.ts +47 -35
- package/src/runtime/plugins/browser-adapter.ts +898 -135
- package/src/runtime/plugins/browser-automation-service.ts +33 -34
- package/src/runtime/plugins/browser-macos-bridge.ts +386 -46
- package/src/runtime/plugins/browser-manifest-surface.ts +75 -17
- package/src/runtime/plugins/browser-native-session-service.ts +64 -14
- package/src/runtime/plugins/browser-provider-registry.ts +2 -109
- package/src/runtime/plugins/browser-registration.ts +32 -0
- package/src/runtime/plugins/browser-runtime-contract.ts +2 -154
- package/src/runtime/plugins/browser-runtime.ts +55 -10
- package/src/runtime/plugins/browser-session-authority.ts +101 -291
- package/src/runtime/plugins/browser-session-legacy-migration.ts +203 -0
- package/src/runtime/plugins/browser-session-store.ts +243 -80
- package/src/runtime/plugins/browser-session-types.ts +2 -98
- package/src/runtime/plugins/capability-authorization-grants.ts +272 -59
- package/src/runtime/plugins/catalog-trust.ts +82 -0
- 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 +1050 -0
- package/src/runtime/plugins/config-store.ts +119 -0
- package/src/runtime/plugins/desktop-operator-external-policy.ts +964 -0
- package/src/runtime/plugins/desktop-operator-registration.ts +123 -12
- package/src/runtime/plugins/errors.ts +8 -1
- package/src/runtime/plugins/external-adapter.ts +82 -323
- package/src/runtime/plugins/external-provider-policy.ts +48 -0
- package/src/runtime/plugins/external-registration.ts +30 -2
- package/src/runtime/plugins/external-unix-socket-probe.cjs +9 -3
- package/src/runtime/plugins/external-unix-socket.ts +64 -193
- package/src/runtime/plugins/first-party-external-registration.ts +163 -0
- package/src/runtime/plugins/first-party-registry.ts +3 -1
- package/src/runtime/plugins/github-adapter.ts +1 -2
- package/src/runtime/plugins/gmail-adapter.ts +29 -8
- package/src/runtime/plugins/google-calendar-adapter.ts +8 -8
- package/src/runtime/plugins/google-shared.ts +45 -53
- package/src/runtime/plugins/google-tasks-adapter.ts +8 -8
- package/src/runtime/plugins/ios-adapter.ts +2 -3
- package/src/runtime/plugins/lightweight-action.ts +208 -2
- package/src/runtime/plugins/local-system-adapter.ts +192 -2
- package/src/runtime/plugins/macos-capability-broker.ts +15 -105
- 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/resend-adapter.ts +15 -24
- package/src/runtime/plugins/store.ts +1003 -387
- package/src/runtime/plugins/types.ts +28 -1
- package/src/runtime/plugins/uu-remote-rescue-registration.ts +155 -0
- package/src/runtime/plugins/windows-host-recovery-install.ts +68 -0
- package/src/runtime/plugins/windows-host-recovery-registration.ts +85 -0
- package/src/runtime/plugins/xiaohongshu-publish.ts +102 -430
- package/src/runtime/projections/controller-context.ts +12 -6
- package/src/runtime/projections/git-status-sampler.ts +73 -22
- package/src/runtime/projections/invalidation.ts +7 -3
- package/src/runtime/projections/materialized-view.ts +93 -43
- package/src/runtime/recovery/actions.ts +3 -3
- package/src/runtime/recovery/capability-action-application.ts +229 -0
- package/src/runtime/recovery/index.ts +3 -0
- package/src/runtime/recovery/lifecycle-inventory.ts +338 -0
- package/src/runtime/recovery/local-jobs-repair.ts +14 -14
- package/src/runtime/recovery/maintenance-executor.ts +701 -168
- package/src/runtime/recovery/quarantine-retention.ts +256 -0
- package/src/runtime/recovery/store.ts +29 -11
- package/src/runtime/release/identity.ts +6 -0
- 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/active-execution-power-assertion.ts +139 -0
- package/src/runtime/root/assistant-learning-loop.ts +45 -0
- package/src/runtime/root/browser-session-composition.ts +59 -0
- package/src/runtime/root/computer-composition.ts +376 -0
- package/src/runtime/root/computer-target-composition.ts +16 -0
- package/src/runtime/root/computer-target-persistence.ts +39 -0
- package/src/runtime/root/controller-progression-composition.ts +192 -0
- package/src/runtime/root/controller-round-composition.ts +126 -0
- package/src/runtime/root/controller-services.ts +2 -0
- package/src/runtime/root/deployment-topology.ts +106 -0
- package/src/runtime/root/entry.ts +8 -6
- package/src/runtime/root/gateway-adapter.ts +3 -3
- package/src/runtime/root/known-good-recovery.ts +184 -0
- package/src/runtime/root/local-bridge.ts +5 -3
- package/src/runtime/root/mcp-transport.ts +116 -23
- package/src/runtime/root/ownership.ts +261 -9
- package/src/runtime/root/package-connector-service.ts +212 -74
- package/src/runtime/root/package-runtime-release.ts +199 -33
- package/src/runtime/root/package-runtime-service.ts +77 -108
- package/src/runtime/root/release-execution-canary.ts +103 -0
- package/src/runtime/root/release-loader.ts +150 -0
- package/src/runtime/root/release-manifest.ts +185 -7
- package/src/runtime/root/release-materialize.ts +474 -31
- package/src/runtime/root/release-store.ts +425 -37
- package/src/runtime/root/runtime-lane.ts +191 -0
- package/src/runtime/root/runtime.ts +379 -32
- package/src/runtime/root/scheduled-controller-composition.ts +76 -0
- package/src/runtime/root/scheduler.ts +12 -4
- package/src/runtime/root/service-runner.ts +3 -3
- package/src/runtime/root/service.ts +73 -45
- package/src/runtime/root/status.ts +49 -0
- package/src/runtime/root/types.ts +55 -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/local-bridge-surface.ts +1 -1
- package/src/runtime/shared/process-environment.ts +36 -10
- package/src/runtime/shared/response-budget.ts +1 -3
- package/src/runtime/shared/storage-capacity.ts +68 -0
- package/src/runtime/standalone-recovery/controller-home-migration.ts +1108 -0
- package/src/runtime/standalone-recovery/core.ts +4609 -495
- package/src/runtime/standalone-recovery/entry.ts +642 -81
- package/src/runtime/standalone-recovery/independent-host-rescue.ts +172 -0
- package/src/runtime/standalone-recovery/installer.ts +399 -177
- package/src/runtime/standalone-recovery/mcp-server.ts +79 -0
- package/src/runtime/standalone-recovery/mutation-identity-contract.ts +21 -0
- package/src/runtime/standalone-recovery/operation-lock.ts +160 -0
- package/src/runtime/standalone-recovery/performance.ts +173 -0
- package/src/runtime/standalone-recovery/release.ts +58 -5
- package/src/runtime/standalone-recovery/service-labels.ts +5 -2
- package/src/runtime/standalone-recovery/watchdog-heartbeat.ts +5 -2
- package/src/runtime/watchdog/workflow-watchdog.ts +1 -1
- package/src/runtime/workflow/schedules/browser-probe.ts +17 -6
- package/src/runtime/workflow/schedules/chatgpt-automation-migration.ts +11 -4
- package/src/runtime/workflow/schedules/engine.ts +298 -484
- package/src/runtime/workflow/schedules/pending-activation.ts +1 -1
- package/src/runtime/workflow/schedules/settlement.ts +2 -191
- package/src/runtime/workflow/schedules/store.ts +2 -607
- package/src/runtime/workflow/schedules/types.ts +2 -127
- package/src/runtime/workflow/schedules/work-continuation.ts +220 -16
- package/src/runtime/workflows/first-party/xiaohongshu.ts +122 -0
- package/src/runtime/workflows/runtime.ts +482 -0
- package/src/testing/test-governance.ts +95 -30
- 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/assets/templates/helpers/archive-architecture-request.sh +0 -244
- package/docs/architecture/history/README.md +0 -7
- package/docs/architecture/history/chatgpt-handoff-facade.md +0 -397
- package/docs/architecture/history/global-hook-runtime.md +0 -166
- package/docs/architecture/history/ios-semantic-automation-provider-v2.md +0 -170
- package/docs/architecture/requests/archive/2026/20260528-154740-ai-hooks-ai-hooks-hook-input-sh.md +0 -59
- package/docs/architecture/requests/archive/2026/20260528-154816-assets-hooks-assets-hooks-hook-input-sh.md +0 -59
- package/docs/architecture/requests/archive/2026/20260528-161851-ai-harness-workflow-contract-json-ai-harness-workflow-contract-json.md +0 -59
- package/docs/architecture/requests/archive/2026/20260528-161853-scripts-check-task-workflow-sh-scripts-check-task-workflow-sh.md +0 -59
- package/docs/architecture/requests/archive/2026/20260528-161911-assets-workflow-contract-v1-json-assets-workflow-contract-v1-json.md +0 -59
- package/docs/architecture/requests/archive/2026/20260528-222416-ai-hooks-ai-hooks-hook-input-sh.md +0 -59
- package/docs/architecture/requests/archive/2026/20260528-222444-ai-hooks-ai-hooks-pre-edit-guard-sh.md +0 -59
- package/docs/architecture/requests/archive/2026/20260528-222457-ai-hooks-ai-hooks-pre-edit-guard-sh.md +0 -59
- package/docs/architecture/requests/archive/2026/20260528-222648-ai-hooks-ai-hooks-pre-edit-guard-sh.md +0 -59
- package/docs/architecture/requests/archive/2026/20260528-222705-ai-hooks-ai-hooks-worktree-guard-sh.md +0 -59
- package/docs/architecture/requests/archive/2026/20260528-222726-ai-hooks-ai-hooks-prompt-guard-sh.md +0 -59
- package/docs/architecture/requests/archive/2026/20260528-222727-ai-hooks-ai-hooks-prompt-guard-sh.md +0 -59
- package/docs/architecture/requests/archive/2026/20260528-224736-ai-hooks-ai-hooks-hook-input-sh.md +0 -59
- package/docs/architecture/requests/archive/2026/20260528-233259-ai-hooks-ai-hooks-prompt-guard-sh.md +0 -59
- package/docs/architecture/requests/archive/2026/20260528-233335-assets-hooks-assets-hooks-prompt-guard-sh.md +0 -59
- package/docs/architecture/requests/archive/2026/20260528-233456-ai-hooks-ai-hooks-prompt-guard-sh.md +0 -59
- package/docs/architecture/requests/archive/2026/20260528-233457-assets-hooks-assets-hooks-prompt-guard-sh.md +0 -59
- package/docs/architecture/requests/archive/2026/20260528-233637-ai-hooks-ai-hooks-prompt-guard-sh.md +0 -59
- package/docs/architecture/requests/archive/2026/20260528-233638-assets-hooks-assets-hooks-prompt-guard-sh.md +0 -59
- package/docs/architecture/requests/archive/2026/20260529-000322-root-package-json.md +0 -59
- package/docs/architecture/requests/archive/2026/20260529-004238-ai-hooks-ai-hooks-lib-workflow-state-sh.md +0 -59
- package/docs/architecture/requests/archive/2026/20260529-020654-ai-harness-policy-json-ai-harness-policy-json.md +0 -63
- package/docs/architecture/requests/archive/2026/20260529-094236-ai-hooks-ai-hooks-prompt-guard-sh.md +0 -60
- package/docs/architecture/requests/archive/2026/20260529-094323-assets-hooks-assets-hooks-prompt-guard-sh.md +0 -60
- package/docs/architecture/requests/archive/2026/20260529-094331-ai-hooks-ai-hooks-prompt-guard-sh.md +0 -60
- package/docs/architecture/requests/archive/2026/20260529-094339-assets-hooks-assets-hooks-prompt-guard-sh.md +0 -60
- package/docs/architecture/requests/archive/2026/20260529-094430-assets-hooks-assets-hooks-session-start-context-sh.md +0 -60
- package/docs/architecture/requests/archive/2026/20260529-094446-ai-hooks-ai-hooks-session-start-context-sh.md +0 -60
- package/docs/architecture/requests/archive/2026/20260613-002040-runtime-harness-hook-adapters.md +0 -68
- package/docs/architecture/requests/archive/2026/root.md +0 -68
- package/docs/architecture/requests/archive/2026/runtime-harness-hook-adapters.md +0 -76
- package/docs/architecture/requests/archive/2026/verification-evals-checks.md +0 -68
- package/docs/architecture/requests/archive/2026/workflow-engine-contract-assets.md +0 -69
- package/scripts/archive-architecture-request.sh +0 -4
- package/scripts/benchmark-background-check-overlap.ts +0 -228
- package/scripts/benchmark-controller-hotpath.ts +0 -212
- package/scripts/benchmark-controller-round2.ts +0 -139
- package/scripts/benchmark-ios-agent-device.ts +0 -514
- package/scripts/benchmark-mcp-host.sh +0 -117
- package/scripts/benchmark-mcp-transport.ts +0 -170
- 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 -67
- 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/run-skill-evals.ts +0 -1022
- package/scripts/stage-runtime-release.ts +0 -39
- 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/direct-edit-work-completion.ts +0 -385
- package/src/runtime/control-plane/execution/work-finalization-service.ts +0 -1913
- package/src/runtime/control-plane/execution/work-path-scope.ts +0 -37
- package/src/runtime/control-plane/execution/work-task-receipt.ts +0 -449
- package/src/runtime/control-plane/facade/controller-round-relay.ts +0 -1118
- package/src/runtime/control-plane/facade/work-admission-policy.ts +0 -93
- 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 -382
- package/src/runtime/control-plane/routing/workspace-admission.ts +0 -70
|
@@ -1,13 +1,25 @@
|
|
|
1
1
|
import { createHash, randomBytes } from 'crypto';
|
|
2
|
+
import { spawnSync } from 'child_process';
|
|
2
3
|
import { existsSync } from 'fs';
|
|
3
|
-
import {
|
|
4
|
+
import { hostname } from 'os';
|
|
5
|
+
import { isAbsolute, join, resolve } from 'path';
|
|
4
6
|
import { Command } from 'commander';
|
|
5
|
-
import { readMcpServiceOAuthPassphrase } from '
|
|
6
|
-
import {
|
|
7
|
+
import { readMcpServiceOAuthPassphrase } from '../../../adapters/mcp/auth';
|
|
8
|
+
import {
|
|
9
|
+
openAiSecureTunnelConnectArgs,
|
|
10
|
+
openAiSecureTunnelStatusArgs,
|
|
11
|
+
parseOpenAiSecureTunnelRuntimeStatus,
|
|
12
|
+
type OpenAiSecureTunnelRuntimeObservation,
|
|
13
|
+
} from '../../../adapters/mcp/tunnels/openai-secure-tunnel';
|
|
14
|
+
import { findRegisteredRepositoryByCheckoutRoot } from '../repositories/registry';
|
|
15
|
+
import {
|
|
16
|
+
resolveControllerHome,
|
|
17
|
+
rollbackStoppedControllerHomeAuthorityRelocation,
|
|
18
|
+
type StoppedControllerHomeAuthorityRelocation,
|
|
19
|
+
} from '../repositories/controller-home';
|
|
7
20
|
import { FORGE_VERSION } from '../../version';
|
|
8
21
|
import {
|
|
9
|
-
|
|
10
|
-
RECOVERY_WATCHDOG_LABEL,
|
|
22
|
+
RECOVERY_DAEMON_LABEL,
|
|
11
23
|
inspectRecoveryTunnelLaunchdContract,
|
|
12
24
|
installStandaloneRecovery,
|
|
13
25
|
recoveryLaunchdPid,
|
|
@@ -16,11 +28,17 @@ import {
|
|
|
16
28
|
} from '../../runtime/standalone-recovery/installer';
|
|
17
29
|
import {
|
|
18
30
|
RECOVERY_TOOLS,
|
|
31
|
+
RECOVERY_VERIFIER_OAUTH_CLIENT_ID,
|
|
32
|
+
RECOVERY_VERIFIER_OAUTH_CLIENT_NAME,
|
|
33
|
+
RECOVERY_VERIFIER_OAUTH_REDIRECT_URI,
|
|
19
34
|
} from '../../runtime/standalone-recovery/entry';
|
|
20
35
|
import {
|
|
21
36
|
activateRuntimeRelease,
|
|
37
|
+
defaultPrimaryRuntimeServiceConfig,
|
|
22
38
|
loadRecoveryConfig,
|
|
39
|
+
normalizeRecoveryInstallProfile,
|
|
23
40
|
recoverPrimaryRuntime,
|
|
41
|
+
recoveryMachineIdentity,
|
|
24
42
|
restartPrimaryConnector,
|
|
25
43
|
restartPrimaryRuntime,
|
|
26
44
|
restartRecoveryGateway,
|
|
@@ -28,12 +46,25 @@ import {
|
|
|
28
46
|
rollbackPrevious,
|
|
29
47
|
runtimeStatus,
|
|
30
48
|
verifyStableRuntime,
|
|
49
|
+
type OpenAiSecureTunnelServiceConfig,
|
|
31
50
|
type PrimaryConnectorServiceConfig,
|
|
51
|
+
type RecoveryMachineIdentity,
|
|
32
52
|
type PublicTunnelServiceConfig,
|
|
53
|
+
type RecoveryTunnelServiceConfig,
|
|
54
|
+
type SystemdUserRecoveryTunnelServiceConfig,
|
|
33
55
|
} from '../../runtime/standalone-recovery/core';
|
|
34
56
|
import { readRecoveryRuntimeIdentity } from '../../runtime/standalone-recovery/release';
|
|
57
|
+
import {
|
|
58
|
+
assertRecoveryControllerHomeMigrationReady,
|
|
59
|
+
recoveryControllerHomeMigrationPreflight,
|
|
60
|
+
runLinuxControllerHomeMigrationRequest,
|
|
61
|
+
scheduleLinuxControllerHomeMigration,
|
|
62
|
+
type RecoveryControllerHomeMigrationPreflight,
|
|
63
|
+
} from '../../runtime/standalone-recovery/controller-home-migration';
|
|
35
64
|
import { configureCodegraph, ensureCodegraph } from '../tools/codegraph';
|
|
36
65
|
import { isProcessAlive } from '../../runtime/shared/process-tree';
|
|
66
|
+
import { systemdUserServicePid, systemdUserUnitName, systemdUserUnitPath } from '../controller/systemd-user';
|
|
67
|
+
import { installWindowsHostRecoveryPlugin } from '../../runtime/plugins/windows-host-recovery-install';
|
|
37
68
|
|
|
38
69
|
function output(value: unknown, json = true): void {
|
|
39
70
|
console.log(json ? JSON.stringify(value, null, 2) : String(value));
|
|
@@ -55,15 +86,125 @@ function launchdService(label?: string, plistPath?: string, role = 'RECOVERY_TUN
|
|
|
55
86
|
return { platform: 'launchd', label, ...(plistPath ? { plistPath } : {}) };
|
|
56
87
|
}
|
|
57
88
|
|
|
89
|
+
function systemdRecoveryTunnelService(unitName?: string): SystemdUserRecoveryTunnelServiceConfig | undefined {
|
|
90
|
+
if (!unitName) return undefined;
|
|
91
|
+
const normalized = systemdUserUnitName(unitName);
|
|
92
|
+
if (!/^[A-Za-z0-9_.@-]{1,180}\.service$/.test(normalized)) throw new Error('RECOVERY_TUNNEL_SYSTEMD_UNIT_INVALID');
|
|
93
|
+
return { platform: 'systemd-user', unitName: normalized };
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
export function recoveryOpenAiTunnelDefaultAlias(
|
|
97
|
+
controllerHome: string,
|
|
98
|
+
platform: NodeJS.Platform = process.platform,
|
|
99
|
+
host = hostname(),
|
|
100
|
+
): string {
|
|
101
|
+
const suffix = createHash('sha256').update(`${host}\0${platform}\0${resolve(controllerHome)}`).digest('hex').slice(0, 12);
|
|
102
|
+
return `forge-recovery-${suffix}`;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
export function assertDistinctRecoveryOpenAiTunnelIdentity(
|
|
106
|
+
recovery: RecoveryTunnelServiceConfig | undefined,
|
|
107
|
+
primary: PublicTunnelServiceConfig | undefined,
|
|
108
|
+
): void {
|
|
109
|
+
if (recovery?.platform !== 'openai-secure-tunnel' || primary?.platform !== 'openai-secure-tunnel') return;
|
|
110
|
+
if (recovery.alias === primary.alias) throw new Error('RECOVERY_OPENAI_TUNNEL_ALIAS_CONFLICT');
|
|
111
|
+
if (recovery.tunnelId === primary.tunnelId) throw new Error('RECOVERY_OPENAI_TUNNEL_ID_CONFLICT');
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
function openAiTunnelService(input: {
|
|
115
|
+
tunnelId?: string;
|
|
116
|
+
alias?: string;
|
|
117
|
+
runtimeApiKeyRef?: string;
|
|
118
|
+
profile?: string;
|
|
119
|
+
profileDir?: string;
|
|
120
|
+
adminProfile?: string;
|
|
121
|
+
mcpServerUrl: string;
|
|
122
|
+
defaultAlias: string;
|
|
123
|
+
role: string;
|
|
124
|
+
}): OpenAiSecureTunnelServiceConfig | undefined {
|
|
125
|
+
const supplied = Boolean(input.tunnelId || input.alias || input.runtimeApiKeyRef || input.profile || input.profileDir || input.adminProfile);
|
|
126
|
+
if (!supplied) return undefined;
|
|
127
|
+
if (!input.tunnelId) throw new Error(`${input.role}_OPENAI_TUNNEL_ID_REQUIRED`);
|
|
128
|
+
if (input.profileDir && !isAbsolute(input.profileDir)) throw new Error(`${input.role}_OPENAI_PROFILE_DIR_ABSOLUTE_REQUIRED`);
|
|
129
|
+
const service: OpenAiSecureTunnelServiceConfig = {
|
|
130
|
+
platform: 'openai-secure-tunnel',
|
|
131
|
+
alias: input.alias?.trim() || input.defaultAlias,
|
|
132
|
+
tunnelId: input.tunnelId.trim(),
|
|
133
|
+
mcpServerUrl: input.mcpServerUrl,
|
|
134
|
+
runtimeApiKeyRef: input.runtimeApiKeyRef?.trim(),
|
|
135
|
+
profile: input.profile?.trim(),
|
|
136
|
+
profileDir: input.profileDir ? resolve(input.profileDir) : undefined,
|
|
137
|
+
adminProfile: input.adminProfile?.trim(),
|
|
138
|
+
};
|
|
139
|
+
try { openAiSecureTunnelConnectArgs(service); } catch (error) {
|
|
140
|
+
throw new Error(`${input.role}_${error instanceof Error ? error.message : 'OPENAI_TUNNEL_CONFIG_INVALID'}`);
|
|
141
|
+
}
|
|
142
|
+
return service;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
|
|
146
|
+
export { recoveryControllerHomeMigrationPreflight };
|
|
147
|
+
export type { RecoveryControllerHomeMigrationPreflight };
|
|
148
|
+
|
|
58
149
|
export interface RecoveryConnectorDependencies {
|
|
150
|
+
platform?: NodeJS.Platform;
|
|
59
151
|
pathExists?: (path: string) => boolean;
|
|
60
|
-
launchdPid?: (role: '
|
|
152
|
+
launchdPid?: (role: 'daemon') => number | undefined;
|
|
153
|
+
systemdPid?: (role: 'daemon') => number | undefined;
|
|
61
154
|
tunnelLaunchdPid?: (label: string) => number | undefined;
|
|
155
|
+
tunnelSystemdPid?: (unitName: string) => number | undefined;
|
|
156
|
+
openAiTunnelStatus?: (service: OpenAiSecureTunnelServiceConfig) => OpenAiSecureTunnelRuntimeObservation;
|
|
62
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;
|
|
63
203
|
}
|
|
64
204
|
|
|
65
205
|
export interface RecoveryConnectorDescriptor {
|
|
66
206
|
name: 'Forge Recovery';
|
|
207
|
+
identity: RecoveryMachineIdentity;
|
|
67
208
|
transport: 'streamable_http';
|
|
68
209
|
url: string;
|
|
69
210
|
public: boolean;
|
|
@@ -78,9 +219,22 @@ export interface RecoveryConnectorDescriptor {
|
|
|
78
219
|
};
|
|
79
220
|
healthUrl: string;
|
|
80
221
|
services: {
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
222
|
+
recovery: { label: string; platform: 'launchd' | 'systemd-user'; serviceInstalled: boolean; plistInstalled: boolean; running: boolean; pid?: number };
|
|
223
|
+
tunnel: {
|
|
224
|
+
configured: boolean;
|
|
225
|
+
platform?: 'launchd' | 'systemd-user' | 'openai-secure-tunnel';
|
|
226
|
+
label?: string;
|
|
227
|
+
unitName?: string;
|
|
228
|
+
alias?: string;
|
|
229
|
+
tunnelId?: string;
|
|
230
|
+
serviceInstalled?: boolean;
|
|
231
|
+
plistInstalled: boolean;
|
|
232
|
+
restartSafe: boolean;
|
|
233
|
+
running: boolean;
|
|
234
|
+
healthy?: boolean;
|
|
235
|
+
ready?: boolean;
|
|
236
|
+
pid?: number;
|
|
237
|
+
};
|
|
84
238
|
};
|
|
85
239
|
tools: string[];
|
|
86
240
|
warnings: string[];
|
|
@@ -98,61 +252,97 @@ export function recoveryConnectorDescriptor(
|
|
|
98
252
|
const url = configuredUrl ?? `${localOrigin}/recovery/mcp`;
|
|
99
253
|
const origin = new URL(url).origin;
|
|
100
254
|
const passphraseConfigured = Boolean(readMcpServiceOAuthPassphrase(home));
|
|
101
|
-
const
|
|
102
|
-
const
|
|
255
|
+
const recoveryIdentity = readRecoveryRuntimeIdentity(home, 'daemon');
|
|
256
|
+
const platform = dependencies.platform ?? process.platform;
|
|
257
|
+
const servicePlatform: 'launchd' | 'systemd-user' = platform === 'linux' ? 'systemd-user' : 'launchd';
|
|
103
258
|
const pathExists = dependencies.pathExists ?? existsSync;
|
|
104
259
|
const launchdPid = dependencies.launchdPid ?? recoveryLaunchdPid;
|
|
260
|
+
const systemdPid = dependencies.systemdPid ?? ((_role: 'daemon') => systemdUserServicePid(RECOVERY_DAEMON_LABEL));
|
|
261
|
+
const managedPid = () => servicePlatform === 'systemd-user' ? systemdPid('daemon') : launchdPid('daemon');
|
|
105
262
|
const processAlive = dependencies.processAlive ?? isProcessAlive;
|
|
106
|
-
const
|
|
263
|
+
const serviceOwnsRuntimeProcess = (managedPid: number | undefined, runtimePid: number | undefined) =>
|
|
264
|
+
recoveryManagedServiceOwnsRuntimeProcess(managedPid, runtimePid, {
|
|
265
|
+
processAlive,
|
|
266
|
+
processParentPid: dependencies.processParentPid,
|
|
267
|
+
});
|
|
268
|
+
const configuredTunnel = config.recoveryTunnelService;
|
|
269
|
+
const tunnelService = configuredTunnel?.platform === 'launchd' ? configuredTunnel : undefined;
|
|
270
|
+
const systemdTunnelService = configuredTunnel?.platform === 'systemd-user' ? configuredTunnel : undefined;
|
|
271
|
+
const openAiTunnelService = configuredTunnel?.platform === 'openai-secure-tunnel' ? configuredTunnel : undefined;
|
|
107
272
|
const tunnelContract = tunnelService ? inspectRecoveryTunnelLaunchdContract(tunnelService) : undefined;
|
|
108
273
|
const tunnelLaunchdPid = tunnelService
|
|
109
274
|
? (dependencies.tunnelLaunchdPid ?? recoveryLaunchdServicePid)(tunnelService.label)
|
|
110
275
|
: undefined;
|
|
111
276
|
const tunnelPlistInstalled = Boolean(tunnelContract?.plistPath && pathExists(tunnelContract.plistPath));
|
|
112
|
-
const
|
|
113
|
-
const
|
|
114
|
-
const
|
|
115
|
-
const
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
const
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
277
|
+
const systemdTunnelUnitName = systemdTunnelService?.unitName.trim();
|
|
278
|
+
const systemdTunnelIdentityValid = Boolean(systemdTunnelUnitName && /^[A-Za-z0-9_.@-]{1,180}\.service$/.test(systemdTunnelUnitName));
|
|
279
|
+
const systemdTunnelInstalled = Boolean(systemdTunnelIdentityValid && pathExists(systemdUserUnitPath(systemdTunnelUnitName!)));
|
|
280
|
+
const systemdTunnelPid = systemdTunnelIdentityValid
|
|
281
|
+
? (dependencies.tunnelSystemdPid ?? ((unitName: string) => systemdUserServicePid(unitName)))(systemdTunnelUnitName!)
|
|
282
|
+
: undefined;
|
|
283
|
+
const openAiTunnelStatus = openAiTunnelService
|
|
284
|
+
? (dependencies.openAiTunnelStatus ?? ((service: OpenAiSecureTunnelServiceConfig) => {
|
|
285
|
+
const status = spawnSync('tunnel-client', openAiSecureTunnelStatusArgs(service.alias, service), {
|
|
286
|
+
encoding: 'utf8', stdio: ['ignore', 'pipe', 'pipe'], timeout: 15_000,
|
|
287
|
+
});
|
|
288
|
+
return parseOpenAiSecureTunnelRuntimeStatus(status.stdout || '{}', { alias: service.alias, tunnelId: service.tunnelId, mcpServerUrl: service.mcpServerUrl });
|
|
289
|
+
}))(openAiTunnelService)
|
|
290
|
+
: undefined;
|
|
291
|
+
let openAiRestartSafe = false;
|
|
292
|
+
if (openAiTunnelService) {
|
|
293
|
+
try { openAiSecureTunnelConnectArgs(openAiTunnelService); openAiRestartSafe = true; } catch { openAiRestartSafe = false; }
|
|
294
|
+
}
|
|
295
|
+
const tunnelRestartSafe = openAiTunnelService
|
|
296
|
+
? openAiRestartSafe
|
|
297
|
+
: systemdTunnelService
|
|
298
|
+
? systemdTunnelIdentityValid && systemdTunnelInstalled
|
|
299
|
+
: Boolean(tunnelContract?.restartSafe);
|
|
300
|
+
const tunnelRunning = openAiTunnelService
|
|
301
|
+
? openAiTunnelStatus?.running === true
|
|
302
|
+
: systemdTunnelService
|
|
303
|
+
? Boolean(systemdTunnelPid && processAlive(systemdTunnelPid))
|
|
304
|
+
: Boolean(tunnelLaunchdPid && processAlive(tunnelLaunchdPid));
|
|
305
|
+
const tunnelHealthy = openAiTunnelService ? openAiTunnelStatus?.healthy === true : tunnelRunning;
|
|
306
|
+
const tunnelReady = openAiTunnelService ? openAiTunnelStatus?.ok === true : tunnelRestartSafe && tunnelRunning;
|
|
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)
|
|
132
315
|
&& authority.current
|
|
133
|
-
&&
|
|
134
|
-
&&
|
|
316
|
+
&& recoveryIdentity.releaseRevision === authority.current.releaseRevision
|
|
317
|
+
&& recoveryIdentity.manifestSha256 === authority.current.manifestSha256,
|
|
135
318
|
);
|
|
136
|
-
const installed = Boolean(authority.current &&
|
|
319
|
+
const installed = Boolean(authority.current && recoveryServiceInstalled);
|
|
137
320
|
const publicEndpoint = Boolean(configuredUrl?.startsWith('https://'));
|
|
138
321
|
const warnings: string[] = [];
|
|
139
322
|
if (!authority.current) warnings.push('No current immutable Forge Recovery release is installed. Run forge recovery install.');
|
|
140
|
-
if (!
|
|
141
|
-
if (!
|
|
142
|
-
if (!
|
|
143
|
-
else if (
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
else 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.');
|
|
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.');
|
|
326
|
+
else if (openAiTunnelService) {
|
|
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.');
|
|
328
|
+
else if (!tunnelRunning) warnings.push(`The dedicated OpenAI Recovery tunnel runtime ${openAiTunnelService.alias} is not running.`);
|
|
329
|
+
else if (!tunnelHealthy || !tunnelReady) warnings.push(`The dedicated OpenAI Recovery tunnel runtime ${openAiTunnelService.alias} is not healthy and ready.`);
|
|
330
|
+
} else if (!configuredUrl) warnings.push('The configured Recovery tunnel requires --recovery-public-url.');
|
|
331
|
+
else if (!publicEndpoint) warnings.push('ChatGPT Recovery Connector requires an HTTPS public endpoint for managed public tunnels.');
|
|
332
|
+
else if (systemdTunnelService && !systemdTunnelInstalled) warnings.push(`The dedicated Forge Recovery systemd-user tunnel unit ${systemdTunnelUnitName ?? systemdTunnelService.unitName} is not installed.`);
|
|
333
|
+
else if (systemdTunnelService && !tunnelRunning) warnings.push(`The dedicated Forge Recovery systemd-user tunnel unit ${systemdTunnelUnitName} is not running.`);
|
|
334
|
+
else if (!systemdTunnelService && !tunnelPlistInstalled) warnings.push('The dedicated Forge Recovery tunnel plist is not installed.');
|
|
335
|
+
else if (!systemdTunnelService && !tunnelRestartSafe) warnings.push('The dedicated Forge Recovery tunnel plist must use RunAtLoad=true and unconditional KeepAlive=true.');
|
|
336
|
+
else if (!systemdTunnelService && !tunnelRunning) warnings.push('The dedicated Forge Recovery tunnel service is not running.');
|
|
148
337
|
if (!passphraseConfigured) warnings.push('MCP OAuth passphrase is not configured. Run forge mcp setup chatgpt first.');
|
|
149
338
|
|
|
150
339
|
return {
|
|
151
340
|
name: 'Forge Recovery',
|
|
341
|
+
identity: recoveryMachineIdentity(config, { platform }),
|
|
152
342
|
transport: 'streamable_http',
|
|
153
343
|
url,
|
|
154
344
|
public: publicEndpoint,
|
|
155
|
-
readyForChatGPT: installed &&
|
|
345
|
+
readyForChatGPT: installed && recoveryRunning && tunnelReady && (openAiTunnelService ? true : publicEndpoint) && passphraseConfigured,
|
|
156
346
|
installed,
|
|
157
347
|
currentRelease: authority.current?.releaseRevision,
|
|
158
348
|
previousRelease: authority.previous?.releaseRevision,
|
|
@@ -163,25 +353,26 @@ export function recoveryConnectorDescriptor(
|
|
|
163
353
|
},
|
|
164
354
|
healthUrl: `${origin}/recovery/health`,
|
|
165
355
|
services: {
|
|
166
|
-
|
|
167
|
-
label:
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
label: RECOVERY_WATCHDOG_LABEL,
|
|
174
|
-
plistInstalled: watchdogPlistInstalled,
|
|
175
|
-
running: watchdogRunning,
|
|
176
|
-
...(watchdogIdentity ? { pid: watchdogIdentity.pid } : {}),
|
|
356
|
+
recovery: {
|
|
357
|
+
label: RECOVERY_DAEMON_LABEL,
|
|
358
|
+
platform: servicePlatform,
|
|
359
|
+
serviceInstalled: recoveryServiceInstalled,
|
|
360
|
+
plistInstalled: recoveryPlistInstalled,
|
|
361
|
+
running: recoveryRunning,
|
|
362
|
+
...(recoveryIdentity ? { pid: recoveryIdentity.pid } : {}),
|
|
177
363
|
},
|
|
178
364
|
tunnel: {
|
|
179
|
-
configured: Boolean(
|
|
365
|
+
configured: Boolean(configuredTunnel),
|
|
366
|
+
...(configuredTunnel ? { platform: configuredTunnel.platform } : {}),
|
|
180
367
|
...(tunnelService ? { label: tunnelService.label } : {}),
|
|
368
|
+
...(systemdTunnelService ? { unitName: systemdTunnelUnitName ?? systemdTunnelService.unitName } : {}),
|
|
369
|
+
...(openAiTunnelService ? { alias: openAiTunnelService.alias, tunnelId: openAiTunnelService.tunnelId } : {}),
|
|
370
|
+
serviceInstalled: openAiTunnelService ? openAiRestartSafe : systemdTunnelService ? systemdTunnelInstalled : tunnelPlistInstalled,
|
|
181
371
|
plistInstalled: tunnelPlistInstalled,
|
|
182
372
|
restartSafe: tunnelRestartSafe,
|
|
183
373
|
running: tunnelRunning,
|
|
184
|
-
...(
|
|
374
|
+
...(openAiTunnelService ? { healthy: tunnelHealthy, ready: tunnelReady } : {}),
|
|
375
|
+
...(systemdTunnelPid ? { pid: systemdTunnelPid } : tunnelLaunchdPid ? { pid: tunnelLaunchdPid } : {}),
|
|
185
376
|
},
|
|
186
377
|
},
|
|
187
378
|
tools: RECOVERY_TOOLS.map((tool) => tool.name),
|
|
@@ -189,6 +380,12 @@ export function recoveryConnectorDescriptor(
|
|
|
189
380
|
};
|
|
190
381
|
}
|
|
191
382
|
|
|
383
|
+
export function recoveryConnectorHasExternalTransport(
|
|
384
|
+
connector: Pick<RecoveryConnectorDescriptor, 'public' | 'services'>,
|
|
385
|
+
): boolean {
|
|
386
|
+
return connector.public || connector.services.tunnel.platform === 'openai-secure-tunnel';
|
|
387
|
+
}
|
|
388
|
+
|
|
192
389
|
export interface RecoveryConnectorVerificationDependencies {
|
|
193
390
|
fetcher?: typeof fetch;
|
|
194
391
|
random?: (size: number) => Buffer;
|
|
@@ -203,7 +400,15 @@ export interface RecoveryConnectorVerificationResult {
|
|
|
203
400
|
authorizationMetadata: { ok: boolean; status?: number };
|
|
204
401
|
protectedResourceMetadata: { ok: boolean; status?: number };
|
|
205
402
|
unauthenticatedChallenge: { ok: boolean; status?: number };
|
|
206
|
-
oauthPkce: {
|
|
403
|
+
oauthPkce: {
|
|
404
|
+
ok: boolean;
|
|
405
|
+
registrationStatus?: number;
|
|
406
|
+
authorizationStatus?: number;
|
|
407
|
+
tokenStatus?: number;
|
|
408
|
+
clientOwner?: 'recovery_verifier';
|
|
409
|
+
clientReused?: boolean;
|
|
410
|
+
credentialRetirement?: 'shared_recovery_token_not_individually_revocable';
|
|
411
|
+
};
|
|
207
412
|
mcp: {
|
|
208
413
|
ok: boolean;
|
|
209
414
|
initializeStatus?: number;
|
|
@@ -224,7 +429,25 @@ function jsonObject(value: unknown): Record<string, unknown> {
|
|
|
224
429
|
}
|
|
225
430
|
|
|
226
431
|
async function responseJson(response: Response): Promise<Record<string, unknown>> {
|
|
227
|
-
try {
|
|
432
|
+
try {
|
|
433
|
+
const text = await response.text();
|
|
434
|
+
if (!text.trim()) return {};
|
|
435
|
+
if (/text\/event-stream/i.test(response.headers.get('content-type') ?? '')) {
|
|
436
|
+
for (const line of text.split(/\r?\n/)) {
|
|
437
|
+
if (!line.startsWith('data:')) continue;
|
|
438
|
+
try {
|
|
439
|
+
const payload = jsonObject(JSON.parse(line.slice('data:'.length).trim()));
|
|
440
|
+
if (Object.keys(payload).length > 0) return payload;
|
|
441
|
+
} catch {
|
|
442
|
+
// Ignore non-JSON SSE fields and keep looking for the MCP data event.
|
|
443
|
+
}
|
|
444
|
+
}
|
|
445
|
+
return {};
|
|
446
|
+
}
|
|
447
|
+
return jsonObject(JSON.parse(text));
|
|
448
|
+
} catch {
|
|
449
|
+
return {};
|
|
450
|
+
}
|
|
228
451
|
}
|
|
229
452
|
|
|
230
453
|
export async function verifyRecoveryConnector(
|
|
@@ -250,7 +473,9 @@ export async function verifyRecoveryConnector(
|
|
|
250
473
|
});
|
|
251
474
|
|
|
252
475
|
if (!connector.readyForChatGPT) failures.push(...connector.warnings.map((warning) => `readiness: ${warning}`));
|
|
253
|
-
if (!connector
|
|
476
|
+
if (!recoveryConnectorHasExternalTransport(connector)) {
|
|
477
|
+
failures.push('readiness: Recovery Connector has neither an HTTPS public endpoint nor a dedicated OpenAI Secure MCP Tunnel.');
|
|
478
|
+
}
|
|
254
479
|
|
|
255
480
|
const origin = new URL(connector.url).origin;
|
|
256
481
|
try {
|
|
@@ -325,12 +550,13 @@ export async function verifyRecoveryConnector(
|
|
|
325
550
|
failures.push('oauthPkce: MCP OAuth passphrase is not configured.');
|
|
326
551
|
} else {
|
|
327
552
|
try {
|
|
328
|
-
const redirectUri =
|
|
553
|
+
const redirectUri = RECOVERY_VERIFIER_OAUTH_REDIRECT_URI;
|
|
329
554
|
const registration = await request(`${origin}/recovery/oauth/register`, {
|
|
330
555
|
method: 'POST',
|
|
331
556
|
headers: { 'content-type': 'application/json' },
|
|
332
557
|
body: JSON.stringify({
|
|
333
|
-
|
|
558
|
+
client_id: RECOVERY_VERIFIER_OAUTH_CLIENT_ID,
|
|
559
|
+
client_name: RECOVERY_VERIFIER_OAUTH_CLIENT_NAME,
|
|
334
560
|
redirect_uris: [redirectUri],
|
|
335
561
|
grant_types: ['authorization_code'],
|
|
336
562
|
response_types: ['code'],
|
|
@@ -339,7 +565,11 @@ export async function verifyRecoveryConnector(
|
|
|
339
565
|
});
|
|
340
566
|
const registrationBody = await responseJson(registration);
|
|
341
567
|
const clientId = typeof registrationBody.client_id === 'string' ? registrationBody.client_id : '';
|
|
342
|
-
|
|
568
|
+
const clientOwner = registrationBody.forge_client_owner;
|
|
569
|
+
const clientReused = registrationBody.forge_client_reused === true;
|
|
570
|
+
if (registration.status !== 201 || clientId !== RECOVERY_VERIFIER_OAUTH_CLIENT_ID || clientOwner !== 'recovery_verifier') {
|
|
571
|
+
throw new Error(`dynamic verifier registration HTTP ${registration.status}`);
|
|
572
|
+
}
|
|
343
573
|
|
|
344
574
|
const verifier = random(32).toString('base64url');
|
|
345
575
|
const challenge = createHash('sha256').update(verifier).digest('base64url');
|
|
@@ -388,6 +618,13 @@ export async function verifyRecoveryConnector(
|
|
|
388
618
|
registrationStatus: registration.status,
|
|
389
619
|
authorizationStatus: authorization.status,
|
|
390
620
|
tokenStatus: tokenResponse.status,
|
|
621
|
+
clientOwner: 'recovery_verifier',
|
|
622
|
+
clientReused,
|
|
623
|
+
// Recovery MCP currently uses one configured shared bearer token, so
|
|
624
|
+
// there is no verifier-specific credential that can be revoked without
|
|
625
|
+
// revoking Recovery itself. The reserved client slot keeps verifier
|
|
626
|
+
// registration state bounded across success and failure loops.
|
|
627
|
+
credentialRetirement: 'shared_recovery_token_not_individually_revocable',
|
|
391
628
|
};
|
|
392
629
|
|
|
393
630
|
const rpc = async (id: number | undefined, method: string, params?: Record<string, unknown>) => {
|
|
@@ -401,7 +638,13 @@ export async function verifyRecoveryConnector(
|
|
|
401
638
|
},
|
|
402
639
|
body: JSON.stringify({ jsonrpc: '2.0', ...(id === undefined ? {} : { id }), method, ...(params ? { params } : {}) }),
|
|
403
640
|
});
|
|
404
|
-
if (
|
|
641
|
+
if (response.headers.get('mcp-session-id')?.trim()) {
|
|
642
|
+
throw new Error(`${method} unexpectedly established transport session state`);
|
|
643
|
+
}
|
|
644
|
+
if (method === 'notifications/initialized') {
|
|
645
|
+
if (response.status !== 202) throw new Error(`${method} HTTP ${response.status}`);
|
|
646
|
+
return { response, result: {} as Record<string, unknown> };
|
|
647
|
+
}
|
|
405
648
|
const body = await responseJson(response);
|
|
406
649
|
const rpcError = jsonObject(body.error);
|
|
407
650
|
if (response.status !== 200 || Object.keys(rpcError).length > 0) {
|
|
@@ -444,7 +687,7 @@ export async function verifyRecoveryConnector(
|
|
|
444
687
|
runtimeStatusCall: runtimeStatusCall.response.status === 200,
|
|
445
688
|
listReleasesCall: listReleasesCall.response.status === 200,
|
|
446
689
|
};
|
|
447
|
-
if (!mcpOk) failures.push('mcp: initialize, Forge version, tool surface, or read-only calls did not match the Recovery contract.');
|
|
690
|
+
if (!mcpOk) failures.push('mcp: stateless initialize, Forge version, tool surface, or read-only calls did not match the Recovery contract.');
|
|
448
691
|
} catch (error) {
|
|
449
692
|
failures.push(`oauthPkce/mcp: ${error instanceof Error ? error.message : String(error)}`);
|
|
450
693
|
}
|
|
@@ -516,6 +759,10 @@ export function buildRecoveryCommand(): Command {
|
|
|
516
759
|
}) => {
|
|
517
760
|
const home = resolveControllerHome(opts.controllerHome);
|
|
518
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
|
+
}
|
|
519
766
|
const current = loadRecoveryConfig(home);
|
|
520
767
|
const primaryConnectorBase = launchdService(
|
|
521
768
|
opts.primaryConnectorServiceLabel,
|
|
@@ -529,13 +776,15 @@ export function buildRecoveryCommand(): Command {
|
|
|
529
776
|
const installed = await installStandaloneRecovery({
|
|
530
777
|
controllerHome: home,
|
|
531
778
|
repoRoot,
|
|
779
|
+
primaryRuntimeSourceRepositoryId: primaryRuntimeSourceRepository.repoId,
|
|
532
780
|
port: current.gateway?.port ?? 8787,
|
|
533
781
|
publicMcpUrl: current.publicMcpUrl,
|
|
534
782
|
recoveryPublicUrl: current.recoveryPublicUrl,
|
|
535
783
|
recoveryTunnelService: current.recoveryTunnelService,
|
|
536
784
|
primaryPublicTunnelService: current.primaryPublicTunnelService,
|
|
537
|
-
primaryRuntimeService: current.primaryRuntimeService ??
|
|
785
|
+
primaryRuntimeService: current.primaryRuntimeService ?? defaultPrimaryRuntimeServiceConfig(),
|
|
538
786
|
primaryConnectorService,
|
|
787
|
+
profile: 'self-healing',
|
|
539
788
|
});
|
|
540
789
|
const refreshed = loadRecoveryConfig(home);
|
|
541
790
|
const runtime = await stageAndActivateConfiguredRuntimeRelease(refreshed);
|
|
@@ -620,20 +869,121 @@ export function buildRecoveryCommand(): Command {
|
|
|
620
869
|
if (!result.ok) process.exitCode = 1;
|
|
621
870
|
});
|
|
622
871
|
|
|
872
|
+
command.command('migrate-controller-home')
|
|
873
|
+
.description('Transactionally relocate Forge Controller Home on Linux/WSL through an independent transient systemd worker')
|
|
874
|
+
.requiredOption('--from <path>', 'Current Controller Home authority')
|
|
875
|
+
.requiredOption('--controller-home <path>', 'Destination user-level Controller Home')
|
|
876
|
+
.option('--archive-suffix <suffix>', 'Stable suffix for an authority-free destination shell archive')
|
|
877
|
+
.option('--timeout-ms <ms>', 'Overall migration transaction timeout in milliseconds', '240000')
|
|
878
|
+
.action(async (opts: { from: string; controllerHome: string; archiveSuffix?: string; timeoutMs: string }) => {
|
|
879
|
+
if (process.platform !== 'linux') throw new Error('RECOVERY_CONTROLLER_HOME_MIGRATION_LINUX_ONLY');
|
|
880
|
+
const timeoutMs = Number(opts.timeoutMs);
|
|
881
|
+
if (!Number.isInteger(timeoutMs) || timeoutMs < 30_000 || timeoutMs > 900_000) {
|
|
882
|
+
throw new Error('RECOVERY_CONTROLLER_HOME_MIGRATION_TIMEOUT_INVALID');
|
|
883
|
+
}
|
|
884
|
+
const scheduled = scheduleLinuxControllerHomeMigration({
|
|
885
|
+
sourceHome: resolve(opts.from),
|
|
886
|
+
destinationHome: resolveControllerHome(opts.controllerHome),
|
|
887
|
+
...(opts.archiveSuffix ? { archiveSuffix: opts.archiveSuffix } : {}),
|
|
888
|
+
timeoutMs,
|
|
889
|
+
});
|
|
890
|
+
output({
|
|
891
|
+
status: 'migration_scheduled',
|
|
892
|
+
operationId: scheduled.request.operationId,
|
|
893
|
+
sourceHome: scheduled.request.sourceHome,
|
|
894
|
+
destinationHome: scheduled.request.destinationHome,
|
|
895
|
+
workerUnit: scheduled.request.workerUnit,
|
|
896
|
+
receiptPath: scheduled.request.receiptPath,
|
|
897
|
+
logPath: scheduled.request.logPath,
|
|
898
|
+
preflight: scheduled.preflight,
|
|
899
|
+
});
|
|
900
|
+
});
|
|
901
|
+
|
|
902
|
+
command.command('migrate-controller-home-worker')
|
|
903
|
+
.description('Internal Linux/WSL transient worker for a durable Controller Home migration request')
|
|
904
|
+
.requiredOption('--request <path>', 'Durable migration request written before service cutover')
|
|
905
|
+
.action(async (opts: { request: string }) => {
|
|
906
|
+
if (process.platform !== 'linux') throw new Error('RECOVERY_CONTROLLER_HOME_MIGRATION_LINUX_ONLY');
|
|
907
|
+
const receipt = await runLinuxControllerHomeMigrationRequest(resolve(opts.request));
|
|
908
|
+
// A durable terminal receipt, including failed-after-rollback, is a completed worker transaction.
|
|
909
|
+
// Only an unhandled process failure before a terminal receipt should trigger systemd Restart=on-failure.
|
|
910
|
+
output(receipt);
|
|
911
|
+
});
|
|
912
|
+
|
|
913
|
+
command.command('rollback-controller-home-migration')
|
|
914
|
+
.description('Rollback a stopped Controller Home relocation before any writer is restarted')
|
|
915
|
+
.requiredOption('--from <path>', 'Original Controller Home path')
|
|
916
|
+
.requiredOption('--controller-home <path>', 'Relocated user-level Controller Home path')
|
|
917
|
+
.option('--archived-destination-home <path>', 'Archived authority-free destination shell returned by migration')
|
|
918
|
+
.action(async (opts: { from: string; controllerHome: string; archivedDestinationHome?: string }) => {
|
|
919
|
+
if (process.platform !== 'linux') throw new Error('RECOVERY_CONTROLLER_HOME_MIGRATION_LINUX_ONLY');
|
|
920
|
+
const sourceHome = resolve(opts.from);
|
|
921
|
+
const destinationHome = resolveControllerHome(opts.controllerHome);
|
|
922
|
+
const preflight = recoveryControllerHomeMigrationPreflight(destinationHome, sourceHome);
|
|
923
|
+
if (preflight.liveOwners.length > 0) {
|
|
924
|
+
throw new Error(`RECOVERY_CONTROLLER_HOME_MIGRATION_OWNERS_LIVE: ${preflight.liveOwners.map((entry) => `${entry.label}:${entry.pid}`).join(',')}`);
|
|
925
|
+
}
|
|
926
|
+
const relocation: StoppedControllerHomeAuthorityRelocation = {
|
|
927
|
+
migrated: true,
|
|
928
|
+
sourceHome,
|
|
929
|
+
destinationHome,
|
|
930
|
+
...(opts.archivedDestinationHome ? { archivedDestinationHome: resolve(opts.archivedDestinationHome) } : {}),
|
|
931
|
+
};
|
|
932
|
+
rollbackStoppedControllerHomeAuthorityRelocation(relocation);
|
|
933
|
+
output({ status: 'rolled_back', relocation });
|
|
934
|
+
});
|
|
935
|
+
|
|
936
|
+
command.command('windows-host-register')
|
|
937
|
+
.description('Register the Windows-host Recovery provider using discovered or explicitly bound host paths')
|
|
938
|
+
.option('--controller-home <path>', 'Override Controller Home')
|
|
939
|
+
.option('--rescue-root <path>', 'Override the local Recovery helper root')
|
|
940
|
+
.option('--recovery-script-host <path>', 'Host-visible path to ForgeRecovery.ps1')
|
|
941
|
+
.option('--recovery-script-windows <path>', 'Windows path to ForgeRecovery.ps1')
|
|
942
|
+
.option('--powershell-host <path>', 'Host-visible path to powershell.exe')
|
|
943
|
+
.option('--powershell-windows <path>', 'Windows path to powershell.exe')
|
|
944
|
+
.option('--disabled', 'Register the provider disabled')
|
|
945
|
+
.action((opts) => {
|
|
946
|
+
const result = installWindowsHostRecoveryPlugin({
|
|
947
|
+
controllerHome: resolveControllerHome(opts.controllerHome),
|
|
948
|
+
rescueRoot: opts.rescueRoot,
|
|
949
|
+
recoveryScriptHostPath: opts.recoveryScriptHost,
|
|
950
|
+
recoveryScriptWindowsPath: opts.recoveryScriptWindows,
|
|
951
|
+
powershellHostPath: opts.powershellHost,
|
|
952
|
+
powershellWindowsPath: opts.powershellWindows,
|
|
953
|
+
enabled: opts.disabled !== true,
|
|
954
|
+
});
|
|
955
|
+
output({ status: 'registered', ...result });
|
|
956
|
+
});
|
|
957
|
+
|
|
623
958
|
command.command('install')
|
|
624
|
-
.description('Build and activate the
|
|
959
|
+
.description('Build Forge Recovery artifacts and activate only the explicitly selected persistent Recovery profile')
|
|
625
960
|
.requiredOption('--controller-home <path>', 'Explicit Controller Home')
|
|
961
|
+
.option('--profile <profile>', 'Recovery install profile: manual, gateway, or self-healing', 'manual')
|
|
626
962
|
.option('--port <port>', 'Loopback Recovery Gateway port', '8787')
|
|
627
963
|
.option('--public-mcp-url <url>', 'Primary Forge MCP public URL')
|
|
628
964
|
.option('--recovery-public-url <url>', 'Dedicated Forge Recovery MCP public URL')
|
|
629
965
|
.option('--recovery-tunnel-service-label <label>', 'Dedicated Recovery tunnel launchd label')
|
|
630
966
|
.option('--recovery-tunnel-service-plist <path>', 'Absolute Recovery tunnel launchd plist path')
|
|
967
|
+
.option('--recovery-tunnel-systemd-unit <unit>', 'Dedicated Recovery systemd --user tunnel unit (Linux only)')
|
|
968
|
+
.option('--recovery-openai-tunnel-id <id>', 'Dedicated Recovery OpenAI Secure MCP Tunnel id')
|
|
969
|
+
.option('--recovery-openai-tunnel-alias <alias>', 'Dedicated Recovery tunnel-client runtime alias (default: machine-specific forge-recovery-<id>)')
|
|
970
|
+
.option('--recovery-openai-runtime-api-key-ref <ref>', 'Recovery tunnel runtime API key reference (env:NAME or file:/absolute/path)')
|
|
971
|
+
.option('--recovery-openai-profile <profile>', 'Optional tunnel-client runtime profile name for Recovery')
|
|
972
|
+
.option('--recovery-openai-profile-dir <path>', 'Optional absolute tunnel-client profile directory for Recovery')
|
|
973
|
+
.option('--recovery-openai-admin-profile <profile>', 'Optional tunnel-client admin profile used for Recovery runtime connect')
|
|
631
974
|
.option('--primary-connector-service-label <label>', 'Primary OAuth/Connector launchd label managed by standalone Recovery')
|
|
632
975
|
.option('--primary-connector-service-plist <path>', 'Absolute primary OAuth/Connector launchd plist path')
|
|
633
976
|
.option('--primary-connector-local-url <url>', 'Local primary OAuth/Connector MCP endpoint used to distinguish Connector from tunnel failures')
|
|
634
977
|
.option('--primary-tunnel-service-label <label>', 'Primary public MCP tunnel launchd label managed by standalone Recovery')
|
|
635
978
|
.option('--primary-tunnel-service-plist <path>', 'Absolute primary public MCP tunnel launchd plist path')
|
|
636
|
-
.option('--
|
|
979
|
+
.option('--primary-openai-tunnel-id <id>', 'Primary OpenAI Secure MCP Tunnel id managed by Recovery')
|
|
980
|
+
.option('--primary-openai-tunnel-alias <alias>', 'Primary tunnel-client runtime alias (default: forge)')
|
|
981
|
+
.option('--primary-openai-runtime-api-key-ref <ref>', 'Primary tunnel runtime API key reference (env:NAME or file:/absolute/path)')
|
|
982
|
+
.option('--primary-openai-profile <profile>', 'Optional tunnel-client runtime profile name for primary Forge')
|
|
983
|
+
.option('--primary-openai-profile-dir <path>', 'Optional absolute tunnel-client profile directory for primary Forge')
|
|
984
|
+
.option('--primary-openai-admin-profile <profile>', 'Optional tunnel-client admin profile used for primary runtime connect')
|
|
985
|
+
.option('--primary-runtime-source-root <path>', 'Stable canonical/package source used by Recovery for future Runtime staging')
|
|
986
|
+
.option('--stage-only', 'Compatibility alias: build/canary only and do not mutate installed Recovery config or services')
|
|
637
987
|
.action(async (opts: {
|
|
638
988
|
controllerHome: string;
|
|
639
989
|
port: string;
|
|
@@ -641,36 +991,112 @@ export function buildRecoveryCommand(): Command {
|
|
|
641
991
|
recoveryPublicUrl?: string;
|
|
642
992
|
recoveryTunnelServiceLabel?: string;
|
|
643
993
|
recoveryTunnelServicePlist?: string;
|
|
994
|
+
recoveryTunnelSystemdUnit?: string;
|
|
995
|
+
recoveryOpenaiTunnelId?: string;
|
|
996
|
+
recoveryOpenaiTunnelAlias?: string;
|
|
997
|
+
recoveryOpenaiRuntimeApiKeyRef?: string;
|
|
998
|
+
recoveryOpenaiProfile?: string;
|
|
999
|
+
recoveryOpenaiProfileDir?: string;
|
|
1000
|
+
recoveryOpenaiAdminProfile?: string;
|
|
644
1001
|
primaryConnectorServiceLabel?: string;
|
|
645
1002
|
primaryConnectorServicePlist?: string;
|
|
646
1003
|
primaryConnectorLocalUrl?: string;
|
|
647
1004
|
primaryTunnelServiceLabel?: string;
|
|
648
1005
|
primaryTunnelServicePlist?: string;
|
|
1006
|
+
primaryOpenaiTunnelId?: string;
|
|
1007
|
+
primaryOpenaiTunnelAlias?: string;
|
|
1008
|
+
primaryOpenaiRuntimeApiKeyRef?: string;
|
|
1009
|
+
primaryOpenaiProfile?: string;
|
|
1010
|
+
primaryOpenaiProfileDir?: string;
|
|
1011
|
+
primaryOpenaiAdminProfile?: string;
|
|
1012
|
+
primaryRuntimeSourceRoot?: string;
|
|
1013
|
+
profile: string;
|
|
649
1014
|
stageOnly?: boolean;
|
|
650
1015
|
}) => {
|
|
651
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');
|
|
652
1019
|
const port = Number(opts.port);
|
|
653
1020
|
if (!Number.isInteger(port) || port < 1024 || port > 65535) throw new Error('RECOVERY_PORT_INVALID');
|
|
654
|
-
const
|
|
655
|
-
const
|
|
1021
|
+
const recoveryLaunchdTunnel = launchdService(opts.recoveryTunnelServiceLabel, opts.recoveryTunnelServicePlist, 'RECOVERY_TUNNEL') as PublicTunnelServiceConfig | undefined;
|
|
1022
|
+
const recoverySystemdTunnel = systemdRecoveryTunnelService(opts.recoveryTunnelSystemdUnit);
|
|
1023
|
+
if (recoveryLaunchdTunnel && process.platform === 'linux') throw new Error('RECOVERY_TUNNEL_LAUNCHD_UNSUPPORTED_ON_LINUX');
|
|
1024
|
+
if (recoverySystemdTunnel && process.platform !== 'linux') throw new Error('RECOVERY_TUNNEL_SYSTEMD_UNSUPPORTED_ON_THIS_PLATFORM');
|
|
1025
|
+
const recoveryLocalMcpUrl = `http://127.0.0.1:${port}/recovery/mcp`;
|
|
1026
|
+
const recoveryOpenAiTunnel = openAiTunnelService({
|
|
1027
|
+
tunnelId: opts.recoveryOpenaiTunnelId,
|
|
1028
|
+
alias: opts.recoveryOpenaiTunnelAlias,
|
|
1029
|
+
runtimeApiKeyRef: opts.recoveryOpenaiRuntimeApiKeyRef,
|
|
1030
|
+
profile: opts.recoveryOpenaiProfile,
|
|
1031
|
+
profileDir: opts.recoveryOpenaiProfileDir,
|
|
1032
|
+
adminProfile: opts.recoveryOpenaiAdminProfile,
|
|
1033
|
+
mcpServerUrl: recoveryLocalMcpUrl,
|
|
1034
|
+
defaultAlias: recoveryOpenAiTunnelDefaultAlias(home),
|
|
1035
|
+
role: 'RECOVERY',
|
|
1036
|
+
});
|
|
1037
|
+
const recoveryTunnelOwners = [recoveryLaunchdTunnel, recoverySystemdTunnel, recoveryOpenAiTunnel].filter(Boolean);
|
|
1038
|
+
if (recoveryTunnelOwners.length > 1) throw new Error('RECOVERY_TUNNEL_OWNER_CONFLICT');
|
|
1039
|
+
const recoveryTunnelService: RecoveryTunnelServiceConfig | undefined = recoveryOpenAiTunnel ?? recoverySystemdTunnel ?? recoveryLaunchdTunnel;
|
|
1040
|
+
|
|
1041
|
+
const primaryConnectorLaunchd = launchdService(opts.primaryConnectorServiceLabel, opts.primaryConnectorServicePlist, 'RECOVERY_PRIMARY_CONNECTOR') as PrimaryConnectorServiceConfig | undefined;
|
|
656
1042
|
const primaryConnectorLocalUrl = endpoint(opts.primaryConnectorLocalUrl, 'RECOVERY_PRIMARY_CONNECTOR_LOCAL_URL');
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
: undefined;
|
|
661
|
-
|
|
1043
|
+
let primaryConnectorService: PrimaryConnectorServiceConfig | undefined;
|
|
1044
|
+
if (process.platform === 'linux') {
|
|
1045
|
+
if (primaryConnectorLaunchd) throw new Error('RECOVERY_PRIMARY_CONNECTOR_LAUNCHD_UNSUPPORTED_ON_LINUX');
|
|
1046
|
+
primaryConnectorService = primaryConnectorLocalUrl ? { platform: 'systemd-user', localMcpUrl: primaryConnectorLocalUrl } : undefined;
|
|
1047
|
+
} else {
|
|
1048
|
+
if (primaryConnectorLocalUrl && !primaryConnectorLaunchd) throw new Error('RECOVERY_PRIMARY_CONNECTOR_LABEL_REQUIRED_FOR_LOCAL_URL');
|
|
1049
|
+
primaryConnectorService = primaryConnectorLaunchd
|
|
1050
|
+
? { ...primaryConnectorLaunchd, ...(primaryConnectorLocalUrl ? { localMcpUrl: primaryConnectorLocalUrl } : {}) }
|
|
1051
|
+
: undefined;
|
|
1052
|
+
}
|
|
1053
|
+
|
|
1054
|
+
const primaryLaunchdTunnel = launchdService(opts.primaryTunnelServiceLabel, opts.primaryTunnelServicePlist, 'RECOVERY_PRIMARY_TUNNEL') as PublicTunnelServiceConfig | undefined;
|
|
1055
|
+
const primaryOpenAiTunnel = primaryConnectorLocalUrl ? openAiTunnelService({
|
|
1056
|
+
tunnelId: opts.primaryOpenaiTunnelId,
|
|
1057
|
+
alias: opts.primaryOpenaiTunnelAlias,
|
|
1058
|
+
runtimeApiKeyRef: opts.primaryOpenaiRuntimeApiKeyRef,
|
|
1059
|
+
profile: opts.primaryOpenaiProfile,
|
|
1060
|
+
profileDir: opts.primaryOpenaiProfileDir,
|
|
1061
|
+
adminProfile: opts.primaryOpenaiAdminProfile,
|
|
1062
|
+
mcpServerUrl: primaryConnectorLocalUrl,
|
|
1063
|
+
defaultAlias: 'forge',
|
|
1064
|
+
role: 'RECOVERY_PRIMARY',
|
|
1065
|
+
}) : undefined;
|
|
1066
|
+
const primaryOpenAiOptionsSupplied = Boolean(opts.primaryOpenaiTunnelId || opts.primaryOpenaiTunnelAlias || opts.primaryOpenaiRuntimeApiKeyRef || opts.primaryOpenaiProfile || opts.primaryOpenaiProfileDir || opts.primaryOpenaiAdminProfile);
|
|
1067
|
+
if (primaryOpenAiOptionsSupplied && !primaryConnectorLocalUrl) throw new Error('RECOVERY_PRIMARY_CONNECTOR_LOCAL_URL_REQUIRED_FOR_OPENAI_TUNNEL');
|
|
1068
|
+
if (primaryLaunchdTunnel && primaryOpenAiTunnel) throw new Error('RECOVERY_PRIMARY_TUNNEL_OWNER_CONFLICT');
|
|
1069
|
+
const primaryPublicTunnelService = primaryOpenAiTunnel ?? primaryLaunchdTunnel;
|
|
662
1070
|
if (primaryPublicTunnelService && !primaryConnectorService) throw new Error('RECOVERY_PRIMARY_CONNECTOR_REQUIRED_FOR_PRIMARY_TUNNEL');
|
|
1071
|
+
assertDistinctRecoveryOpenAiTunnelIdentity(recoveryTunnelService, primaryPublicTunnelService);
|
|
1072
|
+
|
|
663
1073
|
const recoveryPublicUrl = endpoint(opts.recoveryPublicUrl, 'RECOVERY_PUBLIC_URL');
|
|
664
|
-
if (
|
|
665
|
-
|
|
666
|
-
|
|
1074
|
+
if (profile === 'manual' && (recoveryTunnelService || recoveryPublicUrl)) throw new Error('RECOVERY_PROFILE_GATEWAY_REQUIRED');
|
|
1075
|
+
if (recoveryOpenAiTunnel && recoveryPublicUrl) throw new Error('RECOVERY_OPENAI_TUNNEL_PUBLIC_URL_CONFLICT');
|
|
1076
|
+
if ((recoveryLaunchdTunnel || recoverySystemdTunnel) && !recoveryPublicUrl) throw new Error('RECOVERY_PUBLIC_URL_AND_TUNNEL_SERVICE_MUST_BE_CONFIGURED_TOGETHER');
|
|
1077
|
+
if (!recoveryTunnelService && recoveryPublicUrl) throw new Error('RECOVERY_PUBLIC_URL_AND_TUNNEL_SERVICE_MUST_BE_CONFIGURED_TOGETHER');
|
|
1078
|
+
|
|
667
1079
|
const packageRoot = resolve(import.meta.dir, '..', '..', '..');
|
|
1080
|
+
const primaryRuntimeSourceRoot = opts.primaryRuntimeSourceRoot ? resolve(opts.primaryRuntimeSourceRoot) : packageRoot;
|
|
1081
|
+
const primaryRuntimeSourceRepository = findRegisteredRepositoryByCheckoutRoot(primaryRuntimeSourceRoot, home);
|
|
1082
|
+
if (!opts.stageOnly && !primaryRuntimeSourceRepository) {
|
|
1083
|
+
throw new Error(`RECOVERY_PRIMARY_RUNTIME_SOURCE_REPOSITORY_NOT_REGISTERED: ${primaryRuntimeSourceRoot}`);
|
|
1084
|
+
}
|
|
1085
|
+
if (!opts.stageOnly && /[\\/]\.forge[\\/]managed-worktrees[\\/]/.test(primaryRuntimeSourceRoot)) {
|
|
1086
|
+
throw new Error('RECOVERY_PRIMARY_RUNTIME_SOURCE_ROOT_DURABLE_REQUIRED');
|
|
1087
|
+
}
|
|
668
1088
|
const result = await installStandaloneRecovery({
|
|
669
1089
|
controllerHome: home,
|
|
670
|
-
repoRoot:
|
|
671
|
-
|
|
1090
|
+
repoRoot: primaryRuntimeSourceRoot,
|
|
1091
|
+
...(primaryRuntimeSourceRepository ? { primaryRuntimeSourceRepositoryId: primaryRuntimeSourceRepository.repoId } : {}),
|
|
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,
|
|
672
1096
|
port,
|
|
1097
|
+
profile,
|
|
673
1098
|
stageOnly: opts.stageOnly === true,
|
|
1099
|
+
primaryRuntimeService: defaultPrimaryRuntimeServiceConfig(),
|
|
674
1100
|
publicMcpUrl: endpoint(opts.publicMcpUrl, 'PUBLIC_MCP_URL'),
|
|
675
1101
|
recoveryPublicUrl,
|
|
676
1102
|
recoveryTunnelService,
|
|
@@ -679,6 +1105,7 @@ export function buildRecoveryCommand(): Command {
|
|
|
679
1105
|
});
|
|
680
1106
|
output({
|
|
681
1107
|
status: opts.stageOnly ? 'staged' : 'installed',
|
|
1108
|
+
profile: result.profile,
|
|
682
1109
|
staged: result.staged.release,
|
|
683
1110
|
activation: result.activated,
|
|
684
1111
|
connector: recoveryConnectorDescriptor(home),
|