machine-bridge-mcp 2.0.0 → 3.0.0-beta.102
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/CHANGELOG.md +1142 -0
- package/CONTRIBUTING.md +23 -25
- package/GOVERNANCE.md +2 -2
- package/README.md +58 -20
- package/SECURITY.md +161 -120
- package/SUPPORT.md +1 -1
- package/browser-extension/broker-auth.js +83 -0
- package/browser-extension/broker-liveness.js +35 -0
- package/browser-extension/browser-error-boundary.js +96 -0
- package/browser-extension/browser-operations.js +1456 -101
- package/browser-extension/devtools-input.js +195 -34
- package/browser-extension/devtools-observation.js +429 -0
- package/browser-extension/devtools-session.js +48 -0
- package/browser-extension/manifest.json +4 -3
- package/browser-extension/page-automation.js +578 -118
- package/browser-extension/pairing-bootstrap.js +42 -0
- package/browser-extension/pairing.js +28 -12
- package/browser-extension/service-worker.js +126 -106
- package/docs/AGENT_CONTEXT.md +13 -10
- package/docs/ARCHITECTURE.md +159 -67
- package/docs/AUDIT.md +1302 -4
- package/docs/CLIENTS.md +19 -6
- package/docs/COMPUTER_USE.md +297 -0
- package/docs/ENGINEERING.md +72 -13
- package/docs/GETTING_STARTED.md +18 -20
- package/docs/LOCAL_AUTHORIZATION.md +115 -72
- package/docs/LOCAL_AUTOMATION.md +27 -21
- package/docs/LOGGING.md +40 -19
- package/docs/MANAGED_JOBS.md +37 -34
- package/docs/MULTI_ACCOUNT.md +98 -37
- package/docs/OPERATIONS.md +145 -51
- package/docs/OVERVIEW.md +14 -11
- package/docs/POLICY_REFERENCE.md +71 -3
- package/docs/PRIVACY.md +41 -2
- package/docs/PROJECT_STANDARDS.md +29 -6
- package/docs/RELEASING.md +238 -64
- package/docs/TESTING.md +150 -39
- package/docs/THREAT_MODEL.md +164 -67
- package/docs/TOOL_REFERENCE.md +653 -60
- package/docs/UPGRADING.md +78 -18
- package/native/macos/MachineBridgeBackgroundInput.swift +1051 -0
- package/native/macos/MachineBridgeBackgroundInputSmokeFixture.swift +295 -0
- package/native/macos/MachineBridgeTrustBroker.swift +233 -0
- package/package.json +94 -16
- package/scripts/accepted-candidate-tarball.mjs +77 -0
- package/scripts/candidate-runtime-store.mjs +93 -0
- package/scripts/check-plan.mjs +73 -3
- package/scripts/check-runner.mjs +129 -17
- package/scripts/commit-message-check.mjs +5 -2
- package/scripts/consumer-package-security.mjs +293 -0
- package/scripts/coverage-check.mjs +251 -15
- package/scripts/coverage-generation.mjs +41 -0
- package/scripts/coverage-range-merge.mjs +41 -0
- package/scripts/foreground-daemon-recovery.mjs +88 -0
- package/scripts/generate-policy-reference.mjs +28 -5
- package/scripts/generate-tool-reference.mjs +1 -1
- package/scripts/generate-worker-types.mjs +21 -11
- package/scripts/github-backlog.mjs +11 -10
- package/scripts/github-push.mjs +62 -16
- package/scripts/github-release-asset.mjs +58 -0
- package/scripts/github-release.mjs +241 -132
- package/scripts/global-package-installation.mjs +68 -0
- package/scripts/hardened-npm-session.mjs +42 -0
- package/scripts/install-published-prerelease.mjs +198 -0
- package/scripts/local-release-acceptance.mjs +103 -45
- package/scripts/macos-background-input-smoke.mjs +515 -0
- package/scripts/network-retry.mjs +8 -1
- package/scripts/npm-global-prefix.mjs +27 -0
- package/scripts/npm-publication-policy.mjs +17 -0
- package/scripts/official-mcp-conformance.mjs +267 -0
- package/scripts/persistent-activation-process.mjs +101 -0
- package/scripts/prepare-pinned-npm.mjs +12 -69
- package/scripts/prerelease-activation.mjs +160 -0
- package/scripts/privacy-check.mjs +14 -6
- package/scripts/promotion-digest.mjs +128 -0
- package/scripts/publish-npm.mjs +260 -0
- package/scripts/published-release.mjs +132 -0
- package/scripts/release-acceptance.mjs +62 -54
- package/scripts/release-browser-extension-store.mjs +172 -0
- package/scripts/release-candidate-manifest.mjs +52 -0
- package/scripts/release-channel.mjs +106 -0
- package/scripts/release-diagnostic.mjs +41 -0
- package/scripts/release-impact-check.mjs +12 -22
- package/scripts/release-oauth-canary-core.mjs +325 -0
- package/scripts/release-oauth-canary-evidence.mjs +100 -0
- package/scripts/release-oauth-canary.mjs +127 -0
- package/scripts/release-publication-guard.mjs +67 -0
- package/scripts/release-soak.mjs +284 -0
- package/scripts/release-state.mjs +1 -1
- package/scripts/run-checks.mjs +44 -7
- package/scripts/run-worker-dry-run.mjs +21 -0
- package/scripts/sarif-security-gate.mjs +2 -1
- package/scripts/sbom-check.mjs +106 -0
- package/scripts/start-release-candidate.mjs +267 -44
- package/scripts/syntax-check.mjs +36 -14
- package/scripts/verification-generation-guard.mjs +15 -0
- package/scripts/verification-idle-sleep-guard.mjs +37 -0
- package/scripts/verification-state.mjs +108 -0
- package/scripts/wrangler-command-lifecycle.mjs +115 -0
- package/src/local/account-access.mjs +13 -1
- package/src/local/account-admin-response.mjs +92 -0
- package/src/local/account-admin.mjs +52 -19
- package/src/local/agent-context-projection.mjs +26 -7
- package/src/local/agent-context.mjs +88 -49
- package/src/local/agent-skill-discovery.mjs +16 -5
- package/src/local/app-automation-macos-jxa.mjs +350 -0
- package/src/local/app-automation.mjs +873 -163
- package/src/local/application-capability-projection.mjs +24 -0
- package/src/local/authority-context.mjs +106 -0
- package/src/local/autostart-log-maintenance.mjs +36 -0
- package/src/local/browser-bridge-http.mjs +5 -3
- package/src/local/browser-bridge.mjs +109 -31
- package/src/local/browser-broker-auth-http.mjs +67 -0
- package/src/local/browser-broker-auth.mjs +98 -0
- package/src/local/browser-broker-routes.mjs +63 -20
- package/src/local/browser-broker-server.mjs +17 -7
- package/src/local/browser-command.mjs +79 -30
- package/src/local/browser-computer-observation-service.mjs +266 -0
- package/src/local/browser-extension-identity.mjs +50 -0
- package/src/local/browser-extension-path.mjs +22 -0
- package/src/local/browser-extension-protocol.mjs +50 -11
- package/src/local/browser-operation-service.mjs +147 -117
- package/src/local/browser-pairing-grant.mjs +109 -0
- package/src/local/browser-pairing-http.mjs +36 -0
- package/src/local/browser-pairing-launch.mjs +58 -0
- package/src/local/browser-pairing-store.mjs +85 -48
- package/src/local/browser-request-registry.mjs +40 -14
- package/src/local/browser-request-settlement.mjs +78 -0
- package/src/local/browser-resource-input.mjs +74 -0
- package/src/local/browser-trusted-input-health.mjs +63 -0
- package/src/local/call-authority.mjs +21 -0
- package/src/local/call-capacity.mjs +45 -0
- package/src/local/call-registry-drain.mjs +54 -0
- package/src/local/call-registry.mjs +30 -15
- package/src/local/capability-observer.mjs +5 -0
- package/src/local/capability-ranking.mjs +3 -2
- package/src/local/child-process-settlement.mjs +132 -0
- package/src/local/cli-account-admin.mjs +40 -6
- package/src/local/cli-activate.mjs +162 -0
- package/src/local/cli-local-admin.mjs +20 -45
- package/src/local/cli-options.mjs +12 -13
- package/src/local/cli-ready-output.mjs +52 -0
- package/src/local/cli-service.mjs +91 -11
- package/src/local/cli.mjs +232 -150
- package/src/local/computer-use-application-observation.mjs +224 -0
- package/src/local/computer-use-arguments.mjs +270 -0
- package/src/local/computer-use-deadline.mjs +50 -0
- package/src/local/computer-use-dispatch-settlement.mjs +40 -0
- package/src/local/computer-use-expectation.mjs +171 -0
- package/src/local/computer-use-observation.mjs +769 -0
- package/src/local/computer-use-recovery.mjs +82 -0
- package/src/local/computer-use-result-budget.mjs +145 -0
- package/src/local/computer-use-snapshot-store.mjs +67 -0
- package/src/local/computer-use.mjs +2255 -0
- package/src/local/daemon-http-relay-auth.mjs +26 -0
- package/src/local/daemon-http-relay-connection.mjs +298 -0
- package/src/local/daemon-http-relay-request.mjs +64 -0
- package/src/local/daemon-http-relay-sequence.mjs +49 -0
- package/src/local/daemon-process.mjs +40 -7
- package/src/local/delegated-process-sandbox.mjs +148 -0
- package/src/local/device-identity.mjs +156 -49
- package/src/local/device-root-provider.mjs +81 -0
- package/src/local/directory-metadata.mjs +47 -0
- package/src/local/doctor-reporting.mjs +23 -0
- package/src/local/durable-process-spec.mjs +80 -0
- package/src/local/errors.mjs +25 -15
- package/src/local/exclusive-file.mjs +74 -26
- package/src/local/execution-limits.mjs +9 -0
- package/src/local/execution-routing.mjs +276 -0
- package/src/local/execution-surface.mjs +23 -0
- package/src/local/file-mutation-coordinator.mjs +47 -0
- package/src/local/file-snapshot-preservation.mjs +24 -0
- package/src/local/filesystem-identity.mjs +54 -0
- package/src/local/fixed-process-environment.mjs +21 -0
- package/src/local/full-access-test.mjs +31 -13
- package/src/local/git-commit.mjs +69 -0
- package/src/local/git-config-safety.mjs +55 -0
- package/src/local/git-log-parser.mjs +41 -0
- package/src/local/git-metadata-boundary.mjs +77 -0
- package/src/local/git-metadata-tree-safety.mjs +59 -0
- package/src/local/git-operation-state.mjs +19 -0
- package/src/local/git-service.mjs +165 -30
- package/src/local/hardened-npm-download-timeout.mjs +46 -0
- package/src/local/hardened-npm-download.mjs +109 -0
- package/src/local/hardened-npm-extract.mjs +20 -0
- package/src/local/hardened-npm-verification.mjs +104 -0
- package/src/local/hardened-npm.mjs +199 -0
- package/src/local/job-runner.mjs +244 -89
- package/src/local/lifecycle.mjs +6 -0
- package/src/local/log.mjs +19 -45
- package/src/local/macos-background-input.mjs +398 -0
- package/src/local/macos-idle-sleep-assertion.mjs +65 -0
- package/src/local/macos-trust-broker.mjs +404 -0
- package/src/local/managed-job-cancellation.mjs +42 -0
- package/src/local/managed-job-capacity.mjs +16 -0
- package/src/local/managed-job-directory-generation.mjs +60 -0
- package/src/local/managed-job-directory.mjs +75 -0
- package/src/local/managed-job-durable-process.mjs +49 -0
- package/src/local/managed-job-lock.mjs +46 -14
- package/src/local/managed-job-plan.mjs +38 -14
- package/src/local/managed-job-projection.mjs +23 -15
- package/src/local/managed-job-retention.mjs +128 -0
- package/src/local/managed-job-runner-claim.mjs +70 -0
- package/src/local/managed-job-runner.mjs +35 -10
- package/src/local/managed-job-storage.mjs +22 -6
- package/src/local/managed-job-terminal-maintenance.mjs +40 -0
- package/src/local/managed-job-terminal.mjs +150 -0
- package/src/local/managed-jobs.mjs +424 -287
- package/src/local/npm-cli.mjs +42 -0
- package/src/local/npm-environment.mjs +37 -0
- package/src/local/operation-authorization.mjs +68 -324
- package/src/local/operation-risk.mjs +51 -4
- package/src/local/owner-state-lock.mjs +118 -0
- package/src/local/package-identity.mjs +9 -0
- package/src/local/patch.mjs +20 -18
- package/src/local/path-inspection.mjs +23 -0
- package/src/local/policy.mjs +19 -0
- package/src/local/private-toolchain-integrity.mjs +54 -0
- package/src/local/process-execution.mjs +87 -75
- package/src/local/process-foreground-timeout.mjs +50 -0
- package/src/local/process-identity.mjs +41 -7
- package/src/local/process-nonreplayable-settlement.mjs +50 -0
- package/src/local/process-result-projection.mjs +22 -0
- package/src/local/process-session-events.mjs +47 -0
- package/src/local/process-session-remote-activity.mjs +10 -0
- package/src/local/process-session-termination.mjs +73 -0
- package/src/local/process-sessions.mjs +144 -112
- package/src/local/process-tracker.mjs +140 -13
- package/src/local/process-tree-ownership-types.d.ts +37 -0
- package/src/local/process-tree-ownership.mjs +57 -0
- package/src/local/process-tree-signal.mjs +34 -0
- package/src/local/process-tree-snapshot.mjs +77 -0
- package/src/local/process-tree-supervisor.mjs +69 -0
- package/src/local/process-tree.mjs +11 -53
- package/src/local/project-metadata.mjs +19 -6
- package/src/local/relay-call-recovery.mjs +58 -38
- package/src/local/relay-connection-classification.mjs +131 -0
- package/src/local/relay-connection-support.mjs +91 -0
- package/src/local/relay-connection.mjs +179 -272
- package/src/local/relay-diagnostics.mjs +91 -0
- package/src/local/relay-heartbeat.mjs +119 -0
- package/src/local/relay-liveness.mjs +109 -0
- package/src/local/relay-peer-diagnostics.mjs +29 -0
- package/src/local/release-runtime-lock.mjs +18 -0
- package/src/local/remote-activity-idle-sleep-guard.mjs +77 -0
- package/src/local/remote-configuration.mjs +48 -0
- package/src/local/resilient-relay-connection.mjs +178 -0
- package/src/local/resource-admission-diagnostics.mjs +52 -0
- package/src/local/resource-admission-policy.mjs +115 -0
- package/src/local/resource-admission.mjs +339 -0
- package/src/local/resource-build-root.mjs +83 -0
- package/src/local/resource-cargo-concurrency.mjs +38 -0
- package/src/local/resource-cmake-concurrency.mjs +42 -0
- package/src/local/resource-command-concurrency.mjs +37 -0
- package/src/local/resource-command-profile.mjs +176 -0
- package/src/local/resource-coordinator-accounting.mjs +21 -0
- package/src/local/resource-cpu-window.mjs +20 -0
- package/src/local/resource-disk-headroom.mjs +13 -0
- package/src/local/resource-elastic-memory.mjs +19 -0
- package/src/local/resource-elastic-request.mjs +36 -0
- package/src/local/resource-foreground-wait.mjs +29 -0
- package/src/local/resource-go-concurrency.mjs +43 -0
- package/src/local/resource-gradle-concurrency.mjs +57 -0
- package/src/local/resource-host-cache.mjs +39 -0
- package/src/local/resource-host-darwin.mjs +54 -0
- package/src/local/resource-host-linux.mjs +35 -0
- package/src/local/resource-host-sample-file.mjs +23 -0
- package/src/local/resource-host-snapshot.mjs +99 -0
- package/src/local/resource-lease-accounting.mjs +119 -0
- package/src/local/resource-light-command.mjs +6 -0
- package/src/local/resource-make-concurrency.mjs +42 -0
- package/src/local/resource-maven-concurrency.mjs +38 -0
- package/src/local/resource-ninja-command-concurrency.mjs +20 -0
- package/src/local/resource-ninja-concurrency.mjs +28 -0
- package/src/local/resource-operations.mjs +26 -10
- package/src/local/resource-pressure.mjs +67 -0
- package/src/local/resource-probe-command.mjs +35 -0
- package/src/local/resource-process-admission.mjs +59 -0
- package/src/local/resource-process-ancestry-cache.mjs +43 -0
- package/src/local/resource-process-ancestry.mjs +32 -0
- package/src/local/resource-process-priority.mjs +15 -0
- package/src/local/resource-project-key.mjs +53 -0
- package/src/local/resource-pytest-concurrency.mjs +33 -0
- package/src/local/resource-release-control-classification.mjs +14 -0
- package/src/local/resource-release-control-executable.mjs +70 -0
- package/src/local/resource-release-control-workspace.mjs +41 -0
- package/src/local/resource-request-contract.mjs +30 -0
- package/src/local/resource-script-classification.mjs +44 -0
- package/src/local/resource-shell-analysis.mjs +58 -0
- package/src/local/resource-staging-recovery.mjs +97 -0
- package/src/local/resource-swift-concurrency.mjs +31 -0
- package/src/local/resource-transaction-lock.mjs +189 -0
- package/src/local/resource-wait.mjs +48 -0
- package/src/local/resource-waiters.mjs +139 -0
- package/src/local/resource-xcode-command.mjs +7 -0
- package/src/local/resource-xcode-concurrency.mjs +34 -0
- package/src/local/resource-xcode-non-build.mjs +19 -0
- package/src/local/runtime-activation.mjs +700 -0
- package/src/local/runtime-activity-projection.mjs +48 -0
- package/src/local/runtime-capabilities.mjs +48 -15
- package/src/local/runtime-diagnostic-state.mjs +14 -0
- package/src/local/runtime-diagnostics.mjs +40 -13
- package/src/local/runtime-info-projection.mjs +60 -0
- package/src/local/runtime-info-relay-projection.mjs +21 -0
- package/src/local/runtime-paths.mjs +2 -1
- package/src/local/runtime-process-routing.mjs +33 -0
- package/src/local/runtime-relay-connection-options.mjs +44 -0
- package/src/local/runtime-relay-control.mjs +98 -0
- package/src/local/runtime-relay.mjs +26 -50
- package/src/local/runtime-reporting.mjs +37 -21
- package/src/local/runtime-resource-service.mjs +77 -0
- package/src/local/runtime-tool-handlers.mjs +13 -10
- package/src/local/runtime.mjs +244 -208
- package/src/local/secure-file.mjs +73 -20
- package/src/local/security-audit-dispatch.mjs +35 -0
- package/src/local/security-audit-log.mjs +215 -0
- package/src/local/security-audit-state.mjs +139 -0
- package/src/local/security-audit-storage.mjs +135 -0
- package/src/local/security-audit-warning.mjs +31 -0
- package/src/local/security-audit-worker.mjs +87 -0
- package/src/local/service-convergence.mjs +42 -1
- package/src/local/service-definition.mjs +24 -0
- package/src/local/service-environment.mjs +18 -10
- package/src/local/service-owner.mjs +146 -0
- package/src/local/service-ownership.mjs +17 -0
- package/src/local/service-restart-handoff.mjs +64 -0
- package/src/local/service-restart-scheduler.mjs +49 -0
- package/src/local/service-runtime-convergence.mjs +52 -0
- package/src/local/service-runtime.mjs +105 -0
- package/src/local/service-status.mjs +60 -0
- package/src/local/service.mjs +385 -92
- package/src/local/shell.mjs +39 -19
- package/src/local/ssh-key.mjs +158 -42
- package/src/local/state-inventory.mjs +50 -24
- package/src/local/state-owner-lock-inventory.mjs +23 -0
- package/src/local/state-root-owned-namespaces.mjs +83 -0
- package/src/local/state-root-retirement.mjs +89 -0
- package/src/local/state.mjs +386 -96
- package/src/local/stdio.mjs +96 -66
- package/src/local/support-state-projection.mjs +30 -0
- package/src/local/system-network-route.mjs +76 -0
- package/src/local/systemd-removal.mjs +20 -0
- package/src/local/tool-executor.mjs +85 -20
- package/src/local/tool-result-boundary.mjs +51 -0
- package/src/local/toolchain-operation-lock.mjs +41 -0
- package/src/local/tools.mjs +7 -5
- package/src/local/trusted-executable.mjs +53 -0
- package/src/local/trusted-git-executable.mjs +34 -0
- package/src/local/trusted-github-cli.mjs +24 -0
- package/src/local/windows-service-convergence.mjs +49 -0
- package/src/local/windows-service.mjs +52 -45
- package/src/local/worker-deployment-fingerprint.mjs +102 -0
- package/src/local/worker-deployment.mjs +48 -60
- package/src/local/worker-health.mjs +12 -4
- package/src/local/worker-secret-file.mjs +37 -17
- package/src/local/workspace-file-service.mjs +156 -239
- package/src/local/workspace-file-transaction.mjs +189 -0
- package/src/local/workspace-search.mjs +55 -0
- package/src/local/wrangler-toolchain/package-lock.json +1505 -0
- package/src/local/wrangler-toolchain/package.json +23 -0
- package/src/local/wrangler-toolchain-verification.mjs +135 -0
- package/src/local/wrangler-toolchain.mjs +188 -0
- package/src/shared/access-contract.json +7 -1
- package/src/shared/activation-recovery.mjs +49 -0
- package/src/shared/admin-auth.d.mts +2 -1
- package/src/shared/admin-auth.mjs +3 -3
- package/src/shared/authority-revocation.d.mts +9 -0
- package/src/shared/authority-revocation.mjs +28 -0
- package/src/shared/daemon-auth.d.mts +11 -0
- package/src/shared/daemon-auth.mjs +17 -0
- package/src/shared/device-session-auth.d.mts +20 -0
- package/src/shared/device-session-auth.mjs +51 -0
- package/src/shared/foreground-timeout.d.mts +15 -0
- package/src/shared/foreground-timeout.mjs +70 -0
- package/src/shared/log-redaction.d.mts +9 -0
- package/src/shared/log-redaction.mjs +51 -0
- package/src/shared/mcp-protocol.d.mts +27 -0
- package/src/shared/mcp-protocol.mjs +275 -0
- package/src/shared/project-overview-projection.d.mts +4 -0
- package/src/shared/project-overview-projection.mjs +96 -0
- package/src/shared/relay-contract.json +28 -0
- package/src/shared/result-projection.d.mts +2 -1
- package/src/shared/result-projection.mjs +13 -2
- package/src/shared/server-metadata.json +15 -9
- package/src/shared/tool-argument-validation.d.mts +17 -0
- package/src/shared/tool-argument-validation.mjs +325 -0
- package/src/shared/tool-call-capacity.d.mts +41 -0
- package/src/shared/tool-call-capacity.mjs +59 -0
- package/src/shared/tool-catalog.json +626 -57
- package/src/worker/access.ts +12 -0
- package/src/worker/account-admin.ts +55 -33
- package/src/worker/authority-revocations.ts +174 -0
- package/src/worker/authority.ts +52 -6
- package/src/worker/daemon-auth.ts +49 -68
- package/src/worker/daemon-channel.ts +36 -0
- package/src/worker/daemon-http-auth.ts +63 -0
- package/src/worker/daemon-http-channel.ts +120 -0
- package/src/worker/daemon-http-controller.ts +163 -0
- package/src/worker/daemon-http-protocol.ts +62 -0
- package/src/worker/daemon-http-registry.ts +82 -0
- package/src/worker/daemon-last-observation.ts +30 -0
- package/src/worker/daemon-liveness.ts +8 -6
- package/src/worker/daemon-ready-dispatch.ts +17 -0
- package/src/worker/daemon-ready-messages.ts +73 -0
- package/src/worker/daemon-ready-waiters.ts +79 -0
- package/src/worker/daemon-recovery-budget.ts +13 -0
- package/src/worker/daemon-registry.ts +58 -0
- package/src/worker/daemon-relay-diagnostics.ts +127 -0
- package/src/worker/daemon-socket-attachment.ts +55 -0
- package/src/worker/daemon-sockets.ts +72 -62
- package/src/worker/daemon-status.ts +38 -0
- package/src/worker/device-session-verifier.ts +129 -0
- package/src/worker/dpop.ts +157 -0
- package/src/worker/durable-process-timeout.ts +29 -0
- package/src/worker/errors.ts +57 -0
- package/src/worker/http.ts +112 -26
- package/src/worker/index.ts +446 -440
- package/src/worker/mcp-access.ts +57 -0
- package/src/worker/mcp-controller.ts +188 -0
- package/src/worker/mcp-http-accept.ts +11 -0
- package/src/worker/mcp-http-contract.ts +322 -0
- package/src/worker/mcp-initialization-compat.ts +141 -0
- package/src/worker/mcp-jsonrpc.ts +11 -29
- package/src/worker/mcp-removed-protocol.ts +17 -0
- package/src/worker/mcp-response-proxy.ts +135 -0
- package/src/worker/mcp-response-stream.ts +65 -0
- package/src/worker/mcp-stale-schema-compat.ts +57 -0
- package/src/worker/mcp-stream-proxy-contract.ts +48 -0
- package/src/worker/mcp-tool-call-input.ts +23 -0
- package/src/worker/nonce-store.ts +33 -35
- package/src/worker/oauth-authorization-page.ts +21 -1
- package/src/worker/oauth-client-admin.ts +52 -0
- package/src/worker/oauth-client-contract.ts +38 -0
- package/src/worker/oauth-controller.ts +107 -47
- package/src/worker/oauth-field-contract.ts +31 -0
- package/src/worker/oauth-record-contract.ts +7 -0
- package/src/worker/oauth-refresh-authority.ts +27 -0
- package/src/worker/oauth-refresh-exchange.ts +162 -0
- package/src/worker/oauth-refresh-families.ts +130 -27
- package/src/worker/oauth-refresh-persistence.ts +116 -0
- package/src/worker/oauth-state.ts +33 -18
- package/src/worker/oauth-store-validation.ts +131 -0
- package/src/worker/oauth-token-derivation.ts +33 -0
- package/src/worker/oauth-token-issuance.ts +119 -0
- package/src/worker/oauth-tokens.ts +56 -190
- package/src/worker/observability.ts +38 -5
- package/src/worker/pending-admission.ts +15 -0
- package/src/worker/pending-call-capacity.ts +108 -0
- package/src/worker/pending-call-contract.ts +42 -5
- package/src/worker/pending-call-deadlines.ts +75 -0
- package/src/worker/pending-calls.ts +131 -125
- package/src/worker/runtime-alarm-storage.ts +37 -0
- package/src/worker/runtime-alarm.ts +136 -0
- package/src/worker/server-info-activity.ts +36 -0
- package/src/worker/server-info-tool-delivery.ts +15 -0
- package/src/worker/server-info.ts +168 -0
- package/src/worker/tool-catalog.ts +47 -1
- package/src/worker/tool-timeout.ts +75 -14
- package/src/worker/websocket-protocol.ts +26 -2
- package/src/worker/worker-edge-guard.ts +90 -0
- package/src/worker/worker-edge-log.ts +65 -0
- package/src/worker/worker-entry.ts +52 -0
- package/src/worker/worker-mcp-config.ts +23 -0
- package/src/worker/worker-metadata.ts +48 -0
- package/src/worker/worker-rate-limit-key.ts +30 -0
- package/src/worker/worker-runtime-config.ts +20 -0
- package/src/worker/worker-static-routes.ts +54 -0
- package/src/worker/worker-task-lifetime.ts +18 -0
- package/tsconfig.local.json +17 -1
- package/wrangler.jsonc +13 -0
- package/src/local/cli-approval.mjs +0 -117
- package/src/local/operation-state-lock.mjs +0 -92
- package/src/worker/mcp-session.ts +0 -72
|
@@ -0,0 +1,700 @@
|
|
|
1
|
+
import { canonicalActivationRecoveryDetail, isActivationRecoveryReason } from "../shared/activation-recovery.mjs";
|
|
2
|
+
|
|
3
|
+
export async function activatePersistentRuntime(options = {}) {
|
|
4
|
+
const required = [
|
|
5
|
+
"acquireStartupLock",
|
|
6
|
+
"acquireServiceLock",
|
|
7
|
+
"inspectActivationOwnership",
|
|
8
|
+
"stopAutostart",
|
|
9
|
+
"acquireDaemonLock",
|
|
10
|
+
"prepareRemoteState",
|
|
11
|
+
"createRuntime",
|
|
12
|
+
"installAutostart",
|
|
13
|
+
"startAutostart",
|
|
14
|
+
"inspectDaemon",
|
|
15
|
+
"checkWorker",
|
|
16
|
+
];
|
|
17
|
+
for (const name of required) {
|
|
18
|
+
if (typeof options[name] !== "function") throw new TypeError(`runtime activation requires ${name}`);
|
|
19
|
+
}
|
|
20
|
+
const expectedVersion = requiredExpectedVersion(options.expectedVersion);
|
|
21
|
+
const maximumAttempts = boundedAttempts(options.maximumAttempts ?? 240);
|
|
22
|
+
const candidateStartAttempts = boundedCandidateStartAttempts(options.candidateStartAttempts ?? 10);
|
|
23
|
+
const restoreStartAttempts = boundedRestoreStartAttempts(options.restoreStartAttempts ?? 30);
|
|
24
|
+
const candidateRetryWait = optionalFunction(options.candidateRetryWait, "candidateRetryWait", defaultCandidateRetryWait);
|
|
25
|
+
const convergenceWait = optionalFunction(options.wait, "wait", defaultWait);
|
|
26
|
+
const restorePreviousAutostart = optionalFunction(options.restorePreviousAutostart, "restorePreviousAutostart", options.startAutostart);
|
|
27
|
+
const startRecoveryAutostart = optionalFunction(options.startRecoveryAutostart, "startRecoveryAutostart", options.startAutostart);
|
|
28
|
+
const inspectCandidateAutostart = optionalFunction(options.inspectCandidateAutostart, "inspectCandidateAutostart", options.inspectDaemon);
|
|
29
|
+
if (options.repairRemoteState !== undefined && typeof options.repairRemoteState !== "function") {
|
|
30
|
+
throw new TypeError("runtime activation repairRemoteState must be a function");
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
let startupLock = null;
|
|
34
|
+
let startupReleased = false;
|
|
35
|
+
let serviceLock = null;
|
|
36
|
+
let daemonLock = null;
|
|
37
|
+
let candidateRuntime = null;
|
|
38
|
+
let candidateRelayVerified = false;
|
|
39
|
+
let candidateRecoveryRedeployed = false;
|
|
40
|
+
let remotePrepared = false;
|
|
41
|
+
let autostartInstalled = false;
|
|
42
|
+
let serviceOwnerTransaction = null;
|
|
43
|
+
let providerStopped = false;
|
|
44
|
+
let previousServiceRuntime = null;
|
|
45
|
+
let serviceStarted = false;
|
|
46
|
+
try {
|
|
47
|
+
const acquiredServiceLock = await options.acquireServiceLock();
|
|
48
|
+
if (!acquiredServiceLock?.acquired) {
|
|
49
|
+
const owner = acquiredServiceLock?.owner || {};
|
|
50
|
+
throw new Error(`another machine-service operation is active (pid ${owner.pid || "unknown"})`);
|
|
51
|
+
}
|
|
52
|
+
requireReleasableLock(acquiredServiceLock, "machine-service");
|
|
53
|
+
serviceLock = acquiredServiceLock;
|
|
54
|
+
const acquiredStartupLock = await options.acquireStartupLock();
|
|
55
|
+
requireReleasableLock(acquiredStartupLock, "startup");
|
|
56
|
+
startupLock = acquiredStartupLock;
|
|
57
|
+
const ownership = validateActivationOwnership(await options.inspectActivationOwnership());
|
|
58
|
+
providerStopped = ownership.previousServiceRuntimeActive;
|
|
59
|
+
previousServiceRuntime = ownership.previousServiceRuntime;
|
|
60
|
+
const providerStop = await options.stopAutostart();
|
|
61
|
+
providerStopped = validateProviderStop(providerStop) || providerStopped;
|
|
62
|
+
|
|
63
|
+
daemonLock = await options.acquireDaemonLock();
|
|
64
|
+
if (!daemonLock?.acquired) {
|
|
65
|
+
const owner = daemonLock?.owner || {};
|
|
66
|
+
if (owner.mode === "foreground") {
|
|
67
|
+
throw new Error(`a foreground daemon is active (pid ${owner.pid || "unknown"}); stop it explicitly before activation`);
|
|
68
|
+
}
|
|
69
|
+
throw new Error(`the existing daemon could not be taken over (pid ${owner.pid || "unknown"})`);
|
|
70
|
+
}
|
|
71
|
+
requireReleasableLock(daemonLock, "daemon");
|
|
72
|
+
|
|
73
|
+
let readiness;
|
|
74
|
+
try {
|
|
75
|
+
readiness = await options.prepareRemoteState({
|
|
76
|
+
onRemotePrepared() { remotePrepared = true; },
|
|
77
|
+
});
|
|
78
|
+
remotePrepared = true;
|
|
79
|
+
} catch (error) {
|
|
80
|
+
if (error?.deploymentSucceeded === true) remotePrepared = true;
|
|
81
|
+
throw error;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
const candidate = await startCandidateWithRecovery({
|
|
85
|
+
attempts: candidateStartAttempts,
|
|
86
|
+
daemonLock,
|
|
87
|
+
readiness,
|
|
88
|
+
createRuntime: options.createRuntime,
|
|
89
|
+
repairRemoteState: options.repairRemoteState,
|
|
90
|
+
wait: candidateRetryWait,
|
|
91
|
+
onRuntimeCreated(runtime) { candidateRuntime = runtime; },
|
|
92
|
+
onRuntimeStopped() { candidateRuntime = null; },
|
|
93
|
+
onRemoteRepaired() { remotePrepared = true; },
|
|
94
|
+
});
|
|
95
|
+
candidateRuntime = candidate.runtime;
|
|
96
|
+
candidateRelayVerified = true;
|
|
97
|
+
candidateRecoveryRedeployed = candidate.repaired;
|
|
98
|
+
|
|
99
|
+
const installed = await options.installAutostart({ deferOwnerCommit: true });
|
|
100
|
+
serviceOwnerTransaction = deferredServiceOwnerTransaction(installed);
|
|
101
|
+
const terminalError = candidateRuntime.terminalError?.();
|
|
102
|
+
if (terminalError) throw terminalError;
|
|
103
|
+
if (installed?.ok !== true) {
|
|
104
|
+
throw activationOperationalError(
|
|
105
|
+
`autostart installation failed (${installed?.provider || "unknown"})`,
|
|
106
|
+
"autostart_install_failed",
|
|
107
|
+
);
|
|
108
|
+
}
|
|
109
|
+
autostartInstalled = true;
|
|
110
|
+
|
|
111
|
+
candidateRuntime.stop();
|
|
112
|
+
candidateRuntime = null;
|
|
113
|
+
daemonLock.release();
|
|
114
|
+
daemonLock = null;
|
|
115
|
+
startupLock.release();
|
|
116
|
+
startupReleased = true;
|
|
117
|
+
|
|
118
|
+
const serviceStart = await options.startAutostart({ owner: serviceOwnerTransaction?.owner || null });
|
|
119
|
+
requireActiveServiceStart(serviceStart, "autostart start", "autostart_start_failed");
|
|
120
|
+
serviceStarted = true;
|
|
121
|
+
|
|
122
|
+
const convergence = await waitForActivatedRuntime({
|
|
123
|
+
expectedVersion,
|
|
124
|
+
inspectDaemon: options.inspectDaemon,
|
|
125
|
+
checkWorker: options.checkWorker,
|
|
126
|
+
maximumAttempts,
|
|
127
|
+
wait: convergenceWait,
|
|
128
|
+
});
|
|
129
|
+
if (!convergence.ok) {
|
|
130
|
+
throw new Error(`persistent runtime activation did not converge (${convergence.reason})`);
|
|
131
|
+
}
|
|
132
|
+
if (serviceOwnerTransaction) {
|
|
133
|
+
await commitVerifiedServiceOwner({ transaction: serviceOwnerTransaction, stopAutostart: options.stopAutostart });
|
|
134
|
+
serviceOwnerTransaction = null;
|
|
135
|
+
}
|
|
136
|
+
serviceLock.release();
|
|
137
|
+
serviceLock = null;
|
|
138
|
+
return {
|
|
139
|
+
ok: true,
|
|
140
|
+
serviceStart,
|
|
141
|
+
convergence,
|
|
142
|
+
candidateRelayVerified,
|
|
143
|
+
candidateRecoveryRedeployed,
|
|
144
|
+
};
|
|
145
|
+
} catch (error) {
|
|
146
|
+
const settlement = await failedActivationSettlement({
|
|
147
|
+
error,
|
|
148
|
+
candidateRuntime,
|
|
149
|
+
daemonLock,
|
|
150
|
+
startupLock,
|
|
151
|
+
startupReleased,
|
|
152
|
+
serviceLock,
|
|
153
|
+
providerStopped,
|
|
154
|
+
serviceStarted,
|
|
155
|
+
remotePrepared,
|
|
156
|
+
autostartInstalled,
|
|
157
|
+
serviceOwnerTransaction,
|
|
158
|
+
installAutostart: options.installAutostart,
|
|
159
|
+
startRecoveryAutostart,
|
|
160
|
+
restorePreviousAutostart,
|
|
161
|
+
stopRecoveryAutostart: options.stopAutostart,
|
|
162
|
+
inspectCandidateAutostart,
|
|
163
|
+
inspectPreviousAutostart: options.inspectPreviousAutostart,
|
|
164
|
+
checkWorker: options.checkWorker,
|
|
165
|
+
expectedVersion,
|
|
166
|
+
previousServiceRuntime,
|
|
167
|
+
restoreWait: convergenceWait,
|
|
168
|
+
restoreMaximumAttempts: options.maximumAttempts,
|
|
169
|
+
restoreStartAttempts,
|
|
170
|
+
candidateRelayVerified,
|
|
171
|
+
candidateRecoveryRedeployed,
|
|
172
|
+
});
|
|
173
|
+
if (settlement?.ok === true) return settlement;
|
|
174
|
+
throw settlement;
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
async function failedActivationSettlement({
|
|
179
|
+
error,
|
|
180
|
+
candidateRuntime,
|
|
181
|
+
daemonLock,
|
|
182
|
+
startupLock,
|
|
183
|
+
startupReleased,
|
|
184
|
+
serviceLock,
|
|
185
|
+
providerStopped,
|
|
186
|
+
serviceStarted,
|
|
187
|
+
remotePrepared,
|
|
188
|
+
autostartInstalled,
|
|
189
|
+
serviceOwnerTransaction,
|
|
190
|
+
installAutostart,
|
|
191
|
+
startRecoveryAutostart,
|
|
192
|
+
restorePreviousAutostart,
|
|
193
|
+
stopRecoveryAutostart,
|
|
194
|
+
inspectCandidateAutostart,
|
|
195
|
+
inspectPreviousAutostart,
|
|
196
|
+
checkWorker,
|
|
197
|
+
expectedVersion,
|
|
198
|
+
previousServiceRuntime,
|
|
199
|
+
restoreWait,
|
|
200
|
+
restoreMaximumAttempts,
|
|
201
|
+
restoreStartAttempts,
|
|
202
|
+
candidateRelayVerified,
|
|
203
|
+
candidateRecoveryRedeployed,
|
|
204
|
+
}) {
|
|
205
|
+
const cleanupErrors = [];
|
|
206
|
+
try { candidateRuntime?.stop?.(); } catch (failure) { cleanupErrors.push(failure); }
|
|
207
|
+
try { daemonLock?.release?.(); } catch (failure) { cleanupErrors.push(failure); }
|
|
208
|
+
if (!startupReleased && startupLock) {
|
|
209
|
+
try { startupLock.release(); }
|
|
210
|
+
catch (failure) { cleanupErrors.push(failure); }
|
|
211
|
+
}
|
|
212
|
+
let recovery = null;
|
|
213
|
+
const cleanupIncomplete = error?.cleanupIncomplete === true || cleanupErrors.length > 0;
|
|
214
|
+
const recoveryBlocked = error?.recoveryBlocked === true;
|
|
215
|
+
if (!cleanupIncomplete && !recoveryBlocked) {
|
|
216
|
+
try {
|
|
217
|
+
recovery = await restoreCompatibleProvider({
|
|
218
|
+
installAutostart,
|
|
219
|
+
startRecoveryAutostart,
|
|
220
|
+
restorePreviousAutostart,
|
|
221
|
+
stopRecoveryAutostart,
|
|
222
|
+
inspectCandidateAutostart,
|
|
223
|
+
inspectPreviousAutostart,
|
|
224
|
+
checkWorker,
|
|
225
|
+
expectedVersion,
|
|
226
|
+
previousServiceRuntime,
|
|
227
|
+
restoreWait,
|
|
228
|
+
restoreMaximumAttempts,
|
|
229
|
+
restoreStartAttempts,
|
|
230
|
+
providerStopped,
|
|
231
|
+
serviceStarted,
|
|
232
|
+
candidateServiceRequired: remotePrepared,
|
|
233
|
+
candidateDefinitionRequired: remotePrepared && !autostartInstalled,
|
|
234
|
+
serviceOwnerTransaction,
|
|
235
|
+
});
|
|
236
|
+
} catch (failure) { cleanupErrors.push(failure); }
|
|
237
|
+
}
|
|
238
|
+
if (serviceLock) {
|
|
239
|
+
try { serviceLock.release(); } catch (failure) { cleanupErrors.push(failure); }
|
|
240
|
+
}
|
|
241
|
+
if (cleanupErrors.length) return activationCleanupFailure(error, cleanupErrors);
|
|
242
|
+
if (recovery?.candidateServiceStarted && candidateRelayVerified && recoverablePostReadySettlement(error)) {
|
|
243
|
+
return {
|
|
244
|
+
ok: true,
|
|
245
|
+
serviceStart: recovery.serviceStart,
|
|
246
|
+
convergence: recovery.convergence,
|
|
247
|
+
candidateRelayVerified: true,
|
|
248
|
+
candidateRecoveryRedeployed,
|
|
249
|
+
activationRecovered: true,
|
|
250
|
+
recoveryReason: activationRecoveryReason(error),
|
|
251
|
+
recoveryDetail: activationRecoveryDetail(error),
|
|
252
|
+
};
|
|
253
|
+
}
|
|
254
|
+
if (recovery?.candidateServiceStarted) return activationFailureWithRecovery(error);
|
|
255
|
+
return error;
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
async function startCandidateWithRecovery({
|
|
259
|
+
attempts = 3,
|
|
260
|
+
daemonLock,
|
|
261
|
+
readiness,
|
|
262
|
+
createRuntime,
|
|
263
|
+
repairRemoteState,
|
|
264
|
+
wait = defaultCandidateRetryWait,
|
|
265
|
+
onRuntimeCreated,
|
|
266
|
+
onRuntimeStopped,
|
|
267
|
+
onRemoteRepaired,
|
|
268
|
+
} = {}) {
|
|
269
|
+
const maximumAttempts = boundedCandidateStartAttempts(attempts);
|
|
270
|
+
let currentReadiness = readiness;
|
|
271
|
+
let repaired = false;
|
|
272
|
+
let lastError = null;
|
|
273
|
+
for (let attempt = 1; attempt <= maximumAttempts; attempt += 1) {
|
|
274
|
+
const runtime = createRuntime({ daemonLock, readiness: currentReadiness });
|
|
275
|
+
if (!runtime || typeof runtime.start !== "function" || typeof runtime.stop !== "function") {
|
|
276
|
+
throw new TypeError("runtime activation candidate must expose start and stop");
|
|
277
|
+
}
|
|
278
|
+
onRuntimeCreated(runtime);
|
|
279
|
+
try {
|
|
280
|
+
await runtime.start();
|
|
281
|
+
return { runtime, repaired };
|
|
282
|
+
} catch (error) {
|
|
283
|
+
lastError = error;
|
|
284
|
+
let stopFailure = null;
|
|
285
|
+
try { await runtime.stop(); } catch (failure) { stopFailure = failure; }
|
|
286
|
+
finally { onRuntimeStopped(); }
|
|
287
|
+
if (stopFailure) {
|
|
288
|
+
const cleanupError = new AggregateError(
|
|
289
|
+
[error, stopFailure],
|
|
290
|
+
"candidate relay start failed and runtime cleanup was incomplete",
|
|
291
|
+
);
|
|
292
|
+
cleanupError.cleanupIncomplete = true;
|
|
293
|
+
throw cleanupError;
|
|
294
|
+
}
|
|
295
|
+
if (!recoverableCandidateStartError(error) || attempt >= maximumAttempts) throw error;
|
|
296
|
+
if (!repaired && typeof repairRemoteState === "function") {
|
|
297
|
+
let repairPrepared = false;
|
|
298
|
+
const markRemoteRepaired = () => {
|
|
299
|
+
if (repairPrepared) return;
|
|
300
|
+
repairPrepared = true;
|
|
301
|
+
onRemoteRepaired();
|
|
302
|
+
};
|
|
303
|
+
currentReadiness = await repairRemoteState({
|
|
304
|
+
attempt,
|
|
305
|
+
error,
|
|
306
|
+
readiness: currentReadiness,
|
|
307
|
+
onRemotePrepared: markRemoteRepaired,
|
|
308
|
+
});
|
|
309
|
+
repaired = true;
|
|
310
|
+
markRemoteRepaired();
|
|
311
|
+
}
|
|
312
|
+
await wait(attempt);
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
throw lastError || new Error("candidate relay did not start");
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
function recoverableCandidateStartError(error) {
|
|
319
|
+
return error?.code === "relay_authentication_failed";
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
async function restoreCompatibleProvider({
|
|
323
|
+
installAutostart,
|
|
324
|
+
startRecoveryAutostart,
|
|
325
|
+
restorePreviousAutostart,
|
|
326
|
+
stopRecoveryAutostart,
|
|
327
|
+
inspectCandidateAutostart,
|
|
328
|
+
inspectPreviousAutostart,
|
|
329
|
+
checkWorker,
|
|
330
|
+
expectedVersion,
|
|
331
|
+
previousServiceRuntime,
|
|
332
|
+
restoreWait,
|
|
333
|
+
restoreMaximumAttempts,
|
|
334
|
+
restoreStartAttempts,
|
|
335
|
+
providerStopped,
|
|
336
|
+
serviceStarted,
|
|
337
|
+
candidateServiceRequired,
|
|
338
|
+
candidateDefinitionRequired,
|
|
339
|
+
serviceOwnerTransaction,
|
|
340
|
+
}) {
|
|
341
|
+
if ((serviceStarted && !serviceOwnerTransaction) || (!candidateServiceRequired && !providerStopped)) {
|
|
342
|
+
return { candidateServiceStarted: false };
|
|
343
|
+
}
|
|
344
|
+
if (candidateDefinitionRequired) {
|
|
345
|
+
const installed = await installAutostart({ deferOwnerCommit: true });
|
|
346
|
+
serviceOwnerTransaction = deferredServiceOwnerTransaction(installed) || serviceOwnerTransaction;
|
|
347
|
+
if (installed?.ok !== true) {
|
|
348
|
+
throw new Error(`compatible candidate autostart could not be installed (${installed?.provider || "unknown"})`);
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
if (candidateServiceRequired) {
|
|
352
|
+
try {
|
|
353
|
+
const restored = await startRecoveryAutostart({ owner: serviceOwnerTransaction?.owner || null });
|
|
354
|
+
requireActiveServiceStart(restored, "compatible candidate autostart service recovery");
|
|
355
|
+
const convergence = await waitForActivatedRuntime({
|
|
356
|
+
inspectDaemon: inspectCandidateAutostart,
|
|
357
|
+
checkWorker,
|
|
358
|
+
expectedVersion,
|
|
359
|
+
maximumAttempts: restoreMaximumAttempts,
|
|
360
|
+
wait: restoreWait,
|
|
361
|
+
});
|
|
362
|
+
if (!convergence.ok) {
|
|
363
|
+
throw new Error(`compatible candidate autostart recovery did not converge (${convergence.reason})`);
|
|
364
|
+
}
|
|
365
|
+
if (serviceOwnerTransaction) {
|
|
366
|
+
await commitVerifiedServiceOwner({ transaction: serviceOwnerTransaction, stopAutostart: stopRecoveryAutostart });
|
|
367
|
+
}
|
|
368
|
+
return { candidateServiceStarted: true, convergence, serviceStart: restored };
|
|
369
|
+
} catch (error) {
|
|
370
|
+
if (!serviceOwnerTransaction || error?.recoveryBlocked === true) throw error;
|
|
371
|
+
throw await stopUncommittedCandidate(error, stopRecoveryAutostart);
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
if (!previousServiceRuntime || typeof inspectPreviousAutostart !== "function") {
|
|
375
|
+
throw new Error("previous autostart service recovery lacks verified runtime identity evidence");
|
|
376
|
+
}
|
|
377
|
+
const recovery = await restorePreviousServiceUntilReady({
|
|
378
|
+
restorePreviousAutostart,
|
|
379
|
+
inspectPreviousAutostart: () => inspectPreviousAutostart(previousServiceRuntime),
|
|
380
|
+
expectedVersion: previousServiceRuntime.version,
|
|
381
|
+
attempts: restoreStartAttempts,
|
|
382
|
+
wait: restoreWait,
|
|
383
|
+
});
|
|
384
|
+
return { candidateServiceStarted: false, convergence: recovery.convergence, serviceStart: recovery.serviceStart };
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
async function stopUncommittedCandidate(primaryError, stopAutostart) {
|
|
388
|
+
try {
|
|
389
|
+
const stopped = await stopAutostart();
|
|
390
|
+
if (stopped?.ok === true && stopped.active === false) return primaryError;
|
|
391
|
+
const stopError = new Error(`uncommitted candidate service stop could not be verified (${stopped?.provider || "unknown"})`);
|
|
392
|
+
const aggregate = new AggregateError(
|
|
393
|
+
[primaryError, stopError],
|
|
394
|
+
`${activationErrorMessage(primaryError)}; uncommitted candidate service stop could not be verified`,
|
|
395
|
+
);
|
|
396
|
+
aggregate.cleanupIncomplete = true;
|
|
397
|
+
return aggregate;
|
|
398
|
+
} catch (stopError) {
|
|
399
|
+
const aggregate = new AggregateError(
|
|
400
|
+
[primaryError, stopError],
|
|
401
|
+
`${activationErrorMessage(primaryError)}; uncommitted candidate service stop failed`,
|
|
402
|
+
);
|
|
403
|
+
aggregate.cleanupIncomplete = true;
|
|
404
|
+
return aggregate;
|
|
405
|
+
}
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
async function restorePreviousServiceUntilReady({
|
|
409
|
+
restorePreviousAutostart, inspectPreviousAutostart, expectedVersion, attempts = 30, wait = defaultWait,
|
|
410
|
+
} = {}) {
|
|
411
|
+
const maximum = boundedRestoreStartAttempts(attempts);
|
|
412
|
+
let daemon = null;
|
|
413
|
+
let serviceStart = null;
|
|
414
|
+
let lastStartError = null;
|
|
415
|
+
for (let attempt = 1; attempt <= maximum; attempt += 1) {
|
|
416
|
+
try {
|
|
417
|
+
serviceStart = await restorePreviousAutostart();
|
|
418
|
+
lastStartError = null;
|
|
419
|
+
} catch (error) {
|
|
420
|
+
lastStartError = error;
|
|
421
|
+
}
|
|
422
|
+
daemon = await inspectPreviousAutostart();
|
|
423
|
+
if (restoredServiceReady(daemon, expectedVersion)) {
|
|
424
|
+
return { serviceStart, convergence: { ok: true, attempts: attempt, daemon } };
|
|
425
|
+
}
|
|
426
|
+
if (attempt < maximum) await wait(attempt);
|
|
427
|
+
}
|
|
428
|
+
const failure = new Error(`previous autostart service recovery did not converge (${restoredServiceFailureReason(daemon, expectedVersion)})`);
|
|
429
|
+
if (lastStartError) failure.cause = lastStartError;
|
|
430
|
+
throw failure;
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
function deferredServiceOwnerTransaction(result) {
|
|
434
|
+
const transaction = result?.serviceOwnerTransaction;
|
|
435
|
+
if (!transaction) return null;
|
|
436
|
+
if (!transaction.owner || transaction.owner.status !== "pending"
|
|
437
|
+
|| typeof transaction.commit !== "function" || typeof transaction.rollback !== "function") {
|
|
438
|
+
throw new Error("candidate service owner transaction is invalid");
|
|
439
|
+
}
|
|
440
|
+
return transaction;
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
async function commitVerifiedServiceOwner({ transaction, stopAutostart }) {
|
|
444
|
+
try {
|
|
445
|
+
const committed = transaction.commit();
|
|
446
|
+
if (!committed || committed.status !== "committed") {
|
|
447
|
+
throw new Error("machine service owner commit did not return committed state");
|
|
448
|
+
}
|
|
449
|
+
return committed;
|
|
450
|
+
} catch (commitError) {
|
|
451
|
+
let stopError = null;
|
|
452
|
+
try {
|
|
453
|
+
const stopped = await stopAutostart();
|
|
454
|
+
if (stopped?.ok !== true || stopped.active !== false) {
|
|
455
|
+
stopError = new Error(`candidate service could not be stopped after owner commit failure (${stopped?.provider || "unknown"})`);
|
|
456
|
+
}
|
|
457
|
+
} catch (error) {
|
|
458
|
+
stopError = error;
|
|
459
|
+
}
|
|
460
|
+
const failure = new Error(
|
|
461
|
+
"candidate service reached verified readiness but its machine service owner could not be committed; the provider was stopped and the pending owner was retained for explicit recovery",
|
|
462
|
+
{ cause: commitError },
|
|
463
|
+
);
|
|
464
|
+
failure.code = "service_owner_commit_failed";
|
|
465
|
+
failure.recoveryBlocked = true;
|
|
466
|
+
if (!stopError) throw failure;
|
|
467
|
+
const aggregate = new AggregateError(
|
|
468
|
+
[failure, stopError],
|
|
469
|
+
`${failure.message}; provider stop could not be verified`,
|
|
470
|
+
);
|
|
471
|
+
aggregate.code = failure.code;
|
|
472
|
+
aggregate.recoveryBlocked = true;
|
|
473
|
+
aggregate.cleanupIncomplete = true;
|
|
474
|
+
throw aggregate;
|
|
475
|
+
}
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
function restoredServiceReady(daemon, expectedVersion) {
|
|
479
|
+
return daemon?.alive === true && daemon?.verified_service_daemon === true
|
|
480
|
+
&& daemon?.mode === "service" && daemon?.version === expectedVersion;
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
function restoredServiceFailureReason(daemon, expectedVersion) {
|
|
484
|
+
if (!daemon?.alive) return "daemon_not_running";
|
|
485
|
+
if (daemon?.verified_service_daemon !== true) return `daemon_identity_${daemon?.identity_reason || "unverified"}`;
|
|
486
|
+
if (daemon?.mode !== "service") return `daemon_mode_${daemon?.mode || "unknown"}`;
|
|
487
|
+
return daemon?.version === expectedVersion ? "service_not_stable" : `daemon_version_${daemon?.version || "unknown"}`;
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
function validateActivationOwnership(value) {
|
|
491
|
+
const daemon = value?.daemon || {};
|
|
492
|
+
const provider = value?.provider || {};
|
|
493
|
+
if (typeof provider.active !== "boolean") {
|
|
494
|
+
throw new Error(`the machine autostart state could not be verified before activation (${provider.provider || "unknown"})`);
|
|
495
|
+
}
|
|
496
|
+
if (daemon.alive === true) {
|
|
497
|
+
if (daemon.mode === "foreground" || daemon.identity_reason === "foreground_daemon") {
|
|
498
|
+
throw new Error(`a foreground daemon is active (pid ${daemon.pid || "unknown"}); stop it explicitly before activation`);
|
|
499
|
+
}
|
|
500
|
+
if (daemon.verified_service_daemon !== true || daemon.mode !== "service") {
|
|
501
|
+
throw new Error(`the existing workspace daemon identity could not be verified before activation (${daemon.identity_reason || "unknown"})`);
|
|
502
|
+
}
|
|
503
|
+
}
|
|
504
|
+
const previousServiceRuntimeActive = daemon.alive === true
|
|
505
|
+
&& daemon.verified_service_daemon === true
|
|
506
|
+
&& daemon.mode === "service";
|
|
507
|
+
if (provider.active === true && !previousServiceRuntimeActive) {
|
|
508
|
+
throw new Error("refusing to stop the active machine service because the selected workspace does not own its verified daemon");
|
|
509
|
+
}
|
|
510
|
+
let previousServiceRuntime = null;
|
|
511
|
+
if (previousServiceRuntimeActive) {
|
|
512
|
+
const evidence = value?.previousRuntime || {};
|
|
513
|
+
if (typeof evidence.version !== "string" || !evidence.version
|
|
514
|
+
|| typeof evidence.entryScript !== "string" || !evidence.entryScript) {
|
|
515
|
+
throw new Error("the previous service daemon identity evidence is incomplete before activation");
|
|
516
|
+
}
|
|
517
|
+
previousServiceRuntime = { version: evidence.version, entryScript: evidence.entryScript };
|
|
518
|
+
}
|
|
519
|
+
return { previousServiceRuntimeActive, previousServiceRuntime };
|
|
520
|
+
}
|
|
521
|
+
|
|
522
|
+
function validateProviderStop(result) {
|
|
523
|
+
if (result?.ok !== true) {
|
|
524
|
+
throw activationOperationalError(
|
|
525
|
+
`the existing autostart service could not be stopped before activation (${result?.provider || "unknown"})`,
|
|
526
|
+
"autostart_stop_failed",
|
|
527
|
+
);
|
|
528
|
+
}
|
|
529
|
+
if (typeof result.active_before !== "boolean" || result.active !== false || typeof result.restore_required !== "boolean") {
|
|
530
|
+
throw new Error(`the existing autostart stop state could not be verified before activation (${result?.provider || "unknown"})`);
|
|
531
|
+
}
|
|
532
|
+
return result.restore_required;
|
|
533
|
+
}
|
|
534
|
+
|
|
535
|
+
function requireActiveServiceStart(result, operation, code = "") {
|
|
536
|
+
if (result?.ok !== true || result.active !== true) {
|
|
537
|
+
const message = `${operation} did not reach an active persistent service (${result?.provider || "unknown"})`;
|
|
538
|
+
if (code) throw activationOperationalError(message, code);
|
|
539
|
+
throw new Error(message);
|
|
540
|
+
}
|
|
541
|
+
}
|
|
542
|
+
|
|
543
|
+
function activationOperationalError(message, code) {
|
|
544
|
+
const error = new Error(message);
|
|
545
|
+
error.code = code;
|
|
546
|
+
return error;
|
|
547
|
+
}
|
|
548
|
+
|
|
549
|
+
function recoverablePostReadySettlement(error) {
|
|
550
|
+
return isActivationRecoveryReason(error?.code);
|
|
551
|
+
}
|
|
552
|
+
|
|
553
|
+
function activationRecoveryDetail(error) {
|
|
554
|
+
return canonicalActivationRecoveryDetail(activationRecoveryReason(error));
|
|
555
|
+
}
|
|
556
|
+
|
|
557
|
+
function activationFailureWithRecovery(error) {
|
|
558
|
+
const message = activationErrorMessage(error);
|
|
559
|
+
const recoveredMessage = `${message}; a compatible candidate service was installed, started, and verified ready for automatic recovery`;
|
|
560
|
+
const recovered = error instanceof AggregateError
|
|
561
|
+
? new AggregateError(error.errors, recoveredMessage, { cause: error })
|
|
562
|
+
: error instanceof TypeError
|
|
563
|
+
? new TypeError(recoveredMessage, { cause: error })
|
|
564
|
+
: error instanceof RangeError
|
|
565
|
+
? new RangeError(recoveredMessage, { cause: error })
|
|
566
|
+
: new Error(recoveredMessage, { cause: error });
|
|
567
|
+
if (error?.code) recovered.code = error.code;
|
|
568
|
+
recovered.activationRecovery = "candidate_service_started";
|
|
569
|
+
return recovered;
|
|
570
|
+
}
|
|
571
|
+
|
|
572
|
+
function activationCleanupFailure(error, cleanupErrors) {
|
|
573
|
+
const details = cleanupErrors.slice(0, 4).map(activationErrorMessage).join("; ");
|
|
574
|
+
const aggregate = new AggregateError(
|
|
575
|
+
[error, ...cleanupErrors],
|
|
576
|
+
`persistent runtime activation failed: ${activationErrorMessage(error)}; local cleanup was incomplete: ${details}`,
|
|
577
|
+
);
|
|
578
|
+
aggregate.cleanupIncomplete = true;
|
|
579
|
+
if (error?.code) aggregate.code = error.code;
|
|
580
|
+
return aggregate;
|
|
581
|
+
}
|
|
582
|
+
|
|
583
|
+
function activationErrorMessage(error) {
|
|
584
|
+
return error instanceof Error && error.message ? error.message : String(error || "activation failed");
|
|
585
|
+
}
|
|
586
|
+
|
|
587
|
+
function activationRecoveryReason(error) {
|
|
588
|
+
const code = String(error?.code || "");
|
|
589
|
+
if (!isActivationRecoveryReason(code)) throw new Error("activation recovery reason is invalid");
|
|
590
|
+
return code;
|
|
591
|
+
}
|
|
592
|
+
|
|
593
|
+
export async function waitForRestoredServiceRuntime({
|
|
594
|
+
inspectDaemon, expectedVersion, maximumAttempts = 240, wait = defaultWait,
|
|
595
|
+
} = {}) {
|
|
596
|
+
if (typeof inspectDaemon !== "function") throw new TypeError("previous runtime recovery requires a daemon inspector");
|
|
597
|
+
const attempts = boundedAttempts(maximumAttempts);
|
|
598
|
+
let daemon = null;
|
|
599
|
+
for (let attempt = 1; attempt <= attempts; attempt += 1) {
|
|
600
|
+
daemon = await inspectDaemon();
|
|
601
|
+
if (daemon?.alive && daemon?.verified_service_daemon
|
|
602
|
+
&& daemon?.mode === "service" && daemon?.version === expectedVersion) {
|
|
603
|
+
return { ok: true, attempts: attempt, daemon };
|
|
604
|
+
}
|
|
605
|
+
if (attempt < attempts) await wait(attempt);
|
|
606
|
+
}
|
|
607
|
+
const reason = !daemon?.alive ? "daemon_not_running"
|
|
608
|
+
: daemon?.verified_service_daemon !== true ? `daemon_identity_${daemon?.identity_reason || "unverified"}`
|
|
609
|
+
: daemon?.mode !== "service" ? `daemon_mode_${daemon?.mode || "unknown"}`
|
|
610
|
+
: `daemon_version_${daemon?.version || "unknown"}`;
|
|
611
|
+
return { ok: false, attempts, daemon, reason };
|
|
612
|
+
}
|
|
613
|
+
|
|
614
|
+
export async function waitForActivatedRuntime({
|
|
615
|
+
inspectDaemon,
|
|
616
|
+
checkWorker,
|
|
617
|
+
expectedVersion,
|
|
618
|
+
maximumAttempts = 240,
|
|
619
|
+
wait = defaultWait,
|
|
620
|
+
} = {}) {
|
|
621
|
+
if (typeof inspectDaemon !== "function" || typeof checkWorker !== "function") {
|
|
622
|
+
throw new TypeError("runtime activation requires daemon and Worker inspectors");
|
|
623
|
+
}
|
|
624
|
+
const attempts = boundedAttempts(maximumAttempts);
|
|
625
|
+
let daemon = null;
|
|
626
|
+
let worker = null;
|
|
627
|
+
for (let attempt = 1; attempt <= attempts; attempt += 1) {
|
|
628
|
+
daemon = await inspectDaemon();
|
|
629
|
+
if (daemon?.alive && daemon?.verified_service_daemon
|
|
630
|
+
&& daemon?.startup_readiness_verified === true
|
|
631
|
+
&& daemon?.version === expectedVersion) {
|
|
632
|
+
worker = await checkWorker();
|
|
633
|
+
if (worker?.ok && worker?.version === expectedVersion) {
|
|
634
|
+
return { ok: true, attempts: attempt, daemon, worker };
|
|
635
|
+
}
|
|
636
|
+
}
|
|
637
|
+
if (attempt < attempts) await wait(attempt);
|
|
638
|
+
}
|
|
639
|
+
const reasons = [];
|
|
640
|
+
if (!daemon?.alive) reasons.push("daemon_not_running");
|
|
641
|
+
else if (!daemon?.verified_service_daemon) reasons.push(`daemon_identity_${daemon?.identity_reason || "unverified"}`);
|
|
642
|
+
else if (daemon?.startup_readiness_verified !== true) reasons.push("daemon_startup_readiness_unverified");
|
|
643
|
+
else if (daemon?.version !== expectedVersion) reasons.push(`daemon_version_${daemon?.version || "unknown"}`);
|
|
644
|
+
if (!worker?.ok) reasons.push(`worker_${worker?.error || "not_ready"}`);
|
|
645
|
+
else if (worker?.version !== expectedVersion) reasons.push(`worker_version_${worker?.version || "unknown"}`);
|
|
646
|
+
return { ok: false, attempts, daemon, worker, reason: reasons.join(",") || "activation_not_converged" };
|
|
647
|
+
}
|
|
648
|
+
|
|
649
|
+
function requiredExpectedVersion(value) {
|
|
650
|
+
if (typeof value !== "string" || !/^[0-9A-Za-z.+-]{1,128}$/.test(value)) {
|
|
651
|
+
throw new TypeError("runtime activation expectedVersion must be a bounded package version string");
|
|
652
|
+
}
|
|
653
|
+
return value;
|
|
654
|
+
}
|
|
655
|
+
|
|
656
|
+
function optionalFunction(value, name, fallback) {
|
|
657
|
+
if (value === undefined) return fallback;
|
|
658
|
+
if (typeof value !== "function") throw new TypeError(`runtime activation ${name} must be a function`);
|
|
659
|
+
return value;
|
|
660
|
+
}
|
|
661
|
+
|
|
662
|
+
function requireReleasableLock(lock, name) {
|
|
663
|
+
if (!lock || typeof lock.release !== "function") {
|
|
664
|
+
throw new TypeError(`runtime activation ${name} lock must expose release`);
|
|
665
|
+
}
|
|
666
|
+
}
|
|
667
|
+
|
|
668
|
+
function boundedAttempts(value) {
|
|
669
|
+
const parsed = Number(value);
|
|
670
|
+
if (!Number.isSafeInteger(parsed) || parsed < 1 || parsed > 1200) {
|
|
671
|
+
throw new Error("runtime activation attempts must be between 1 and 1200");
|
|
672
|
+
}
|
|
673
|
+
return parsed;
|
|
674
|
+
}
|
|
675
|
+
|
|
676
|
+
function boundedCandidateStartAttempts(value) {
|
|
677
|
+
const parsed = Number(value);
|
|
678
|
+
if (!Number.isSafeInteger(parsed) || parsed < 1 || parsed > 10) {
|
|
679
|
+
throw new Error("candidate relay start attempts must be between 1 and 10");
|
|
680
|
+
}
|
|
681
|
+
return parsed;
|
|
682
|
+
}
|
|
683
|
+
|
|
684
|
+
function boundedRestoreStartAttempts(value) {
|
|
685
|
+
const parsed = Number(value);
|
|
686
|
+
if (!Number.isSafeInteger(parsed) || parsed < 1 || parsed > 60) {
|
|
687
|
+
throw new Error("runtime activation restore-start attempts must be between 1 and 60");
|
|
688
|
+
}
|
|
689
|
+
return parsed;
|
|
690
|
+
}
|
|
691
|
+
|
|
692
|
+
function defaultWait(attempt) {
|
|
693
|
+
const delay = Math.min(1_000, 100 + attempt * 25);
|
|
694
|
+
return new Promise((resolvePromise) => { setTimeout(resolvePromise, delay); });
|
|
695
|
+
}
|
|
696
|
+
|
|
697
|
+
function defaultCandidateRetryWait(attempt) {
|
|
698
|
+
const delay = Math.min(15_000, 1_000 * (2 ** Math.max(0, attempt - 1)));
|
|
699
|
+
return new Promise((resolvePromise) => { setTimeout(resolvePromise, delay); });
|
|
700
|
+
}
|