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
|
@@ -1,68 +1,115 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
import { spawn, spawnSync } from "node:child_process";
|
|
4
|
-
import {
|
|
4
|
+
import { createHash } from "node:crypto";
|
|
5
|
+
import { readFileSync, rmSync } from "node:fs";
|
|
5
6
|
import { dirname, join, resolve } from "node:path";
|
|
6
7
|
import { fileURLToPath } from "node:url";
|
|
8
|
+
import { defaultStateRoot, expandHome, selectedWorkspace } from "../src/local/state.mjs";
|
|
9
|
+
import { ensureOwnerOnlyDirectorySync } from "../src/local/secure-file.mjs";
|
|
10
|
+
import { createCandidateRuntimePrefix, isNonBlockingCandidateRuntimeCleanupError, pruneInactiveCandidateRuntimes } from "./candidate-runtime-store.mjs";
|
|
11
|
+
import { ACTIVATION_SCHEMA_VERSION, writePrereleaseActivation } from "./prerelease-activation.mjs";
|
|
7
12
|
import { verifyTarball } from "./release-acceptance.mjs";
|
|
13
|
+
import { parseReleaseVersion } from "./release-channel.mjs";
|
|
14
|
+
import { discoverForegroundDaemonRecovery } from "./foreground-daemon-recovery.mjs";
|
|
15
|
+
import { assertPersistentActivationExecutionSurface, persistentActivationSpawnOptions, persistentCandidateFailureMessage, preflightPersistentActivationWorkerAuth, validateActivationRecoveryPayload } from "./persistent-activation-process.mjs";
|
|
16
|
+
import { assertCandidateMatchesCurrentSource, validateCandidateManifest } from "./release-candidate-manifest.mjs";
|
|
17
|
+
import { computePromotionContentDigest } from "./promotion-digest.mjs";
|
|
18
|
+
import { createHardenedNpmSession, settleHardenedNpmSession } from "./hardened-npm-session.mjs";
|
|
19
|
+
import { nestedNpmEnvironment } from "../src/local/npm-environment.mjs";
|
|
20
|
+
import { withReleaseRuntimeLock } from "../src/local/release-runtime-lock.mjs";
|
|
21
|
+
import { releaseCommandFailure, releaseDiagnostic, releaseDiagnosticEvent } from "./release-diagnostic.mjs";
|
|
22
|
+
import { inspectGlobalPackageInstallation } from "./global-package-installation.mjs";
|
|
23
|
+
import { resolveNpmGlobalPrefix } from "./npm-global-prefix.mjs";
|
|
24
|
+
import { resolveNpmCli } from "../src/local/npm-cli.mjs";
|
|
25
|
+
import { publishReleaseBrowserExtension } from "./release-browser-extension-store.mjs";
|
|
8
26
|
|
|
9
27
|
const root = resolve(dirname(fileURLToPath(import.meta.url)), "..");
|
|
10
28
|
const candidateDirectory = join(root, ".release-candidate");
|
|
11
29
|
const manifestPath = join(candidateDirectory, "manifest.json");
|
|
12
|
-
const
|
|
13
|
-
const
|
|
14
|
-
|
|
15
|
-
|
|
30
|
+
const foregroundInstallPrefix = join(candidateDirectory, "runtime");
|
|
31
|
+
const installOnly = process.argv.includes("--install-only");
|
|
32
|
+
const activateService = process.argv.includes("--activate-service");
|
|
33
|
+
const allowWorkerDeploy = process.argv.includes("--allow-worker-deploy");
|
|
34
|
+
const persistentActivation = activateService && !installOnly;
|
|
35
|
+
const lifecycleNpmCli = process.env.npm_execpath;
|
|
36
|
+
let sourceNpmCli = lifecycleNpmCli;
|
|
37
|
+
let npmCli = "";
|
|
38
|
+
let npmSession = null;
|
|
39
|
+
let persistentExecutionSurface = "local";
|
|
16
40
|
|
|
17
41
|
try {
|
|
18
|
-
|
|
19
|
-
if (
|
|
20
|
-
|
|
42
|
+
if (persistentActivation) persistentExecutionSurface = assertPersistentActivationExecutionSurface(process.env);
|
|
43
|
+
if (installOnly) sourceNpmCli = resolveNpmCli({ allowLifecycleNpmCli: false, allowFallbackLocations: false });
|
|
44
|
+
if (!sourceNpmCli) throw new Error("candidate live startup must run through npm so npm_execpath is available");
|
|
45
|
+
const currentPackage = readJson(join(root, "package.json"), "current package");
|
|
46
|
+
const manifest = validateCandidateManifest(
|
|
47
|
+
readJson(manifestPath, "release candidate manifest"),
|
|
48
|
+
{ packageName: currentPackage.name, packageVersion: currentPackage.version },
|
|
49
|
+
);
|
|
50
|
+
assertCandidateMatchesCurrentSource(manifest, {
|
|
51
|
+
packageName: currentPackage.name,
|
|
52
|
+
packageVersion: currentPackage.version,
|
|
53
|
+
promotionDigest: computePromotionContentDigest(root, { npmCli: sourceNpmCli }),
|
|
54
|
+
});
|
|
55
|
+
const tarball = join(candidateDirectory, manifest.filename);
|
|
21
56
|
verifyTarball(tarball, manifest);
|
|
57
|
+
if (!installOnly && !allowWorkerDeploy) {
|
|
58
|
+
throw new Error("candidate activation may update the configured same-name Worker; rerun with --allow-worker-deploy to authorize that live candidate deployment");
|
|
59
|
+
}
|
|
60
|
+
const globalPrefix = persistentActivation
|
|
61
|
+
? resolveNpmGlobalPrefix(lifecycleNpmCli, { cwd: root, env: process.env })
|
|
62
|
+
: "";
|
|
63
|
+
npmSession = await createHardenedNpmSession();
|
|
64
|
+
npmCli = npmSession.cli;
|
|
22
65
|
|
|
23
66
|
const npmVersion = runNpm(["--version"], root).stdout.trim();
|
|
24
|
-
if (
|
|
25
|
-
throw new Error(`candidate startup
|
|
67
|
+
if (npmVersion !== npmSession.version) {
|
|
68
|
+
throw new Error(`candidate startup hardened npm reported ${npmVersion || "no version"}, expected ${npmSession.version}`);
|
|
26
69
|
}
|
|
27
70
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
71
|
+
const stateRoot = resolve(expandHome(argumentValue("--state-dir") || defaultStateRoot()));
|
|
72
|
+
const forwardedArgs = process.argv.slice(2).filter((value) => ![
|
|
73
|
+
"--install-only", "--allow-worker-deploy", "--activate-service",
|
|
74
|
+
].includes(value));
|
|
75
|
+
if (persistentActivation) {
|
|
76
|
+
await preflightPersistentActivationWorkerAuth({
|
|
77
|
+
surface: persistentExecutionSurface,
|
|
78
|
+
stateRoot,
|
|
79
|
+
packageRoot: root,
|
|
80
|
+
npmCli,
|
|
81
|
+
env: process.env,
|
|
82
|
+
});
|
|
83
|
+
await withReleaseRuntimeLock(stateRoot, async () => {
|
|
84
|
+
const installPrefix = createCandidateRuntimePrefix({ stateRoot, version: manifest.package_version, shasum: manifest.shasum });
|
|
85
|
+
const installedPackage = installCandidateRuntime({ installPrefix, manifest, tarball });
|
|
86
|
+
const previousInstallation = persistentActivation
|
|
87
|
+
? currentGlobalInstallation(manifest.package_name, globalPrefix, npmCli)
|
|
88
|
+
: null;
|
|
89
|
+
disposeNpmSession();
|
|
90
|
+
activatePersistentCandidate({
|
|
91
|
+
manifest, installedPackage, installPrefix, stateRoot, forwardedArgs, previousInstallation,
|
|
92
|
+
});
|
|
93
|
+
});
|
|
94
|
+
process.exit(0);
|
|
44
95
|
}
|
|
45
96
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
const
|
|
49
|
-
|
|
97
|
+
const installPrefix = foregroundInstallPrefix;
|
|
98
|
+
rmSync(installPrefix, { recursive: true, force: true });
|
|
99
|
+
const installedPackage = installCandidateRuntime({ installPrefix, manifest, tarball });
|
|
100
|
+
disposeNpmSession();
|
|
50
101
|
if (installOnly) {
|
|
51
|
-
|
|
102
|
+
rmSync(installPrefix, { recursive: true, force: true, maxRetries: 3, retryDelay: 50 });
|
|
103
|
+
console.log("Candidate installation check passed; temporary runtime was removed and startup was skipped by --install-only.");
|
|
52
104
|
process.exit(0);
|
|
53
105
|
}
|
|
54
106
|
|
|
55
|
-
if (!allowWorkerDeploy) {
|
|
56
|
-
throw new Error("foreground candidate startup may update the configured same-name Worker; rerun with --allow-worker-deploy to authorize that live candidate deployment");
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
const forwardedArgs = process.argv.slice(2).filter((value) => value !== "--install-only" && value !== "--allow-worker-deploy");
|
|
60
107
|
const cli = join(installedPackage, "bin", "machine-mcp.mjs");
|
|
61
108
|
console.log("Authorized live candidate deployment: startup may update the configured same-name Worker when its version or deployment hash differs.");
|
|
62
109
|
console.log("Starting the exact candidate in the foreground. Leave this process running while the coding agent verifies the Worker, relay, and local runtime end to end.");
|
|
63
110
|
const child = spawn(process.execPath, [cli, ...forwardedArgs], {
|
|
64
111
|
cwd: root,
|
|
65
|
-
env: process.env,
|
|
112
|
+
env: nestedNpmEnvironment(process.env),
|
|
66
113
|
stdio: "inherit",
|
|
67
114
|
windowsHide: true,
|
|
68
115
|
});
|
|
@@ -83,22 +130,198 @@ try {
|
|
|
83
130
|
process.exitCode = code ?? 1;
|
|
84
131
|
});
|
|
85
132
|
} catch (error) {
|
|
86
|
-
|
|
133
|
+
const settled = settleNpmSession(error);
|
|
134
|
+
fail(settled?.message || settled);
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
function installCandidateRuntime({ installPrefix, manifest, tarball }) {
|
|
138
|
+
ensureOwnerOnlyDirectorySync(installPrefix);
|
|
139
|
+
runNpm([
|
|
140
|
+
"install",
|
|
141
|
+
"--dry-run=false",
|
|
142
|
+
"--workspaces=false",
|
|
143
|
+
"--ignore-scripts=false",
|
|
144
|
+
"--global",
|
|
145
|
+
"--prefix", installPrefix,
|
|
146
|
+
"--omit=optional",
|
|
147
|
+
"--include=prod",
|
|
148
|
+
"--package-lock-only=false",
|
|
149
|
+
"--allow-scripts=esbuild,workerd,sharp,fsevents",
|
|
150
|
+
tarball,
|
|
151
|
+
], root);
|
|
152
|
+
const globalRoot = runNpm(["root", "--json=false", "--parseable=false", "--workspaces=false", "--global", "--prefix", installPrefix], root).stdout.trim();
|
|
153
|
+
const installedPackage = join(globalRoot, manifest.package_name);
|
|
154
|
+
const installed = readJson(join(installedPackage, "package.json"), "installed candidate package");
|
|
155
|
+
if (installed.version !== manifest.package_version) {
|
|
156
|
+
throw new Error(`installed candidate version ${installed.version} does not match ${manifest.package_version}`);
|
|
157
|
+
}
|
|
158
|
+
console.log(`Verified candidate tarball: ${manifest.filename} (${manifest.shasum})`);
|
|
159
|
+
console.log(`Installed isolated candidate: ${installedPackage}`);
|
|
160
|
+
return installedPackage;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
function activatePersistentCandidate({
|
|
164
|
+
manifest, installedPackage, installPrefix, stateRoot, forwardedArgs, previousInstallation,
|
|
165
|
+
}) {
|
|
166
|
+
const releaseVersion = parseReleaseVersion(manifest.package_version);
|
|
167
|
+
const cli = join(installedPackage, "bin", "machine-mcp.mjs");
|
|
168
|
+
const args = ["activate", ...withoutManagedFlags(forwardedArgs), "--state-dir", stateRoot, "--json"];
|
|
169
|
+
console.log("Activating the exact prerelease as the persistent login daemon. Portable-root startup does not prompt; a separately provisioned Secure Enclave broker may request one user-presence operation.");
|
|
170
|
+
const result = spawnSync(
|
|
171
|
+
process.execPath,
|
|
172
|
+
[cli, ...args],
|
|
173
|
+
persistentActivationSpawnOptions({ cwd: root, env: nestedNpmEnvironment(process.env) }),
|
|
174
|
+
);
|
|
175
|
+
if (result.error) throw result.error;
|
|
176
|
+
if (result.status !== 0) {
|
|
177
|
+
const output = result.stderr || result.stdout;
|
|
178
|
+
const requestedWorkspace = argumentListValue("--workspace", withoutManagedFlags(forwardedArgs))
|
|
179
|
+
|| selectedWorkspace(stateRoot);
|
|
180
|
+
const previousRuntime = discoverForegroundDaemonRecovery({
|
|
181
|
+
output, stateRoot, workspace: requestedWorkspace,
|
|
182
|
+
});
|
|
183
|
+
throw new Error(persistentCandidateFailureMessage(output, { cli, stateRoot, previousRuntime }));
|
|
184
|
+
}
|
|
185
|
+
let activation;
|
|
186
|
+
try { activation = JSON.parse(result.stdout); } catch { throw new Error("persistent candidate activation did not return valid JSON"); }
|
|
187
|
+
if (
|
|
188
|
+
activation.ok !== true
|
|
189
|
+
|| activation.version !== manifest.package_version
|
|
190
|
+
|| activation.daemon?.version !== manifest.package_version
|
|
191
|
+
|| activation.worker?.health?.version !== manifest.package_version
|
|
192
|
+
) {
|
|
193
|
+
throw new Error("persistent candidate activation did not converge on the exact candidate version");
|
|
194
|
+
}
|
|
195
|
+
const recovery = validateActivationRecoveryPayload(activation);
|
|
196
|
+
|
|
197
|
+
let publishedBrowserExtension;
|
|
198
|
+
try {
|
|
199
|
+
publishedBrowserExtension = publishReleaseBrowserExtension({
|
|
200
|
+
stateRoot,
|
|
201
|
+
sourceDirectory: join(installedPackage, "browser-extension"),
|
|
202
|
+
expectedVersion: manifest.package_version,
|
|
203
|
+
});
|
|
204
|
+
} catch (error) {
|
|
205
|
+
throw new Error(
|
|
206
|
+
"persistent candidate activation converged, but the stable browser extension could not be published; the candidate Worker/service is live and must be inspected before retrying",
|
|
207
|
+
{ cause: error },
|
|
208
|
+
);
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
let removedRuntimes = [];
|
|
212
|
+
let runtimeCleanupWarning = "";
|
|
213
|
+
try {
|
|
214
|
+
removedRuntimes = pruneInactiveCandidateRuntimes({ stateRoot, activePrefix: installPrefix });
|
|
215
|
+
} catch (error) {
|
|
216
|
+
if (!isNonBlockingCandidateRuntimeCleanupError(error)) throw error;
|
|
217
|
+
runtimeCleanupWarning = boundedCleanupWarning(error);
|
|
218
|
+
}
|
|
219
|
+
let recordPath = "";
|
|
220
|
+
if (releaseVersion.prerelease) {
|
|
221
|
+
recordPath = writePrereleaseActivation({
|
|
222
|
+
schema_version: ACTIVATION_SCHEMA_VERSION,
|
|
223
|
+
package_name: manifest.package_name,
|
|
224
|
+
package_version: manifest.package_version,
|
|
225
|
+
source: "local-candidate",
|
|
226
|
+
shasum: manifest.shasum,
|
|
227
|
+
integrity: manifest.integrity,
|
|
228
|
+
promotion_content_sha256: manifest.promotion_content_sha256,
|
|
229
|
+
activated_at: new Date().toISOString(),
|
|
230
|
+
workspace_hash: workspaceHash(activation.workspace),
|
|
231
|
+
runtime_entry: cli,
|
|
232
|
+
...(recovery.recovered ? {
|
|
233
|
+
activation_recovered: true,
|
|
234
|
+
activation_recovery_reason: recovery.reason,
|
|
235
|
+
activation_recovery_detail: recovery.detail,
|
|
236
|
+
} : {}),
|
|
237
|
+
...(previousInstallation ? { global_package_rollback_baseline: previousInstallation } : {}),
|
|
238
|
+
}, stateRoot);
|
|
239
|
+
}
|
|
240
|
+
if (recovery.recovered) {
|
|
241
|
+
console.warn(`Persistent activation used verified candidate-service recovery (${recovery.reason}): ${recovery.detail}`);
|
|
242
|
+
}
|
|
243
|
+
console.log(`Persistent release candidate activated: ${manifest.package_version}`);
|
|
244
|
+
console.log(`Stable browser extension published: ${publishedBrowserExtension.path}`);
|
|
245
|
+
if (recordPath) console.log(`Activation record: ${recordPath}`);
|
|
246
|
+
if (removedRuntimes.length) console.log(`Removed ${removedRuntimes.length} inactive candidate runtime(s).`);
|
|
247
|
+
if (runtimeCleanupWarning) console.warn(`Candidate activation succeeded but inactive runtime cleanup was incomplete: ${runtimeCleanupWarning}`);
|
|
248
|
+
console.log("The Worker and login daemon now run the exact candidate. The terminal may close; the coding agent should verify the live deployment through Machine Bridge.");
|
|
249
|
+
if (previousInstallation?.version) {
|
|
250
|
+
console.log(`Global package rollback baseline retained: ${previousInstallation.version}.`);
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
|
|
255
|
+
function currentGlobalInstallation(packageName, globalPrefix, npmExecutable) {
|
|
256
|
+
const globalRoot = runNpm(
|
|
257
|
+
["root", "--json=false", "--parseable=false", "--workspaces=false", "--global", "--prefix", globalPrefix],
|
|
258
|
+
root,
|
|
259
|
+
npmExecutable,
|
|
260
|
+
).stdout.trim();
|
|
261
|
+
return inspectGlobalPackageInstallation(globalRoot, packageName);
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
function withoutManagedFlags(args) {
|
|
265
|
+
const out = [];
|
|
266
|
+
for (let index = 0; index < args.length; index += 1) {
|
|
267
|
+
const value = args[index];
|
|
268
|
+
if (value === "--json" || value.startsWith("--json=")) continue;
|
|
269
|
+
if (value === "--state-dir") { index += 1; continue; }
|
|
270
|
+
if (value.startsWith("--state-dir=")) continue;
|
|
271
|
+
out.push(value);
|
|
272
|
+
}
|
|
273
|
+
return out;
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
function argumentListValue(name, args) {
|
|
277
|
+
const exact = args.find(value => value.startsWith(`${name}=`));
|
|
278
|
+
if (exact) return exact.slice(name.length + 1);
|
|
279
|
+
const index = args.indexOf(name);
|
|
280
|
+
return index >= 0 ? args[index + 1] || "" : "";
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
function argumentValue(name) {
|
|
284
|
+
const exact = process.argv.find((value) => value.startsWith(`${name}=`));
|
|
285
|
+
if (exact) return exact.slice(name.length + 1);
|
|
286
|
+
const index = process.argv.indexOf(name);
|
|
287
|
+
return index >= 0 ? process.argv[index + 1] : "";
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
function workspaceHash(workspace) {
|
|
291
|
+
const value = process.platform === "win32" ? String(workspace).toLowerCase() : String(workspace);
|
|
292
|
+
return createHash("sha256").update(value).digest("hex").slice(0, 24);
|
|
87
293
|
}
|
|
88
294
|
|
|
89
|
-
function runNpm(args, cwd) {
|
|
90
|
-
const
|
|
295
|
+
function runNpm(args, cwd, npmExecutable = npmCli) {
|
|
296
|
+
const cli = String(npmExecutable || "");
|
|
297
|
+
if (!cli) throw new Error("nested npm CLI is unavailable");
|
|
298
|
+
const result = spawnSync(process.execPath, [cli, ...args], {
|
|
91
299
|
cwd,
|
|
92
300
|
encoding: "utf8",
|
|
93
|
-
env: process.env,
|
|
301
|
+
env: nestedNpmEnvironment(process.env),
|
|
94
302
|
timeout: 300_000,
|
|
303
|
+
killSignal: "SIGKILL",
|
|
95
304
|
windowsHide: true,
|
|
96
305
|
});
|
|
97
|
-
if (result.error) throw result
|
|
98
|
-
if (result.status !== 0) throw new Error(`npm ${args[0]} failed: ${result.stderr || result.stdout}`);
|
|
306
|
+
if (result.error || result.status !== 0) throw new Error(releaseCommandFailure("npm", args, result));
|
|
99
307
|
return result;
|
|
100
308
|
}
|
|
101
309
|
|
|
310
|
+
function disposeNpmSession() {
|
|
311
|
+
const error = settleNpmSession();
|
|
312
|
+
if (error) throw error;
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
function settleNpmSession(primaryError = null) {
|
|
316
|
+
const session = npmSession;
|
|
317
|
+
npmSession = null;
|
|
318
|
+
return settleHardenedNpmSession(session, primaryError, "release candidate failed and hardened npm temporary cleanup was incomplete");
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
function boundedCleanupWarning(error) {
|
|
322
|
+
return releaseDiagnostic(error?.message || error || "candidate runtime cleanup failed", 600);
|
|
323
|
+
}
|
|
324
|
+
|
|
102
325
|
function readJson(path, label) {
|
|
103
326
|
try {
|
|
104
327
|
return JSON.parse(readFileSync(path, "utf8"));
|
|
@@ -108,6 +331,6 @@ function readJson(path, label) {
|
|
|
108
331
|
}
|
|
109
332
|
|
|
110
333
|
function fail(message) {
|
|
111
|
-
console.error(
|
|
334
|
+
console.error(JSON.stringify(releaseDiagnosticEvent("release.candidate.failed", message, 1200)));
|
|
112
335
|
process.exit(1);
|
|
113
336
|
}
|
package/scripts/syntax-check.mjs
CHANGED
|
@@ -1,28 +1,49 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
import { spawnSync } from "node:child_process";
|
|
4
|
-
import { readdirSync } from "node:fs";
|
|
4
|
+
import { readFileSync, readdirSync } from "node:fs";
|
|
5
5
|
import { dirname, extname, join, relative, resolve } from "node:path";
|
|
6
6
|
import { fileURLToPath } from "node:url";
|
|
7
|
+
import * as vm from "node:vm";
|
|
7
8
|
|
|
8
9
|
const root = resolve(dirname(fileURLToPath(import.meta.url)), "..");
|
|
9
|
-
const roots = ["bin", "src/local", "scripts", "tests", "browser-extension"];
|
|
10
|
+
const roots = ["bin", "src/local", "src/shared", "scripts", "tests", "browser-extension", ".github/scripts"];
|
|
10
11
|
const files = roots.flatMap((entry) => collect(join(root, entry)))
|
|
11
12
|
.filter((file) => [".js", ".mjs"].includes(extname(file)))
|
|
12
13
|
.sort();
|
|
14
|
+
const parserMode = process.argv.includes("--vm-parse");
|
|
13
15
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
16
|
+
if (parserMode) {
|
|
17
|
+
if (typeof vm.SourceTextModule !== "function") throw new Error("VM module parser is unavailable");
|
|
18
|
+
for (const file of files) {
|
|
19
|
+
try {
|
|
20
|
+
let source = readFileSync(file, "utf8");
|
|
21
|
+
if (source.startsWith("#!")) source = source.replace(/^#![^\n]*(?:\n|$)/, "\n");
|
|
22
|
+
new vm.SourceTextModule(source, { identifier: relative(root, file) });
|
|
23
|
+
} catch (error) {
|
|
24
|
+
process.stderr.write(`syntax check failed: ${relative(root, file)}\n${String(error?.stack || error)}\n`);
|
|
25
|
+
process.exit(1);
|
|
26
|
+
}
|
|
25
27
|
}
|
|
28
|
+
process.exit(0);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
const parser = spawnSync(process.execPath, [
|
|
32
|
+
"--experimental-vm-modules",
|
|
33
|
+
"--no-warnings",
|
|
34
|
+
fileURLToPath(import.meta.url),
|
|
35
|
+
"--vm-parse",
|
|
36
|
+
], {
|
|
37
|
+
cwd: root,
|
|
38
|
+
encoding: "utf8",
|
|
39
|
+
windowsHide: true,
|
|
40
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
41
|
+
shell: false,
|
|
42
|
+
});
|
|
43
|
+
if (parser.error) throw parser.error;
|
|
44
|
+
if (parser.status !== 0) {
|
|
45
|
+
process.stderr.write(parser.stderr || parser.stdout || "syntax parser failed without output\n");
|
|
46
|
+
process.exit(parser.status ?? 1);
|
|
26
47
|
}
|
|
27
48
|
|
|
28
49
|
if (process.platform !== "win32") {
|
|
@@ -31,6 +52,7 @@ if (process.platform !== "win32") {
|
|
|
31
52
|
encoding: "utf8",
|
|
32
53
|
windowsHide: true,
|
|
33
54
|
stdio: ["ignore", "pipe", "pipe"],
|
|
55
|
+
shell: false,
|
|
34
56
|
});
|
|
35
57
|
if (shell.error) throw shell.error;
|
|
36
58
|
if (shell.status !== 0) {
|
|
@@ -39,7 +61,7 @@ if (process.platform !== "win32") {
|
|
|
39
61
|
}
|
|
40
62
|
}
|
|
41
63
|
|
|
42
|
-
console.log(`syntax check ok (${files.length} JavaScript files${process.platform === "win32" ? "" : "; mbm shell wrapper"})`);
|
|
64
|
+
console.log(`syntax check ok (${files.length} JavaScript files in one parser process${process.platform === "win32" ? "" : "; mbm shell wrapper"})`);
|
|
43
65
|
|
|
44
66
|
function collect(directory) {
|
|
45
67
|
const files = [];
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export async function runWithStableGeneration({ captureGeneration, run, label = "verification inputs" }) {
|
|
2
|
+
if (typeof captureGeneration !== "function") throw new TypeError("captureGeneration must be a function");
|
|
3
|
+
if (typeof run !== "function") throw new TypeError("run must be a function");
|
|
4
|
+
const before = captureGeneration();
|
|
5
|
+
let result;
|
|
6
|
+
let runError;
|
|
7
|
+
try { result = await run(); }
|
|
8
|
+
catch (error) { runError = error; }
|
|
9
|
+
const after = captureGeneration();
|
|
10
|
+
if (after !== before) {
|
|
11
|
+
throw new Error(`${label} changed during verification; discard this run (${before} -> ${after})`);
|
|
12
|
+
}
|
|
13
|
+
if (runError) throw runError;
|
|
14
|
+
return result;
|
|
15
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { spawn } from "node:child_process";
|
|
2
|
+
import process from "node:process";
|
|
3
|
+
|
|
4
|
+
export const VERIFICATION_IDLE_SLEEP_GUARD_ENV = "MBM_CHECK_IDLE_SLEEP_GUARD";
|
|
5
|
+
|
|
6
|
+
export async function rerunVerificationUnderIdleSleepGuard(options = {}) {
|
|
7
|
+
const platform = options.platform ?? process.platform;
|
|
8
|
+
const env = options.env ?? process.env;
|
|
9
|
+
if (platform !== "darwin" || env[VERIFICATION_IDLE_SLEEP_GUARD_ENV] === "1") return null;
|
|
10
|
+
|
|
11
|
+
const executable = String(options.execPath || process.execPath);
|
|
12
|
+
const argv = Array.isArray(options.argv) ? options.argv.map(String) : process.argv.slice(1);
|
|
13
|
+
if (!executable || argv.length === 0 || !argv[0]) {
|
|
14
|
+
throw new Error("verification idle-sleep guard requires the current Node executable and entrypoint");
|
|
15
|
+
}
|
|
16
|
+
const spawnProcess = typeof options.spawnProcess === "function" ? options.spawnProcess : spawn;
|
|
17
|
+
let child;
|
|
18
|
+
try {
|
|
19
|
+
child = spawnProcess("/usr/bin/caffeinate", ["-i", executable, ...argv], {
|
|
20
|
+
env: { ...env, [VERIFICATION_IDLE_SLEEP_GUARD_ENV]: "1" },
|
|
21
|
+
stdio: "inherit",
|
|
22
|
+
shell: false,
|
|
23
|
+
windowsHide: true,
|
|
24
|
+
});
|
|
25
|
+
} catch (error) {
|
|
26
|
+
throw new Error("could not start the macOS verification idle-sleep guard", { cause: error });
|
|
27
|
+
}
|
|
28
|
+
return await new Promise((resolvePromise, rejectPromise) => {
|
|
29
|
+
child.once("error", (error) => {
|
|
30
|
+
rejectPromise(new Error("could not start the macOS verification idle-sleep guard", { cause: error }));
|
|
31
|
+
});
|
|
32
|
+
child.once("close", (code, signal) => {
|
|
33
|
+
if (Number.isInteger(code)) resolvePromise(code);
|
|
34
|
+
else rejectPromise(new Error(`macOS verification idle-sleep guard ended by signal ${signal || "unknown"}`));
|
|
35
|
+
});
|
|
36
|
+
});
|
|
37
|
+
}
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import { mkdirSync, readFileSync, rmSync } from "node:fs";
|
|
2
|
+
import { dirname, join } from "node:path";
|
|
3
|
+
import { captureCoverageGeneration } from "./coverage-generation.mjs";
|
|
4
|
+
import { replaceFileAtomicallySync } from "../src/local/exclusive-file.mjs";
|
|
5
|
+
import { readBoundedRegularFileWithInfoSync } from "../src/local/secure-file.mjs";
|
|
6
|
+
|
|
7
|
+
const RECEIPT_SCHEMA_VERSION = 1;
|
|
8
|
+
const RECEIPT_MAX_BYTES = 16 * 1024;
|
|
9
|
+
export const FULL_VERIFICATION_RECEIPT_MAX_AGE_MS = 6 * 60 * 60 * 1000;
|
|
10
|
+
|
|
11
|
+
const VERIFICATION_RUN_GENERATION_OPTIONS = {
|
|
12
|
+
roots: ["src", "scripts", "tests", "browser-extension", ".github", "docs", "bin", "native", "release-acceptance", ".release-candidate"],
|
|
13
|
+
files: [
|
|
14
|
+
"package.json", "package-lock.json", "tsconfig.json", "tsconfig.local.json", "wrangler.jsonc", "eslint.config.mjs",
|
|
15
|
+
".npmrc", ".node-version", ".nvmrc", ".gitattributes", ".gitignore", ".privacy-denylist", ".privacy-denylist.example",
|
|
16
|
+
"mbm", "mbm.cmd", "README.md", "CHANGELOG.md", "CONTRIBUTING.md", "SECURITY.md", "LICENSE",
|
|
17
|
+
"CODE_OF_CONDUCT.md", "GOVERNANCE.md", "SUPPORT.md", "AGENTS.md",
|
|
18
|
+
],
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
const VERIFIED_SOURCE_GENERATION_OPTIONS = {
|
|
22
|
+
...VERIFICATION_RUN_GENERATION_OPTIONS,
|
|
23
|
+
roots: VERIFICATION_RUN_GENERATION_OPTIONS.roots.filter((name) => name !== ".release-candidate"),
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
export function captureVerificationRunGeneration(root) {
|
|
27
|
+
return captureCoverageGeneration(root, VERIFICATION_RUN_GENERATION_OPTIONS);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export function captureVerifiedSourceGeneration(root) {
|
|
31
|
+
return captureCoverageGeneration(root, VERIFIED_SOURCE_GENERATION_OPTIONS);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export function fullVerificationReceiptPath(root) {
|
|
35
|
+
return join(root, ".project-local", "full-verification.json");
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export function clearFullVerificationReceipt(root) {
|
|
39
|
+
rmSync(fullVerificationReceiptPath(root), { force: true });
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export function writeFullVerificationReceipt(root, generation, options = {}) {
|
|
43
|
+
if (!/^[0-9a-f]{64}$/.test(String(generation || ""))) throw new TypeError("full verification generation must be a SHA-256 digest");
|
|
44
|
+
const pkg = readPackage(root);
|
|
45
|
+
const verifiedAtMs = Number(options.now ?? Date.now());
|
|
46
|
+
if (!Number.isFinite(verifiedAtMs)) throw new TypeError("full verification receipt timestamp must be finite");
|
|
47
|
+
const receipt = {
|
|
48
|
+
schema_version: RECEIPT_SCHEMA_VERSION,
|
|
49
|
+
mode: "full",
|
|
50
|
+
generation_sha256: generation,
|
|
51
|
+
package_name: pkg.name,
|
|
52
|
+
package_version: pkg.version,
|
|
53
|
+
node_version: process.version,
|
|
54
|
+
platform: process.platform,
|
|
55
|
+
arch: process.arch,
|
|
56
|
+
verified_at: new Date(verifiedAtMs).toISOString(),
|
|
57
|
+
};
|
|
58
|
+
const path = fullVerificationReceiptPath(root);
|
|
59
|
+
mkdirSync(dirname(path), { recursive: true, mode: 0o700 });
|
|
60
|
+
replaceFileAtomicallySync(path, `${JSON.stringify(receipt, null, 2)}\n`, { mode: 0o600 });
|
|
61
|
+
return receipt;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
export function assertFreshFullVerificationReceipt(root, options = {}) {
|
|
65
|
+
const path = fullVerificationReceiptPath(root);
|
|
66
|
+
let receipt;
|
|
67
|
+
try {
|
|
68
|
+
const snapshot = readBoundedRegularFileWithInfoSync(path, RECEIPT_MAX_BYTES, "full verification receipt", {
|
|
69
|
+
verifyPathIdentity: true,
|
|
70
|
+
rejectMultipleLinks: true,
|
|
71
|
+
});
|
|
72
|
+
receipt = JSON.parse(snapshot.buffer.toString("utf8"));
|
|
73
|
+
} catch (error) {
|
|
74
|
+
if (error?.code === "ENOENT") throw staleReceiptError("full verification receipt is missing");
|
|
75
|
+
throw staleReceiptError(`full verification receipt is unreadable or invalid: ${error.message}`);
|
|
76
|
+
}
|
|
77
|
+
const pkg = readPackage(root);
|
|
78
|
+
const generation = (options.captureGeneration || captureVerifiedSourceGeneration)(root);
|
|
79
|
+
const now = Number(options.now ?? Date.now());
|
|
80
|
+
const verifiedAt = Date.parse(String(receipt?.verified_at || ""));
|
|
81
|
+
const maximumAgeMs = Number(options.maximumAgeMs ?? FULL_VERIFICATION_RECEIPT_MAX_AGE_MS);
|
|
82
|
+
const valid = receipt?.schema_version === RECEIPT_SCHEMA_VERSION
|
|
83
|
+
&& receipt?.mode === "full"
|
|
84
|
+
&& receipt?.generation_sha256 === generation
|
|
85
|
+
&& receipt?.package_name === pkg.name
|
|
86
|
+
&& receipt?.package_version === pkg.version
|
|
87
|
+
&& receipt?.node_version === process.version
|
|
88
|
+
&& receipt?.platform === process.platform
|
|
89
|
+
&& receipt?.arch === process.arch
|
|
90
|
+
&& Number.isFinite(verifiedAt)
|
|
91
|
+
&& Number.isFinite(now)
|
|
92
|
+
&& Number.isFinite(maximumAgeMs)
|
|
93
|
+
&& maximumAgeMs >= 0
|
|
94
|
+
&& now >= verifiedAt
|
|
95
|
+
&& now - verifiedAt <= maximumAgeMs;
|
|
96
|
+
if (!valid) throw staleReceiptError("full verification receipt does not match the current source, runtime, or freshness window");
|
|
97
|
+
return receipt;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
function readPackage(root) {
|
|
101
|
+
return JSON.parse(readFileSync(join(root, "package.json"), "utf8"));
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
function staleReceiptError(reason) {
|
|
105
|
+
const error = new Error(`${reason}; run npm run check:full on the frozen tree before release:candidate`);
|
|
106
|
+
error.code = "MBM_FULL_VERIFICATION_REQUIRED";
|
|
107
|
+
return error;
|
|
108
|
+
}
|