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
|
@@ -13,14 +13,25 @@ import { runNetworkCommand } from "./network-retry.mjs";
|
|
|
13
13
|
import { requireSuccessfulWorkflowRun } from "./release-ci.mjs";
|
|
14
14
|
import { tagSyncError } from "./release-state.mjs";
|
|
15
15
|
import { verifyCurrentReleaseAcceptance } from "./release-acceptance.mjs";
|
|
16
|
+
import { stageAcceptedCandidateTarball } from "./accepted-candidate-tarball.mjs";
|
|
17
|
+
import { createHardenedNpmSession } from "./hardened-npm-session.mjs";
|
|
18
|
+
import { nestedNpmEnvironment } from "../src/local/npm-environment.mjs";
|
|
19
|
+
import { resolveTrustedGitExecutable } from "../src/local/trusted-git-executable.mjs";
|
|
20
|
+
import { resolveTrustedGithubCli } from "../src/local/trusted-github-cli.mjs";
|
|
21
|
+
import { githubReleaseByTagEndpoint, waitForGithubReleaseAsset } from "./github-release-asset.mjs";
|
|
22
|
+
import { parseReleaseVersion, requiresSoakForStable } from "./release-channel.mjs";
|
|
23
|
+
import { verifyCurrentStableSoak } from "./release-soak.mjs";
|
|
24
|
+
import { assertGithubPublicationAuthorized, withGithubPublicationLock } from "./release-publication-guard.mjs";
|
|
25
|
+
import { releaseCommandFailure, releaseDiagnostic, releaseDiagnosticEvent } from "./release-diagnostic.mjs";
|
|
16
26
|
import { fileURLToPath } from "node:url";
|
|
17
27
|
|
|
18
28
|
const root = resolve(dirname(fileURLToPath(import.meta.url)), "..");
|
|
29
|
+
const git = resolveTrustedGitExecutable({ workspace: root });
|
|
30
|
+
const gh = resolveTrustedGithubCli({ workspace: root });
|
|
19
31
|
process.chdir(root);
|
|
20
32
|
|
|
21
33
|
function fail(message) {
|
|
22
|
-
|
|
23
|
-
process.exit(1);
|
|
34
|
+
throw new Error(String(message || "release failed"));
|
|
24
35
|
}
|
|
25
36
|
|
|
26
37
|
function run(command, args, options = {}) {
|
|
@@ -28,17 +39,14 @@ function run(command, args, options = {}) {
|
|
|
28
39
|
cwd: root,
|
|
29
40
|
encoding: "utf8",
|
|
30
41
|
stdio: options.capture ? "pipe" : "inherit",
|
|
31
|
-
env: process.env,
|
|
42
|
+
env: options.env || process.env,
|
|
43
|
+
timeout: options.timeoutMs || 20 * 60 * 1000,
|
|
44
|
+
killSignal: "SIGKILL",
|
|
45
|
+
maxBuffer: 8 * 1024 * 1024,
|
|
32
46
|
});
|
|
33
47
|
|
|
34
|
-
if (result.error) {
|
|
35
|
-
fail(
|
|
36
|
-
}
|
|
37
|
-
if (result.status !== 0 && !options.allowFailure) {
|
|
38
|
-
const detail = options.capture
|
|
39
|
-
? `${result.stdout ?? ""}${result.stderr ?? ""}`.trim()
|
|
40
|
-
: "";
|
|
41
|
-
fail(`${command} ${args.join(" ")} failed${detail ? `: ${detail}` : ""}`);
|
|
48
|
+
if ((result.error || result.status !== 0) && !options.allowFailure) {
|
|
49
|
+
fail(releaseCommandFailure(command, args, options.capture ? result : { ...result, stdout: "", stderr: "" }));
|
|
42
50
|
}
|
|
43
51
|
return result;
|
|
44
52
|
}
|
|
@@ -50,9 +58,7 @@ function runNetwork(command, args, options = {}) {
|
|
|
50
58
|
if (result.stdout) process.stdout.write(result.stdout);
|
|
51
59
|
if (result.stderr) process.stderr.write(result.stderr);
|
|
52
60
|
}
|
|
53
|
-
if (result.error && !options.allowFailure)
|
|
54
|
-
fail(`${command} could not be started: ${result.error.message}`);
|
|
55
|
-
}
|
|
61
|
+
if (result.error && !options.allowFailure) fail(releaseCommandFailure(command, args, result));
|
|
56
62
|
if (result.status !== 0 && !options.allowFailure) failCommandResult(command, args, result);
|
|
57
63
|
return result;
|
|
58
64
|
}
|
|
@@ -63,8 +69,7 @@ function outputNetwork(command, args, options = {}) {
|
|
|
63
69
|
}
|
|
64
70
|
|
|
65
71
|
function failCommandResult(command, args, result) {
|
|
66
|
-
|
|
67
|
-
fail(`${command} ${args.join(" ")} failed${detail ? `: ${detail}` : ""}`);
|
|
72
|
+
fail(releaseCommandFailure(command, args, result));
|
|
68
73
|
}
|
|
69
74
|
|
|
70
75
|
function output(command, args, options = {}) {
|
|
@@ -72,6 +77,14 @@ function output(command, args, options = {}) {
|
|
|
72
77
|
return (result.stdout ?? "").trim();
|
|
73
78
|
}
|
|
74
79
|
|
|
80
|
+
|
|
81
|
+
function runNpmScript(npmCli, task) {
|
|
82
|
+
return run(process.execPath, [
|
|
83
|
+
npmCli, "run", "--workspaces=false", "--global=false", "--ignore-scripts=false",
|
|
84
|
+
"--if-present=false", "--prefix", root, task,
|
|
85
|
+
], { env: nestedNpmEnvironment(process.env) });
|
|
86
|
+
}
|
|
87
|
+
|
|
75
88
|
function packageMetadata() {
|
|
76
89
|
const data = JSON.parse(readFileSync(join(root, "package.json"), "utf8"));
|
|
77
90
|
if (typeof data.name !== "string" || typeof data.version !== "string") {
|
|
@@ -95,16 +108,16 @@ function changelogBody(version) {
|
|
|
95
108
|
}
|
|
96
109
|
|
|
97
110
|
function ensureClean() {
|
|
98
|
-
const status = output(
|
|
111
|
+
const status = output(git, ["status", "--porcelain"]);
|
|
99
112
|
if (status) fail(`working tree is not clean:\n${status}`);
|
|
100
113
|
}
|
|
101
114
|
|
|
102
115
|
function fetchRemote() {
|
|
103
|
-
runNetwork(
|
|
116
|
+
runNetwork(git, ["fetch", "origin", "main", "--tags", "--prune"]);
|
|
104
117
|
}
|
|
105
118
|
|
|
106
119
|
function localTagCommit(tag) {
|
|
107
|
-
const result = run(
|
|
120
|
+
const result = run(git, ["rev-list", "-n", "1", tag], {
|
|
108
121
|
capture: true,
|
|
109
122
|
allowFailure: true,
|
|
110
123
|
});
|
|
@@ -112,7 +125,7 @@ function localTagCommit(tag) {
|
|
|
112
125
|
}
|
|
113
126
|
|
|
114
127
|
function remoteTagCommit(tag) {
|
|
115
|
-
const text = outputNetwork(
|
|
128
|
+
const text = outputNetwork(git, [
|
|
116
129
|
"ls-remote",
|
|
117
130
|
"--tags",
|
|
118
131
|
"origin",
|
|
@@ -132,10 +145,11 @@ function assertSuccessfulCi(head) {
|
|
|
132
145
|
[".github/workflows/codeql.yml", "CodeQL"],
|
|
133
146
|
[".github/workflows/governance.yml", "Governance"],
|
|
134
147
|
[".github/workflows/scorecard.yml", "OpenSSF Scorecard"],
|
|
148
|
+
[".github/workflows/workflow-policy.yml", "Workflow Policy Gate"],
|
|
135
149
|
];
|
|
136
150
|
const verified = [];
|
|
137
151
|
for (const [workflow, name] of required) {
|
|
138
|
-
const text = outputNetwork(
|
|
152
|
+
const text = outputNetwork(gh, [
|
|
139
153
|
"run",
|
|
140
154
|
"list",
|
|
141
155
|
"--workflow",
|
|
@@ -162,27 +176,38 @@ function assertSuccessfulCi(head) {
|
|
|
162
176
|
}
|
|
163
177
|
|
|
164
178
|
function releaseInfo(tag) {
|
|
165
|
-
const
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
)
|
|
176
|
-
|
|
177
|
-
|
|
179
|
+
const args = ["api", githubReleaseByTagEndpoint(tag)];
|
|
180
|
+
const result = runNetwork(gh, args, { capture: true, allowFailure: true });
|
|
181
|
+
if (result.status !== 0 || result.error) {
|
|
182
|
+
const detail = `${result.stdout ?? ""}${result.stderr ?? ""}${result.error?.message ?? ""}`.trim();
|
|
183
|
+
if (/\bHTTP 404\b|\bstatus 404\b|\b404 Not Found\b/i.test(detail)) return null;
|
|
184
|
+
throw commandResultError(gh, args, result);
|
|
185
|
+
}
|
|
186
|
+
let value;
|
|
187
|
+
try { value = JSON.parse(result.stdout); }
|
|
188
|
+
catch { throw new Error(`GitHub REST release query returned invalid JSON for ${tag}`); }
|
|
189
|
+
if (value?.tag_name !== tag || typeof value.draft !== "boolean" || typeof value.prerelease !== "boolean") {
|
|
190
|
+
throw new Error(`GitHub REST release metadata is invalid for ${tag}`);
|
|
191
|
+
}
|
|
192
|
+
return {
|
|
193
|
+
tagName: value.tag_name,
|
|
194
|
+
name: String(value.name || ""),
|
|
195
|
+
targetCommitish: String(value.target_commitish || ""),
|
|
196
|
+
isDraft: value.draft,
|
|
197
|
+
isPrerelease: value.prerelease,
|
|
198
|
+
assets: Array.isArray(value.assets) ? value.assets : [],
|
|
199
|
+
url: String(value.html_url || ""),
|
|
200
|
+
};
|
|
178
201
|
}
|
|
179
202
|
|
|
180
|
-
function assertCoreSync({ requireReleaseAsset }) {
|
|
203
|
+
async function assertCoreSync({ requireReleaseAsset }) {
|
|
181
204
|
const pkg = packageMetadata();
|
|
182
|
-
|
|
205
|
+
const parsedVersion = parseReleaseVersion(pkg.version);
|
|
206
|
+
const acceptance = assertLocalAcceptance();
|
|
207
|
+
if (requiresSoakForStable(pkg.version)) assertStableSoak();
|
|
183
208
|
const tag = `v${pkg.version}`;
|
|
184
|
-
const head = output(
|
|
185
|
-
const originMain = output(
|
|
209
|
+
const head = output(git, ["rev-parse", "HEAD"]);
|
|
210
|
+
const originMain = output(git, ["rev-parse", "origin/main"]);
|
|
186
211
|
if (head !== originMain) {
|
|
187
212
|
fail(`HEAD ${head} does not match origin/main ${originMain}`);
|
|
188
213
|
}
|
|
@@ -196,17 +221,11 @@ function assertCoreSync({ requireReleaseAsset }) {
|
|
|
196
221
|
const remoteTagError = tagSyncError({ scope: "remote", tag, head, commit: remoteCommit });
|
|
197
222
|
if (remoteTagError) fail(remoteTagError);
|
|
198
223
|
|
|
199
|
-
|
|
200
|
-
if (!release || release.isDraft || release.isPrerelease) {
|
|
201
|
-
fail(`published GitHub Release ${tag} is missing or not final`);
|
|
202
|
-
}
|
|
224
|
+
await waitForPublishedReleaseState(tag, parsedVersion.prerelease);
|
|
203
225
|
|
|
204
226
|
if (requireReleaseAsset) {
|
|
205
227
|
const expectedAsset = `${pkg.name}-${pkg.version}.tgz`;
|
|
206
|
-
|
|
207
|
-
if (!names.has(expectedAsset)) {
|
|
208
|
-
fail(`GitHub Release ${tag} is missing ${expectedAsset}`);
|
|
209
|
-
}
|
|
228
|
+
await releaseAssetInfo(tag, expectedAsset, acceptance.artifactSha256);
|
|
210
229
|
}
|
|
211
230
|
|
|
212
231
|
console.log(`GitHub source, tag, release, and package asset are in sync: ${tag}`);
|
|
@@ -220,41 +239,20 @@ function writeNotesFile(directory, version) {
|
|
|
220
239
|
return path;
|
|
221
240
|
}
|
|
222
241
|
|
|
223
|
-
function
|
|
224
|
-
|
|
225
|
-
"
|
|
226
|
-
|
|
227
|
-
{
|
|
228
|
-
);
|
|
229
|
-
let records;
|
|
230
|
-
try {
|
|
231
|
-
records = JSON.parse(result.stdout);
|
|
232
|
-
} catch {
|
|
233
|
-
fail("npm pack did not return valid JSON");
|
|
234
|
-
}
|
|
235
|
-
const record = normalizePackRecord(records, pkg.name);
|
|
236
|
-
const filename = record?.filename;
|
|
237
|
-
if (typeof filename !== "string") fail("npm pack did not report a filename");
|
|
238
|
-
const path = join(directory, filename);
|
|
239
|
-
const expected = `${pkg.name.replaceAll("/", "-").replace(/^@/, "")}-${pkg.version}.tgz`;
|
|
240
|
-
if (filename !== expected) {
|
|
241
|
-
fail(`unexpected npm package filename ${filename}; expected ${expected}`);
|
|
242
|
-
}
|
|
243
|
-
return path;
|
|
244
|
-
}
|
|
245
|
-
|
|
246
|
-
function normalizePackRecord(value, packageName) {
|
|
247
|
-
if (Array.isArray(value)) return value[0] ?? null;
|
|
248
|
-
if (!value || typeof value !== "object") return null;
|
|
249
|
-
if (value[packageName] && typeof value[packageName] === "object") return value[packageName];
|
|
250
|
-
return Object.values(value).find((item) => item && typeof item === "object") ?? null;
|
|
242
|
+
async function releaseAssetInfo(tag, assetName, expectedSha256) {
|
|
243
|
+
return waitForGithubReleaseAsset(() => {
|
|
244
|
+
const text = outputNetwork(gh, ["api", githubReleaseByTagEndpoint(tag)]);
|
|
245
|
+
try { return JSON.parse(text); }
|
|
246
|
+
catch { throw new Error(`GitHub REST release query returned invalid JSON for ${tag}`); }
|
|
247
|
+
}, { tag, assetName, expectedSha256 });
|
|
251
248
|
}
|
|
252
249
|
|
|
253
|
-
function ensureRelease(tag, version, assetPath, latest) {
|
|
250
|
+
function ensureRelease(tag, version, assetPath, { latest, prerelease }) {
|
|
254
251
|
const temp = dirname(assetPath);
|
|
255
252
|
const notes = writeNotesFile(temp, version);
|
|
256
253
|
const existing = releaseInfo(tag);
|
|
257
254
|
const title = `machine-bridge-mcp ${tag}`;
|
|
255
|
+
const failures = [];
|
|
258
256
|
|
|
259
257
|
if (!existing) {
|
|
260
258
|
const args = [
|
|
@@ -266,97 +264,186 @@ function ensureRelease(tag, version, assetPath, latest) {
|
|
|
266
264
|
"--title",
|
|
267
265
|
title,
|
|
268
266
|
latest ? "--latest" : "--latest=false",
|
|
267
|
+
prerelease ? "--prerelease" : "--prerelease=false",
|
|
269
268
|
];
|
|
270
269
|
if (notes) args.push("--notes-file", notes);
|
|
271
270
|
else args.push("--generate-notes");
|
|
272
|
-
const created = runNetwork(
|
|
273
|
-
if (created.status !== 0
|
|
271
|
+
const created = runNetwork(gh, args, { allowFailure: true });
|
|
272
|
+
if (created.status !== 0) failures.push(commandResultError(gh, args, created));
|
|
274
273
|
} else {
|
|
275
|
-
|
|
276
|
-
"release",
|
|
277
|
-
"edit",
|
|
278
|
-
tag,
|
|
279
|
-
"--title",
|
|
280
|
-
title,
|
|
274
|
+
const editArgs = [
|
|
275
|
+
"release", "edit", tag, "--title", title,
|
|
281
276
|
latest ? "--latest" : "--latest=false",
|
|
277
|
+
prerelease ? "--prerelease" : "--prerelease=false",
|
|
282
278
|
...(notes ? ["--notes-file", notes] : []),
|
|
283
|
-
]
|
|
284
|
-
runNetwork(
|
|
279
|
+
];
|
|
280
|
+
const edited = runNetwork(gh, editArgs, { allowFailure: true });
|
|
281
|
+
if (edited.status !== 0) failures.push(commandResultError(gh, editArgs, edited));
|
|
282
|
+
const uploadArgs = ["release", "upload", tag, assetPath, "--clobber"];
|
|
283
|
+
const uploaded = runNetwork(gh, uploadArgs, { allowFailure: true });
|
|
284
|
+
if (uploaded.status !== 0) failures.push(commandResultError(gh, uploadArgs, uploaded));
|
|
285
285
|
}
|
|
286
|
+
if (!failures.length) return null;
|
|
287
|
+
return failures.length === 1
|
|
288
|
+
? failures[0]
|
|
289
|
+
: new AggregateError(failures, "GitHub release mutation commands returned multiple errors");
|
|
286
290
|
}
|
|
287
291
|
|
|
288
|
-
function
|
|
292
|
+
function commandResultError(command, args, result) {
|
|
293
|
+
return new Error(releaseCommandFailure(command, args, result, { maxChars: 1200 }));
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
async function waitForPublishedReleaseState(tag, prerelease, options = {}) {
|
|
297
|
+
const attempts = Number.isSafeInteger(Number(options.attempts))
|
|
298
|
+
? Math.min(Math.max(Number(options.attempts), 1), 10)
|
|
299
|
+
: 5;
|
|
300
|
+
const wait = typeof options.wait === "function" ? options.wait : defaultReleaseStateWait;
|
|
301
|
+
let release = null;
|
|
302
|
+
for (let attempt = 1; attempt <= attempts; attempt += 1) {
|
|
303
|
+
release = releaseInfo(tag);
|
|
304
|
+
if (release && !release.isDraft && release.isPrerelease === prerelease) return release;
|
|
305
|
+
if (attempt < attempts) await wait(attempt);
|
|
306
|
+
}
|
|
307
|
+
throw new Error(`GitHub release ${tag} metadata did not converge after publication`);
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
function defaultReleaseStateWait(attempt) {
|
|
311
|
+
return new Promise((resolvePromise) => { setTimeout(resolvePromise, Math.min(4_000, attempt * 1_000)); });
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
async function publishCurrent({ prereleaseMode = false } = {}) {
|
|
289
315
|
ensureClean();
|
|
290
316
|
fetchRemote();
|
|
291
317
|
|
|
292
|
-
const branch = output(
|
|
318
|
+
const branch = output(git, ["branch", "--show-current"]);
|
|
293
319
|
if (branch !== "main") fail(`release must run from main, not ${branch || "detached HEAD"}`);
|
|
294
320
|
|
|
295
321
|
const pkg = packageMetadata();
|
|
322
|
+
const parsedVersion = parseReleaseVersion(pkg.version);
|
|
323
|
+
if (prereleaseMode !== parsedVersion.prerelease) {
|
|
324
|
+
fail(parsedVersion.prerelease
|
|
325
|
+
? "prerelease versions must use npm run prerelease:release -- --owner-confirm"
|
|
326
|
+
: "stable versions must use npm run release -- --owner-confirm");
|
|
327
|
+
}
|
|
296
328
|
const tag = `v${pkg.version}`;
|
|
297
329
|
if (!changelogBody(pkg.version)) {
|
|
298
330
|
fail(`CHANGELOG.md has no section for ${pkg.version}`);
|
|
299
331
|
}
|
|
300
332
|
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
333
|
+
const npmSession = await createHardenedNpmSession();
|
|
334
|
+
let acceptance;
|
|
335
|
+
let verificationError = null;
|
|
336
|
+
try {
|
|
337
|
+
runNpmScript(npmSession.cli, "check");
|
|
338
|
+
runNpmScript(npmSession.cli, "version:check");
|
|
339
|
+
ensureClean();
|
|
340
|
+
acceptance = assertLocalAcceptance(npmSession.cli);
|
|
341
|
+
if (!parsedVersion.prerelease && requiresSoakForStable(pkg.version)) assertStableSoak(npmSession.cli);
|
|
342
|
+
} catch (error) {
|
|
343
|
+
verificationError = error;
|
|
344
|
+
}
|
|
345
|
+
let npmCleanupError = null;
|
|
346
|
+
try { npmSession.dispose(); } catch (error) { npmCleanupError = error; }
|
|
347
|
+
if (verificationError && npmCleanupError) {
|
|
348
|
+
throw new AggregateError([verificationError, npmCleanupError], "GitHub release verification failed and hardened npm cleanup was incomplete");
|
|
349
|
+
}
|
|
350
|
+
if (verificationError) throw verificationError;
|
|
351
|
+
if (npmCleanupError) throw npmCleanupError;
|
|
305
352
|
|
|
306
|
-
const head = output(
|
|
307
|
-
const originMain = output(
|
|
353
|
+
const head = output(git, ["rev-parse", "HEAD"]);
|
|
354
|
+
const originMain = output(git, ["rev-parse", "origin/main"]);
|
|
308
355
|
if (head !== originMain) {
|
|
309
356
|
fail("HEAD does not match origin/main; local acceptance must be committed, pushed through npm run github:push, reviewed, and merged before release publication");
|
|
310
357
|
}
|
|
311
358
|
assertSuccessfulCi(head);
|
|
312
359
|
|
|
313
|
-
const
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
360
|
+
const candidate = stageAcceptedCandidateTarball(root, acceptance);
|
|
361
|
+
let primaryError = null;
|
|
362
|
+
let releaseVerified = false;
|
|
363
|
+
try {
|
|
364
|
+
const existingLocal = localTagCommit(tag);
|
|
365
|
+
if (existingLocal && existingLocal !== head) {
|
|
366
|
+
fail(`local ${tag} points to ${existingLocal}, not ${head}`);
|
|
367
|
+
}
|
|
368
|
+
if (!existingLocal) {
|
|
369
|
+
run(git, ["tag", "-a", tag, "-m", `Release ${pkg.version}`]);
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
const existingRemote = remoteTagCommit(tag);
|
|
373
|
+
if (existingRemote && existingRemote !== head) {
|
|
374
|
+
fail(`remote ${tag} points to ${existingRemote}, not ${head}`);
|
|
375
|
+
}
|
|
376
|
+
if (!existingRemote) {
|
|
377
|
+
runNetwork(git, ["push", "origin", tag]);
|
|
378
|
+
}
|
|
320
379
|
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
380
|
+
const mutationError = ensureRelease(tag, pkg.version, candidate.path, {
|
|
381
|
+
latest: !parsedVersion.prerelease,
|
|
382
|
+
prerelease: parsedVersion.prerelease,
|
|
383
|
+
});
|
|
384
|
+
let assetError = null;
|
|
385
|
+
try {
|
|
386
|
+
await releaseAssetInfo(tag, acceptance.metadata.filename, acceptance.artifactSha256);
|
|
387
|
+
await waitForPublishedReleaseState(tag, parsedVersion.prerelease);
|
|
388
|
+
} catch (error) {
|
|
389
|
+
assetError = error;
|
|
390
|
+
}
|
|
391
|
+
if (mutationError && assetError) {
|
|
392
|
+
throw new AggregateError([mutationError, assetError], "GitHub release mutation and remote-state reconciliation both failed");
|
|
393
|
+
}
|
|
394
|
+
if (assetError) throw assetError;
|
|
395
|
+
if (mutationError) {
|
|
396
|
+
console.warn("GitHub release mutation returned an error, but the exact release metadata and accepted asset bytes were verified remotely");
|
|
397
|
+
}
|
|
398
|
+
releaseVerified = true;
|
|
399
|
+
} catch (error) {
|
|
400
|
+
primaryError = error;
|
|
324
401
|
}
|
|
325
|
-
|
|
326
|
-
|
|
402
|
+
let cleanupError = null;
|
|
403
|
+
try { candidate.dispose(); } catch (error) { cleanupError = error; }
|
|
404
|
+
if (primaryError) {
|
|
405
|
+
if (cleanupError) throw new AggregateError([primaryError, cleanupError], "GitHub release publication failed and candidate staging cleanup was incomplete");
|
|
406
|
+
throw primaryError;
|
|
327
407
|
}
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
const assetPath = packReleaseAsset(temp, pkg);
|
|
332
|
-
ensureRelease(tag, pkg.version, assetPath, true);
|
|
333
|
-
} finally {
|
|
334
|
-
rmSync(temp, { recursive: true, force: true });
|
|
408
|
+
if (cleanupError) {
|
|
409
|
+
if (!releaseVerified) throw cleanupError;
|
|
410
|
+
console.warn(`GitHub release bytes were verified but candidate staging cleanup was incomplete: ${releaseDiagnostic(cleanupError?.message || cleanupError, 600)}`);
|
|
335
411
|
}
|
|
336
412
|
|
|
337
413
|
fetchRemote();
|
|
338
|
-
assertCoreSync({ requireReleaseAsset: true });
|
|
414
|
+
await assertCoreSync({ requireReleaseAsset: true });
|
|
339
415
|
}
|
|
340
416
|
|
|
341
|
-
function
|
|
417
|
+
function assertStableSoak(npmCli = process.env.npm_execpath) {
|
|
342
418
|
try {
|
|
343
|
-
const result =
|
|
419
|
+
const result = verifyCurrentStableSoak(root, { npmCli });
|
|
344
420
|
if (result.required) {
|
|
345
|
-
console.log(`
|
|
421
|
+
console.log(`Stable promotion matches soaked ${result.record.prerelease_version} (${result.promotionDigest}).`);
|
|
346
422
|
}
|
|
347
423
|
} catch (error) {
|
|
348
424
|
fail(String(error?.message || error));
|
|
349
425
|
}
|
|
350
426
|
}
|
|
351
427
|
|
|
428
|
+
function assertLocalAcceptance(npmCli = process.env.npm_execpath) {
|
|
429
|
+
try {
|
|
430
|
+
const result = verifyCurrentReleaseAcceptance(root, { npmCli });
|
|
431
|
+
if (!result.required) fail("GitHub release publication requires current local candidate acceptance");
|
|
432
|
+
console.log(`Local candidate acceptance matches ${result.metadata.filename} (${result.metadata.shasum}).`);
|
|
433
|
+
return result;
|
|
434
|
+
} catch (error) {
|
|
435
|
+
fail(String(error?.message || error));
|
|
436
|
+
}
|
|
437
|
+
}
|
|
438
|
+
|
|
352
439
|
function backfillMissingReleases() {
|
|
353
440
|
ensureClean();
|
|
354
441
|
fetchRemote();
|
|
355
442
|
|
|
356
|
-
const tags = output(
|
|
443
|
+
const tags = output(git, ["tag", "--sort=version:refname"])
|
|
357
444
|
.split("\n")
|
|
358
445
|
.filter((tag) => /^v\d+\.\d+\.\d+$/.test(tag));
|
|
359
|
-
const releases = JSON.parse(outputNetwork(
|
|
446
|
+
const releases = JSON.parse(outputNetwork(gh, [
|
|
360
447
|
"release",
|
|
361
448
|
"list",
|
|
362
449
|
"--limit",
|
|
@@ -373,6 +460,8 @@ function backfillMissingReleases() {
|
|
|
373
460
|
}
|
|
374
461
|
|
|
375
462
|
const temp = mkdtempSync(join(tmpdir(), "machine-bridge-mcp-backfill-"));
|
|
463
|
+
let primaryError = null;
|
|
464
|
+
let completed = 0;
|
|
376
465
|
try {
|
|
377
466
|
for (const tag of missing) {
|
|
378
467
|
if (!remoteTagCommit(tag)) fail(`remote tag ${tag} is missing`);
|
|
@@ -389,25 +478,45 @@ function backfillMissingReleases() {
|
|
|
389
478
|
];
|
|
390
479
|
if (notes) args.push("--notes-file", notes);
|
|
391
480
|
else args.push("--generate-notes");
|
|
392
|
-
const created = runNetwork(
|
|
393
|
-
if (created.status !== 0 && !releaseInfo(tag)) failCommandResult(
|
|
481
|
+
const created = runNetwork(gh, args, { allowFailure: true });
|
|
482
|
+
if (created.status !== 0 && !releaseInfo(tag)) failCommandResult(gh, args, created);
|
|
483
|
+
completed += 1;
|
|
394
484
|
}
|
|
395
|
-
}
|
|
396
|
-
|
|
485
|
+
} catch (error) {
|
|
486
|
+
primaryError = error;
|
|
487
|
+
}
|
|
488
|
+
let cleanupError = null;
|
|
489
|
+
try { rmSync(temp, { recursive: true, force: true, maxRetries: 3, retryDelay: 50 }); }
|
|
490
|
+
catch (error) { cleanupError = error; }
|
|
491
|
+
if (primaryError) {
|
|
492
|
+
if (cleanupError) throw new AggregateError([primaryError, cleanupError], "GitHub Release backfill failed and temporary cleanup was incomplete");
|
|
493
|
+
throw primaryError;
|
|
494
|
+
}
|
|
495
|
+
if (cleanupError) {
|
|
496
|
+
if (!completed) throw cleanupError;
|
|
497
|
+
console.warn(`GitHub Release backfill completed but temporary cleanup was incomplete: ${releaseDiagnostic(cleanupError?.message || cleanupError, 600)}`);
|
|
397
498
|
}
|
|
398
499
|
|
|
399
500
|
console.log(`Backfilled ${missing.length} GitHub Release(s): ${missing.join(", ")}`);
|
|
400
501
|
}
|
|
401
502
|
|
|
402
503
|
const mode = process.argv[2] ?? "--check";
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
504
|
+
try {
|
|
505
|
+
if (mode === "--check") {
|
|
506
|
+
ensureClean();
|
|
507
|
+
fetchRemote();
|
|
508
|
+
await assertCoreSync({ requireReleaseAsset: true });
|
|
509
|
+
} else if (mode === "--publish" || mode === "--publish-prerelease" || mode === "--backfill") {
|
|
510
|
+
assertGithubPublicationAuthorized();
|
|
511
|
+
await withGithubPublicationLock(root, async () => {
|
|
512
|
+
if (mode === "--publish") await publishCurrent({ prereleaseMode: false });
|
|
513
|
+
else if (mode === "--publish-prerelease") await publishCurrent({ prereleaseMode: true });
|
|
514
|
+
else backfillMissingReleases();
|
|
515
|
+
});
|
|
516
|
+
} else {
|
|
517
|
+
fail("usage: node scripts/github-release.mjs [--check|--publish|--publish-prerelease|--backfill] [--owner-confirm]");
|
|
518
|
+
}
|
|
519
|
+
} catch (error) {
|
|
520
|
+
console.error(JSON.stringify(releaseDiagnosticEvent("github.release.failed", error?.message || error, 1600)));
|
|
521
|
+
process.exitCode = 1;
|
|
413
522
|
}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { lstatSync, realpathSync } from "node:fs";
|
|
2
|
+
import { isAbsolute, join, relative, resolve, sep } from "node:path";
|
|
3
|
+
import { readBoundedRegularFileSync } from "../src/local/secure-file.mjs";
|
|
4
|
+
|
|
5
|
+
const MAX_PACKAGE_MANIFEST_BYTES = 2 * 1024 * 1024;
|
|
6
|
+
|
|
7
|
+
export function inspectGlobalPackageInstallation(globalRoot, packageName) {
|
|
8
|
+
const rootInput = String(globalRoot || "").trim();
|
|
9
|
+
const name = String(packageName || "");
|
|
10
|
+
if (!rootInput || !isAbsolute(rootInput) || !name || name.includes("/") || name.includes("\\") || name.includes("\0")) {
|
|
11
|
+
throw new TypeError("global package inspection requires a valid package name and absolute root");
|
|
12
|
+
}
|
|
13
|
+
let root;
|
|
14
|
+
try { root = realpathSync(resolve(rootInput)); }
|
|
15
|
+
catch (error) {
|
|
16
|
+
if (error?.code === "ENOENT") return null;
|
|
17
|
+
throw error;
|
|
18
|
+
}
|
|
19
|
+
const packageRoot = join(root, name);
|
|
20
|
+
let packageInfo;
|
|
21
|
+
try { packageInfo = lstatSync(packageRoot); }
|
|
22
|
+
catch (error) {
|
|
23
|
+
if (error?.code === "ENOENT") return null;
|
|
24
|
+
throw error;
|
|
25
|
+
}
|
|
26
|
+
if (packageInfo.isSymbolicLink() || !packageInfo.isDirectory()) {
|
|
27
|
+
throw new Error("globally installed package root must be a real directory");
|
|
28
|
+
}
|
|
29
|
+
const canonicalPackageRoot = realpathSync(packageRoot);
|
|
30
|
+
const packageRelative = relative(root, canonicalPackageRoot);
|
|
31
|
+
if (!packageRelative || packageRelative.startsWith(`..${sep}`) || packageRelative === ".." || isAbsolute(packageRelative)) {
|
|
32
|
+
throw new Error("globally installed package root escapes the npm global root");
|
|
33
|
+
}
|
|
34
|
+
const packagePath = join(canonicalPackageRoot, "package.json");
|
|
35
|
+
let bytes;
|
|
36
|
+
try {
|
|
37
|
+
bytes = readBoundedRegularFileSync(packagePath, MAX_PACKAGE_MANIFEST_BYTES, "globally installed package manifest", {
|
|
38
|
+
verifyPathIdentity: true,
|
|
39
|
+
rejectMultipleLinks: true,
|
|
40
|
+
});
|
|
41
|
+
} catch (error) {
|
|
42
|
+
if (error?.code === "ENOENT") throw new Error("globally installed package manifest is missing", { cause: error });
|
|
43
|
+
throw error;
|
|
44
|
+
}
|
|
45
|
+
let value;
|
|
46
|
+
try { value = JSON.parse(bytes.toString("utf8")); }
|
|
47
|
+
catch { throw new Error("globally installed package manifest is not valid JSON"); }
|
|
48
|
+
const version = String(value?.version || "");
|
|
49
|
+
if (value?.name !== name || !/^\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?(?:\+[0-9A-Za-z.-]+)?$/.test(version)) {
|
|
50
|
+
throw new Error("globally installed package identity is invalid");
|
|
51
|
+
}
|
|
52
|
+
const entry = join(canonicalPackageRoot, "bin", "machine-mcp.mjs");
|
|
53
|
+
let info;
|
|
54
|
+
try { info = lstatSync(entry); }
|
|
55
|
+
catch (error) {
|
|
56
|
+
if (error?.code === "ENOENT") throw new Error("globally installed package CLI is missing", { cause: error });
|
|
57
|
+
throw error;
|
|
58
|
+
}
|
|
59
|
+
if (info.isSymbolicLink() || !info.isFile() || Number(info.nlink) !== 1 || (process.platform !== "win32" && (Number(info.mode) & 0o022) !== 0)) {
|
|
60
|
+
throw new Error("globally installed package CLI must be a private regular file");
|
|
61
|
+
}
|
|
62
|
+
const canonicalEntry = realpathSync(entry);
|
|
63
|
+
const entryRelative = relative(canonicalPackageRoot, canonicalEntry);
|
|
64
|
+
if (!entryRelative || entryRelative.startsWith(`..${sep}`) || entryRelative === ".." || isAbsolute(entryRelative)) {
|
|
65
|
+
throw new Error("globally installed package CLI escapes the package root");
|
|
66
|
+
}
|
|
67
|
+
return Object.freeze({ version, entry: canonicalEntry });
|
|
68
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { mkdtempSync, rmSync } from "node:fs";
|
|
2
|
+
import { tmpdir } from "node:os";
|
|
3
|
+
import { join, resolve } from "node:path";
|
|
4
|
+
import { prepareHardenedNpm } from "../src/local/hardened-npm.mjs";
|
|
5
|
+
|
|
6
|
+
export async function createHardenedNpmSession(options = {}) {
|
|
7
|
+
const parent = resolve(String(options.tempRoot || tmpdir()));
|
|
8
|
+
const root = mkdtempSync(join(parent, "mbm-hardened-npm-session-"));
|
|
9
|
+
let disposed = false;
|
|
10
|
+
try {
|
|
11
|
+
const prepared = await prepareHardenedNpm(join(root, "runtime"), options.hardenedNpm || {});
|
|
12
|
+
return Object.freeze({
|
|
13
|
+
cli: prepared.cli,
|
|
14
|
+
version: prepared.version,
|
|
15
|
+
undiciVersion: prepared.undiciVersion,
|
|
16
|
+
braceExpansionVersion: prepared.braceExpansionVersion,
|
|
17
|
+
dispose() {
|
|
18
|
+
if (disposed) return;
|
|
19
|
+
rmSync(root, { recursive: true, force: true, maxRetries: 3, retryDelay: 50 });
|
|
20
|
+
disposed = true;
|
|
21
|
+
},
|
|
22
|
+
});
|
|
23
|
+
} catch (error) {
|
|
24
|
+
try { rmSync(root, { recursive: true, force: true, maxRetries: 3, retryDelay: 50 }); }
|
|
25
|
+
catch (cleanupError) { throw new AggregateError([error, cleanupError], "hardened npm session preparation failed and temporary cleanup was incomplete"); }
|
|
26
|
+
throw error;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export function settleHardenedNpmSession(
|
|
31
|
+
session,
|
|
32
|
+
primaryError = null,
|
|
33
|
+
aggregateMessage = "hardened npm session failed and temporary cleanup was incomplete",
|
|
34
|
+
) {
|
|
35
|
+
try { session?.dispose(); }
|
|
36
|
+
catch (cleanupError) {
|
|
37
|
+
return primaryError
|
|
38
|
+
? new AggregateError([primaryError, cleanupError], aggregateMessage)
|
|
39
|
+
: cleanupError;
|
|
40
|
+
}
|
|
41
|
+
return primaryError;
|
|
42
|
+
}
|