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
package/src/local/cli.mjs
CHANGED
|
@@ -1,31 +1,38 @@
|
|
|
1
|
-
import { readFileSync } from "node:fs";
|
|
2
1
|
import { join, resolve } from "node:path";
|
|
3
2
|
import process from "node:process";
|
|
4
3
|
import readline from "node:readline/promises";
|
|
5
4
|
import { LocalRuntime } from "./runtime.mjs";
|
|
6
|
-
import { acquireDaemonLockWithTakeover, stopWorkspaceServiceDaemon } from "./daemon-process.mjs";
|
|
5
|
+
import { acquireDaemonLockWithTakeover, inspectWorkspaceDaemon, stopWorkspaceServiceDaemon, workspaceDaemonOwnsPlatformAutostart } from "./daemon-process.mjs";
|
|
7
6
|
import { inspectProcessInstance } from "./process-identity.mjs";
|
|
8
7
|
import { runStdioServer } from "./stdio.mjs";
|
|
9
8
|
import { assertCanonicalFullPolicy, POLICY_PROFILES, toolsForPolicy } from "./tools.mjs";
|
|
10
9
|
import { resolvePolicy } from "./cli-policy.mjs";
|
|
11
10
|
import { effectiveLogFormat, effectiveLogLevel, normalizeCommand, parseArgs, validateCommandOptions, validateLoggingOptions, validatePositionals } from "./cli-options.mjs";
|
|
12
11
|
import { createLocalAdminCommands } from "./cli-local-admin.mjs";
|
|
13
|
-
import { createApprovalCommand } from "./cli-approval.mjs";
|
|
14
12
|
import { createServiceCommand } from "./cli-service.mjs";
|
|
13
|
+
import { createActivateCommand } from "./cli-activate.mjs";
|
|
15
14
|
import { generateAccountPassword } from "./account-admin.mjs";
|
|
16
15
|
import { accountAdminClient, createAccountCommand } from "./cli-account-admin.mjs";
|
|
17
16
|
export { resolvePolicy } from "./cli-policy.mjs";
|
|
18
17
|
export { parseArgs, validateCommandOptions, validateLoggingOptions, validatePositionals } from "./cli-options.mjs";
|
|
19
18
|
import { classifyOperationalError, createLogger, sanitizeLogText } from "./log.mjs";
|
|
19
|
+
import { formatPolicySummary, printMcpConnection, printStartJson } from "./cli-ready-output.mjs";
|
|
20
20
|
import { runExecutable, runWrangler } from "./shell.mjs";
|
|
21
21
|
import { runFullAccessTest } from "./full-access-test.mjs";
|
|
22
22
|
import { stopAndRemoveAutostart } from "./service-lifecycle.mjs";
|
|
23
|
+
import { stopOwnedPlatformService } from "./service-ownership.mjs";
|
|
23
24
|
import { loadServiceEnvironment } from "./service-environment.mjs";
|
|
24
|
-
import {
|
|
25
|
+
import { createDeviceSessionForRoot, deviceRootProviderStatus, ensurePreferredDeviceRoot } from "./device-root-provider.mjs";
|
|
26
|
+
import { convergeRemoteConfiguration } from "./remote-configuration.mjs";
|
|
25
27
|
import { workerHealth } from "./worker-health.mjs";
|
|
28
|
+
import { DOCTOR_RUNTIME_SCOPE, doctorRuntimeCheckProjection } from "./doctor-reporting.mjs";
|
|
29
|
+
import { supportStateProjection } from "./support-state-projection.mjs";
|
|
26
30
|
export { workerHealthUserReason } from "./worker-health.mjs";
|
|
27
31
|
import { activeStateJobs, activeStateLocks, knownProfileStates, knownWorkerNames } from "./state-inventory.mjs";
|
|
32
|
+
import { pruneRetiredManagedJobDirectories } from "./managed-job-directory-generation.mjs";
|
|
33
|
+
import { withReleaseRuntimeLock } from "./release-runtime-lock.mjs";
|
|
28
34
|
import {
|
|
35
|
+
acquireMachineServiceLockWithWait,
|
|
29
36
|
acquireMaintenanceLock,
|
|
30
37
|
acquireStartupLockWithWait,
|
|
31
38
|
daemonLockPathForState,
|
|
@@ -36,7 +43,6 @@ import {
|
|
|
36
43
|
expandHome,
|
|
37
44
|
loadGlobalConfig,
|
|
38
45
|
loadState,
|
|
39
|
-
packageRoot,
|
|
40
46
|
readDaemonLockOwner,
|
|
41
47
|
redactState,
|
|
42
48
|
removeStateRoot,
|
|
@@ -47,14 +53,23 @@ import {
|
|
|
47
53
|
selectedWorkspace,
|
|
48
54
|
setSelectedWorkspace,
|
|
49
55
|
} from "./state.mjs";
|
|
56
|
+
import { packageName, packageVersion } from "./package-identity.mjs";
|
|
50
57
|
|
|
51
58
|
const localAdminCommands = createLocalAdminCommands({ chooseWorkspace, confirm });
|
|
52
59
|
const accountCommand = createAccountCommand({ chooseWorkspace, confirm });
|
|
53
|
-
const
|
|
54
|
-
const
|
|
60
|
+
const serviceCommand = createServiceCommand({ chooseWorkspace, stateRootFromArgs, structuredLogger, acquireMachineServiceLockWithWait, currentPackageVersion });
|
|
61
|
+
const activateCommand = createActivateCommand({
|
|
62
|
+
chooseWorkspace,
|
|
63
|
+
prepareRemoteState,
|
|
64
|
+
createRemoteRuntime,
|
|
65
|
+
currentPackageVersion,
|
|
66
|
+
assertNodeVersion,
|
|
67
|
+
structuredLogger,
|
|
68
|
+
});
|
|
55
69
|
|
|
56
70
|
const COMMAND_HANDLERS = new Map([
|
|
57
71
|
["start", startCommand],
|
|
72
|
+
["activate", activateCommand],
|
|
58
73
|
["stdio", stdioCommand],
|
|
59
74
|
["client-config", clientConfigCommand],
|
|
60
75
|
["status", statusCommand],
|
|
@@ -66,7 +81,6 @@ const COMMAND_HANDLERS = new Map([
|
|
|
66
81
|
["rotate-secrets", rotateSecretsCommand],
|
|
67
82
|
["resource", localAdminCommands.resourceCommand],
|
|
68
83
|
["account", accountCommand],
|
|
69
|
-
["approval", approvalCommand],
|
|
70
84
|
["browser", localAdminCommands.browserCommand],
|
|
71
85
|
["job", localAdminCommands.jobCommand],
|
|
72
86
|
["uninstall", uninstallCommand],
|
|
@@ -173,14 +187,18 @@ async function startCommand(args) {
|
|
|
173
187
|
assertNodeVersion();
|
|
174
188
|
const logger = createLogger({ level: args.json ? "error" : effectiveLogLevel(args), format: effectiveLogFormat(args), component: "cli" });
|
|
175
189
|
const workspace = await chooseWorkspace(args, { promptOnFirstRun: true, save: true, allowPositional: true });
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
logger.debug?.("Loaded persisted service network environment", { keys: serviceEnvironment.keys });
|
|
180
|
-
}
|
|
181
|
-
const startupLock = await acquireStartupLockWithWait(state, { operation: "start", logger });
|
|
190
|
+
let state = loadState(workspace, { stateDir: args.stateDir });
|
|
191
|
+
let startupLock = null;
|
|
192
|
+
let serviceLock = null;
|
|
182
193
|
|
|
183
194
|
try {
|
|
195
|
+
serviceLock = await acquireRuntimeStartServiceLock(args, acquireMachineServiceLockWithWait, logger);
|
|
196
|
+
startupLock = await acquireStartupLockWithWait(state, { operation: "start", logger });
|
|
197
|
+
state = loadState(workspace, { stateDir: args.stateDir });
|
|
198
|
+
if (args.daemonOnly) {
|
|
199
|
+
const serviceEnvironment = loadServiceEnvironment(state.paths.stateRoot);
|
|
200
|
+
logger.debug?.("Loaded persisted service network environment", { keys: serviceEnvironment.keys });
|
|
201
|
+
}
|
|
184
202
|
const startMode = await prepareStartMode(args, state, logger);
|
|
185
203
|
const daemonLock = await acquireDaemonLockWithTakeover(state, {
|
|
186
204
|
takeOverServiceOwner: startMode.takeOverServiceOwner,
|
|
@@ -194,9 +212,12 @@ async function startCommand(args) {
|
|
|
194
212
|
reportExistingDaemon(args, state, daemonLock.owner, logger);
|
|
195
213
|
return;
|
|
196
214
|
}
|
|
215
|
+
serviceLock?.release?.();
|
|
216
|
+
serviceLock = null;
|
|
197
217
|
await startRemoteRuntime({ args, workspace, state, daemonLock, logger });
|
|
198
218
|
} finally {
|
|
199
|
-
|
|
219
|
+
serviceLock?.release?.();
|
|
220
|
+
startupLock?.release?.();
|
|
200
221
|
}
|
|
201
222
|
}
|
|
202
223
|
|
|
@@ -206,22 +227,38 @@ async function prepareStartMode(args, state, logger) {
|
|
|
206
227
|
trimAutostartLogs(state.paths.stateRoot);
|
|
207
228
|
return { takeOverServiceOwner: false };
|
|
208
229
|
}
|
|
209
|
-
//
|
|
210
|
-
//
|
|
211
|
-
//
|
|
212
|
-
//
|
|
213
|
-
|
|
230
|
+
// The platform service name is machine-global, while state/workspace locks
|
|
231
|
+
// are scoped. Stop the platform service only when the daemon lock proves
|
|
232
|
+
// that the loaded service belongs to this exact state/workspace. An
|
|
233
|
+
// unrelated foreground start (including install smoke tests with isolated
|
|
234
|
+
// HOME/state) must never unload another Machine Bridge deployment.
|
|
235
|
+
const ownership = await stopOwnedPlatformService({
|
|
236
|
+
state,
|
|
237
|
+
inspectWorkspaceDaemon,
|
|
238
|
+
ownsPlatformAutostart: workspaceDaemonOwnsPlatformAutostart,
|
|
239
|
+
stopPlatformService: () => stopAutostartBestEffort(logger),
|
|
240
|
+
});
|
|
241
|
+
if (!ownership.owned) {
|
|
242
|
+
logger.debug?.("foreground startup left unrelated machine autostart untouched", {
|
|
243
|
+
workspace_daemon_present: ownership.daemon.present === true,
|
|
244
|
+
workspace_daemon_alive: ownership.daemon.alive === true,
|
|
245
|
+
identity_reason: ownership.daemon.identity_reason || "not_running",
|
|
246
|
+
});
|
|
247
|
+
return { takeOverServiceOwner: true, provider: null };
|
|
248
|
+
}
|
|
249
|
+
// Once ownership is proven, unload the provider first so KeepAlive cannot
|
|
250
|
+
// respawn the service while the verified process lock is reclaimed.
|
|
251
|
+
return ownership.provider;
|
|
214
252
|
}
|
|
215
253
|
|
|
216
254
|
function reportExistingDaemon(args, state, owner, logger) {
|
|
217
|
-
const pid = owner?.pid ? `pid ${owner.pid}` : "unknown pid";
|
|
218
255
|
if (isIdempotentDaemonOnlyStart(args)) {
|
|
219
256
|
logger.debug?.("local daemon already running; daemon-only start completed as an idempotent no-op", { owner_pid_known: Boolean(owner?.pid) });
|
|
220
257
|
return;
|
|
221
258
|
}
|
|
222
259
|
const mode = owner?.mode === "foreground" ? "foreground" : owner?.mode === "service" ? "background service" : "local";
|
|
223
260
|
const version = owner?.version ? `, version ${owner.version}` : "";
|
|
224
|
-
const notice = `${mode} daemon already running for this workspace
|
|
261
|
+
const notice = `${mode} daemon already running for this workspace${version}; it was not restarted and requested changes were not applied`;
|
|
225
262
|
logger.warn(notice);
|
|
226
263
|
if (args.json) {
|
|
227
264
|
printStartJson(state, { requestedChangesApplied: false, notice });
|
|
@@ -235,6 +272,20 @@ function reportExistingDaemon(args, state, owner, logger) {
|
|
|
235
272
|
logger.plain(` Workspace: ${state.workspace.path}`);
|
|
236
273
|
}
|
|
237
274
|
|
|
275
|
+
export function runtimeStartRequiresMachineServiceLock(args = {}) {
|
|
276
|
+
return args.daemonOnly !== true;
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
export async function acquireRuntimeStartServiceLock(args = {}, acquireLock = acquireMachineServiceLockWithWait, logger = console) {
|
|
280
|
+
if (!runtimeStartRequiresMachineServiceLock(args)) return null;
|
|
281
|
+
if (typeof acquireLock !== "function") throw new TypeError("runtime start requires a machine-service lock acquirer");
|
|
282
|
+
const lock = await acquireLock({ operation: "runtime-start", logger });
|
|
283
|
+
if (!lock?.acquired || typeof lock.release !== "function") {
|
|
284
|
+
throw new Error("machine-service operation lock could not be acquired for runtime start");
|
|
285
|
+
}
|
|
286
|
+
return lock;
|
|
287
|
+
}
|
|
288
|
+
|
|
238
289
|
export function isIdempotentDaemonOnlyStart(args) {
|
|
239
290
|
if (!args.daemonOnly || args.json) return false;
|
|
240
291
|
return !Boolean(
|
|
@@ -255,44 +306,67 @@ async function startRemoteRuntime({ args, workspace, state, daemonLock, logger }
|
|
|
255
306
|
let runtime = null;
|
|
256
307
|
try {
|
|
257
308
|
const readiness = await prepareRemoteState({ args, workspace, state, logger });
|
|
258
|
-
runtime = createRemoteRuntime({ args, workspace, state, daemonLock });
|
|
309
|
+
runtime = createRemoteRuntime({ args, workspace, state, daemonLock, deviceSessionIdentity: readiness.deviceSessionIdentity });
|
|
259
310
|
await runtime.start();
|
|
260
|
-
|
|
311
|
+
if (typeof daemonLock.update !== "function") throw new Error("daemon lock cannot publish startup readiness");
|
|
312
|
+
daemonLock.update({ startupReady: true, startupReadyAt: new Date().toISOString() });
|
|
313
|
+
reportRemoteReady(args, state, readiness, logger);
|
|
314
|
+
if (args.daemonOnly) {
|
|
315
|
+
const { startAutostartLogMaintenance } = await import("./autostart-log-maintenance.mjs");
|
|
316
|
+
startAutostartLogMaintenance(state.paths.stateRoot, {
|
|
317
|
+
onError(error) {
|
|
318
|
+
logger.event?.("warn", "service.log_maintenance.failed", {
|
|
319
|
+
error_class: classifyOperationalError(error),
|
|
320
|
+
}, "Background log maintenance failed");
|
|
321
|
+
},
|
|
322
|
+
});
|
|
323
|
+
}
|
|
261
324
|
keepProcessAlive({ daemon: runtime, lock: daemonLock, logger });
|
|
262
325
|
} catch (error) {
|
|
263
|
-
|
|
264
|
-
daemonLock.release();
|
|
265
|
-
throw error;
|
|
326
|
+
throw cleanupRuntimeStartFailure(error, runtime, daemonLock);
|
|
266
327
|
}
|
|
267
328
|
}
|
|
268
329
|
|
|
269
|
-
|
|
270
|
-
const
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
saveState(state);
|
|
330
|
+
export function cleanupRuntimeStartFailure(error, runtime, daemonLock) {
|
|
331
|
+
const cleanupErrors = [];
|
|
332
|
+
try { runtime?.stop?.(); } catch (failure) { cleanupErrors.push(failure); }
|
|
333
|
+
try { daemonLock?.release?.(); } catch (failure) { cleanupErrors.push(failure); }
|
|
334
|
+
return cleanupErrors.length
|
|
335
|
+
? new AggregateError([error, ...cleanupErrors],
|
|
336
|
+
"runtime startup failed and local cleanup was incomplete")
|
|
337
|
+
: error;
|
|
338
|
+
}
|
|
279
339
|
|
|
280
|
-
|
|
340
|
+
async function prepareRemoteState({ args, workspace, state, logger, onRemotePrepared, provisionInitialOwner = true }) {
|
|
281
341
|
if (!args.daemonOnly) {
|
|
282
|
-
await
|
|
283
|
-
|
|
342
|
+
await convergeRemoteConfiguration({ args, state });
|
|
343
|
+
onRemotePrepared?.();
|
|
284
344
|
} else if (!state.worker.url) {
|
|
285
345
|
throw new Error("--daemon-only requires an existing Worker URL; run start once without --daemon-only");
|
|
346
|
+
} else if (state.worker.pendingDeviceIdentity) {
|
|
347
|
+
throw new Error("--daemon-only cannot activate a pending device root; run a normal start once to deploy and promote it");
|
|
286
348
|
}
|
|
287
349
|
|
|
350
|
+
const deviceSessionIdentity = await createDeviceSessionForRoot(
|
|
351
|
+
state.worker.deviceIdentity,
|
|
352
|
+
state.worker.url,
|
|
353
|
+
"machine-bridge-mcp",
|
|
354
|
+
currentPackageVersion(),
|
|
355
|
+
{ profileDir: state.paths.profileDir, reason: "Authorize Machine Bridge startup" },
|
|
356
|
+
);
|
|
357
|
+
const initialOwner = args.daemonOnly || provisionInitialOwner === false
|
|
358
|
+
? null
|
|
359
|
+
: await ensureInitialOwnerAccount(state, deviceSessionIdentity);
|
|
288
360
|
if (!args.daemonOnly && !args.noAutostart) {
|
|
289
361
|
await installAutostartBestEffort({ workspace, stateRoot: state.paths.stateRoot, entryScript: process.argv[1], logger });
|
|
290
362
|
}
|
|
291
|
-
return { initialOwner };
|
|
363
|
+
return { initialOwner, deviceSessionIdentity };
|
|
292
364
|
}
|
|
293
365
|
|
|
294
|
-
|
|
295
|
-
|
|
366
|
+
|
|
367
|
+
|
|
368
|
+
async function ensureInitialOwnerAccount(state, deviceSessionIdentity) {
|
|
369
|
+
const client = await accountAdminClient(state, deviceSessionIdentity);
|
|
296
370
|
const existing = await client.list();
|
|
297
371
|
if (existing.accounts.length > 0) return null;
|
|
298
372
|
const password = generateAccountPassword();
|
|
@@ -300,31 +374,43 @@ async function ensureInitialOwnerAccount(state) {
|
|
|
300
374
|
return { ...created.account, password };
|
|
301
375
|
}
|
|
302
376
|
|
|
303
|
-
function createRemoteRuntime({ args, workspace, state, daemonLock }) {
|
|
304
|
-
|
|
377
|
+
function createRemoteRuntime({ args, workspace, state, daemonLock, deviceSessionIdentity, exitOnTerminal = true }) {
|
|
378
|
+
const terminalState = { error: null };
|
|
379
|
+
const runtime = new LocalRuntime({
|
|
305
380
|
workerUrl: state.worker.url,
|
|
306
|
-
deviceIdentity:
|
|
381
|
+
deviceIdentity: deviceSessionIdentity,
|
|
307
382
|
expectedRelayVersion: currentPackageVersion(),
|
|
308
383
|
workspace,
|
|
309
384
|
policy: state.policy,
|
|
310
385
|
logger: createLogger({ level: args.json ? "error" : effectiveLogLevel(args), format: effectiveLogFormat(args), component: "daemon" }),
|
|
311
386
|
jobRoot: join(state.paths.profileDir, "jobs"),
|
|
312
|
-
|
|
387
|
+
securityStateRoot: state.paths.profileDir,
|
|
313
388
|
resources: state.resources,
|
|
314
389
|
resourceStatePath: state.paths.statePath,
|
|
315
390
|
browserStateRoot: state.paths.stateRoot,
|
|
391
|
+
deviceRootStatus: deviceRootProviderStatus(state.worker.deviceIdentity),
|
|
316
392
|
onSuperseded: () => {
|
|
393
|
+
if (!exitOnTerminal) {
|
|
394
|
+
terminalState.error ??= new Error("candidate daemon was superseded before service handoff");
|
|
395
|
+
return;
|
|
396
|
+
}
|
|
317
397
|
daemonLock.release();
|
|
318
398
|
process.exit(0);
|
|
319
399
|
},
|
|
320
|
-
onFatal: () => {
|
|
400
|
+
onFatal: (error) => {
|
|
401
|
+
if (!exitOnTerminal) {
|
|
402
|
+
terminalState.error ??= error instanceof Error ? error : new Error("candidate relay failed before service handoff");
|
|
403
|
+
return;
|
|
404
|
+
}
|
|
321
405
|
daemonLock.release();
|
|
322
406
|
process.exit(1);
|
|
323
407
|
},
|
|
324
408
|
});
|
|
409
|
+
if (!exitOnTerminal) runtime.terminalError = () => terminalState.error;
|
|
410
|
+
return runtime;
|
|
325
411
|
}
|
|
326
412
|
|
|
327
|
-
function reportRemoteReady(args, state, readiness) {
|
|
413
|
+
function reportRemoteReady(args, state, readiness, logger) {
|
|
328
414
|
if (args.json) {
|
|
329
415
|
printStartJson(state, { initialOwner: readiness.initialOwner });
|
|
330
416
|
return;
|
|
@@ -333,6 +419,7 @@ function reportRemoteReady(args, state, readiness) {
|
|
|
333
419
|
quiet: Boolean(args.quiet),
|
|
334
420
|
verbose: Boolean(args.verbose),
|
|
335
421
|
initialOwner: readiness.initialOwner,
|
|
422
|
+
logger,
|
|
336
423
|
});
|
|
337
424
|
}
|
|
338
425
|
|
|
@@ -350,6 +437,7 @@ async function stdioCommand(args) {
|
|
|
350
437
|
resources: state.resources,
|
|
351
438
|
resourceStatePath: state.paths.statePath,
|
|
352
439
|
browserStateRoot: state.paths.stateRoot,
|
|
440
|
+
deviceRootStatus: state.worker?.deviceIdentity ? deviceRootProviderStatus(state.worker.deviceIdentity) : null,
|
|
353
441
|
});
|
|
354
442
|
}
|
|
355
443
|
|
|
@@ -378,65 +466,31 @@ async function clientConfigCommand(args) {
|
|
|
378
466
|
console.log(codex.trimEnd());
|
|
379
467
|
}
|
|
380
468
|
}
|
|
381
|
-
|
|
382
|
-
async function ensureWorker(state, args) {
|
|
383
|
-
const logger = createLogger({ level: args.json ? "error" : effectiveLogLevel(args), format: effectiveLogFormat(args), component: "worker" });
|
|
384
|
-
return ensureWorkerDeployment(state, args, { logger });
|
|
385
|
-
}
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
function printStartJson(state, { requestedChangesApplied = true, notice = "", initialOwner = null } = {}) {
|
|
389
|
-
createLogger({ component: "ready" }).json({
|
|
390
|
-
mcp: {
|
|
391
|
-
server_url: state.worker.mcpServerUrl,
|
|
392
|
-
worker_url: state.worker.url,
|
|
393
|
-
worker_name: state.worker.name,
|
|
394
|
-
},
|
|
395
|
-
...(initialOwner ? { initial_owner: initialOwner } : {}),
|
|
396
|
-
workspace: state.workspace.path,
|
|
397
|
-
state_path: state.paths.statePath,
|
|
398
|
-
policy: state.policy,
|
|
399
|
-
requested_changes_applied: requestedChangesApplied,
|
|
400
|
-
...(notice ? { notice } : {}),
|
|
401
|
-
});
|
|
402
|
-
}
|
|
403
|
-
|
|
404
|
-
function printMcpConnection(state, { quiet = false, verbose = false, initialOwner = null } = {}) {
|
|
405
|
-
const logger = createLogger({ component: "ready", quiet, level: quiet ? "error" : verbose ? "debug" : "info" });
|
|
406
|
-
logger.success("Remote MCP bridge is ready");
|
|
407
|
-
logger.plain(` MCP Server URL: ${state.worker.mcpServerUrl}`);
|
|
408
|
-
if (initialOwner) {
|
|
409
|
-
logger.warn("Initial owner account created; save the password now because it is not stored locally or shown again. Do not share this terminal output; rotate the password immediately if it has been exposed.");
|
|
410
|
-
logger.plain(` Account: ${initialOwner.name}`);
|
|
411
|
-
logger.plain(` Password: ${initialOwner.password}`);
|
|
412
|
-
} else {
|
|
413
|
-
logger.safePlain(" Use `machine-mcp account` to manage account access.");
|
|
414
|
-
}
|
|
415
|
-
logger.plain(` Workspace: ${state.workspace.path}`);
|
|
416
|
-
logger.safePlain(` Policy: ${formatPolicySummary(state.policy)}`);
|
|
417
|
-
if (verbose) logger.plain(` State: ${state.paths.statePath}`);
|
|
418
|
-
}
|
|
419
|
-
|
|
420
|
-
function formatPolicySummary(policy = {}) {
|
|
421
|
-
const scope = policy.unrestrictedPaths ? "all local paths" : "workspace only";
|
|
422
|
-
const environment = policy.minimalEnv ? "isolated env" : "full parent env";
|
|
423
|
-
return `${policy.profile || "custom"} [${policy.origin || "unknown"}; write=${policy.allowWrite ? "on" : "off"}; exec=${policy.execMode || "off"}; ${scope}; ${environment}; absolute_paths=${policy.exposeAbsolutePaths ? "on" : "off"}]`;
|
|
424
|
-
}
|
|
425
|
-
|
|
426
|
-
|
|
427
469
|
function keepProcessAlive({ daemon = null, lock = null, logger = createLogger({ component: "cli" }) } = {}) {
|
|
428
470
|
let stopping = false;
|
|
429
471
|
const stop = async () => {
|
|
430
472
|
if (stopping) return;
|
|
431
473
|
stopping = true;
|
|
432
474
|
logger.info("stopping local services");
|
|
433
|
-
try {
|
|
434
|
-
|
|
475
|
+
try {
|
|
476
|
+
await daemon?.stop?.();
|
|
477
|
+
} catch (error) {
|
|
478
|
+
stopping = false;
|
|
479
|
+
logger.error("local service shutdown is incomplete; retaining daemon ownership for a later retry", {
|
|
480
|
+
error_class: classifyOperationalError(error),
|
|
481
|
+
});
|
|
482
|
+
return;
|
|
483
|
+
}
|
|
484
|
+
try { lock?.release?.(); }
|
|
485
|
+
catch (error) { logger.warn("daemon lock release failed during final shutdown", { error_class: classifyOperationalError(error) }); }
|
|
435
486
|
process.exit(0);
|
|
436
487
|
};
|
|
437
|
-
process.
|
|
438
|
-
process.
|
|
439
|
-
process.once("exit", () =>
|
|
488
|
+
process.on("SIGINT", () => void stop());
|
|
489
|
+
process.on("SIGTERM", () => void stop());
|
|
490
|
+
process.once("exit", () => {
|
|
491
|
+
try { lock?.release?.(); }
|
|
492
|
+
catch { /* Process exit is the final ownership fallback; no in-process recovery remains possible. */ }
|
|
493
|
+
});
|
|
440
494
|
setInterval(() => {}, 2 ** 31 - 1);
|
|
441
495
|
}
|
|
442
496
|
|
|
@@ -454,19 +508,26 @@ async function statusCommand(args) {
|
|
|
454
508
|
|
|
455
509
|
async function doctorCommand(args) {
|
|
456
510
|
const workspace = await chooseWorkspace(args, { promptOnFirstRun: false, save: false, allowPositional: true });
|
|
511
|
+
const state = loadState(workspace, { stateDir: args.stateDir });
|
|
512
|
+
state.policy = resolvePolicy({}, state.policy);
|
|
457
513
|
const checks = [];
|
|
458
514
|
checks.push({ name: "node", ok: isSupportedNodeVersion(), detail: process.version });
|
|
459
515
|
const npmCommand = npmVersionCommand();
|
|
460
516
|
const npm = await runExecutable(npmCommand.file, npmCommand.args, { capture: true, allowFailure: true, timeoutMs: 10_000 });
|
|
461
517
|
const npmDetail = sanitizeLines(npm.stdout || npm.stderr);
|
|
462
518
|
checks.push({ name: "npm", ok: npm.code === 0 && isSupportedNpmVersion(npmDetail), detail: npmDetail || "unavailable" });
|
|
463
|
-
const wrangler = await runWrangler(["--version"], { capture: true, allowFailure: true });
|
|
519
|
+
const wrangler = await runWrangler(["--version"], { capture: true, allowFailure: true, stateRoot: state.paths.stateRoot });
|
|
464
520
|
checks.push({ name: "wrangler", ok: wrangler.code === 0, detail: (wrangler.stdout || wrangler.stderr).trim() });
|
|
465
|
-
const whoami = await runWrangler(["whoami"], { capture: true, allowFailure: true });
|
|
521
|
+
const whoami = await runWrangler(["whoami"], { capture: true, allowFailure: true, stateRoot: state.paths.stateRoot });
|
|
466
522
|
checks.push({ name: "cloudflare-login", ok: whoami.code === 0, detail: whoami.code === 0 ? "authenticated" : sanitizeLines(whoami.stderr || whoami.stdout) });
|
|
467
|
-
const state = loadState(workspace, { stateDir: args.stateDir });
|
|
468
|
-
state.policy = resolvePolicy({}, state.policy);
|
|
469
523
|
checks.push({ name: "policy", ok: true, detail: formatPolicySummary(state.policy) });
|
|
524
|
+
checks.push({
|
|
525
|
+
name: "authorization-model",
|
|
526
|
+
ok: true,
|
|
527
|
+
detail: state.policy.profile === "full"
|
|
528
|
+
? "local owner operations execute automatically without per-operation prompts; shell, browser, and application automation use the daemon OS user's ambient authority"
|
|
529
|
+
: "operations allowed by the selected local policy execute automatically without per-operation prompts",
|
|
530
|
+
});
|
|
470
531
|
if (state.policy.profile === "full") {
|
|
471
532
|
try {
|
|
472
533
|
assertCanonicalFullPolicy(state.policy);
|
|
@@ -476,7 +537,7 @@ async function doctorCommand(args) {
|
|
|
476
537
|
}
|
|
477
538
|
}
|
|
478
539
|
const health = state.worker?.url ? await workerHealth(state.worker.url, currentPackageVersion(), { expectedWorkerName: state.worker.name }) : { ok: false, error: "no worker url" };
|
|
479
|
-
checks.push({ name: "worker-health", ok: health.ok, detail: health.ok ?
|
|
540
|
+
checks.push({ name: "worker-health", ok: health.ok, detail: health.ok ? "reachable" : health.error });
|
|
480
541
|
const diagnosticRuntime = new LocalRuntime({
|
|
481
542
|
workspace,
|
|
482
543
|
policy: state.policy,
|
|
@@ -492,18 +553,12 @@ async function doctorCommand(args) {
|
|
|
492
553
|
} finally {
|
|
493
554
|
diagnosticRuntime.stop();
|
|
494
555
|
}
|
|
495
|
-
for (const check of runtimeDiagnostics.checks)
|
|
496
|
-
checks.push({
|
|
497
|
-
name: `runtime:${check.layer}`,
|
|
498
|
-
ok: check.skipped === true || check.ok === true,
|
|
499
|
-
detail: check.skipped ? `skipped (${check.error_class || "not applicable"})` : check.ok ? "ok" : check.error_class || "failed",
|
|
500
|
-
});
|
|
501
|
-
}
|
|
556
|
+
for (const check of runtimeDiagnostics.checks) checks.push(doctorRuntimeCheckProjection(check));
|
|
502
557
|
console.log(JSON.stringify({
|
|
503
558
|
ok: checks.every(check => check.ok),
|
|
504
559
|
checks,
|
|
505
|
-
|
|
506
|
-
state:
|
|
560
|
+
diagnosticScope: DOCTOR_RUNTIME_SCOPE,
|
|
561
|
+
state: supportStateProjection(state),
|
|
507
562
|
}, null, 2));
|
|
508
563
|
}
|
|
509
564
|
|
|
@@ -518,11 +573,20 @@ async function fullTestCommand(args) {
|
|
|
518
573
|
|
|
519
574
|
async function rotateSecretsCommand(args) {
|
|
520
575
|
const workspace = await chooseWorkspace(args, { promptOnFirstRun: false, save: false, allowPositional: true });
|
|
521
|
-
|
|
576
|
+
let state = loadState(workspace, { stateDir: args.stateDir });
|
|
522
577
|
const operationLogger = createLogger({ level: args.quiet ? "error" : "warn", component: "service" });
|
|
523
|
-
|
|
578
|
+
let startupLock = null;
|
|
579
|
+
let serviceLock = null;
|
|
524
580
|
try {
|
|
525
|
-
await
|
|
581
|
+
serviceLock = await acquireMachineServiceLockWithWait({ operation: "rotate-secrets", logger: operationLogger });
|
|
582
|
+
startupLock = await acquireStartupLockWithWait(state, { operation: "rotate-secrets", logger: operationLogger });
|
|
583
|
+
state = loadState(workspace, { stateDir: args.stateDir });
|
|
584
|
+
await stopOwnedPlatformService({
|
|
585
|
+
state,
|
|
586
|
+
inspectWorkspaceDaemon,
|
|
587
|
+
ownsPlatformAutostart: workspaceDaemonOwnsPlatformAutostart,
|
|
588
|
+
stopPlatformService: () => stopAutostartBestEffort(operationLogger),
|
|
589
|
+
});
|
|
526
590
|
const stopped = await stopWorkspaceServiceDaemon(state, { logger: operationLogger, reason: "secret rotation" });
|
|
527
591
|
if (stopped.found && !stopped.ok) {
|
|
528
592
|
const pid = stopped.pid ? `pid ${stopped.pid}` : "unknown pid";
|
|
@@ -534,19 +598,35 @@ async function rotateSecretsCommand(args) {
|
|
|
534
598
|
if (daemonIdentity?.current) {
|
|
535
599
|
throw new Error(`refusing to rotate secrets while the daemon is active (pid ${daemonOwner.pid}); stop the foreground daemon and retry`);
|
|
536
600
|
}
|
|
537
|
-
|
|
601
|
+
if (state.worker.pendingDeviceIdentity) throw new Error("a device-root rotation is already pending; run machine-mcp to deploy it before rotating again");
|
|
602
|
+
ensureWorkerSecrets(state, { rotateSecrets: true, deferDeviceRotation: true });
|
|
603
|
+
state.worker.pendingDeviceIdentity = await ensurePreferredDeviceRoot({
|
|
604
|
+
profileDir: state.paths.profileDir,
|
|
605
|
+
workspaceHash: state.workspace.hash,
|
|
606
|
+
existing: null,
|
|
607
|
+
rotate: true,
|
|
608
|
+
});
|
|
538
609
|
saveState(state);
|
|
539
|
-
console.log("
|
|
540
|
-
console.log("All account access tokens are invalid. Run machine-mcp to
|
|
610
|
+
console.log("Prepared a two-phase rotation for account administration, device root, and token-version secrets.");
|
|
611
|
+
console.log("All account access tokens are invalid. Run machine-mcp to deploy, verify, and atomically promote the pending device root.");
|
|
541
612
|
} finally {
|
|
542
|
-
startupLock
|
|
613
|
+
startupLock?.release?.();
|
|
614
|
+
serviceLock?.release?.();
|
|
543
615
|
}
|
|
544
616
|
}
|
|
545
617
|
|
|
546
|
-
async function installAutostartBestEffort({ workspace, stateRoot, entryScript, logger }) {
|
|
618
|
+
export async function installAutostartBestEffort({ workspace, stateRoot, entryScript, logger }, options = {}) {
|
|
619
|
+
let serviceLock = null;
|
|
547
620
|
try {
|
|
548
|
-
const
|
|
549
|
-
const
|
|
621
|
+
const acquireLock = options.acquireServiceLock || acquireMachineServiceLockWithWait;
|
|
622
|
+
const acquired = await acquireLock({ operation: "runtime-start-autostart", logger });
|
|
623
|
+
if (!acquired?.acquired || typeof acquired.release !== "function") {
|
|
624
|
+
throw new Error("machine-service operation lock could not be acquired for automatic autostart installation");
|
|
625
|
+
}
|
|
626
|
+
serviceLock = acquired;
|
|
627
|
+
const install = options.installAutostart || (await import("./service.mjs")).installAutostart;
|
|
628
|
+
const makeLogger = options.structuredLogger || structuredLogger;
|
|
629
|
+
const result = await install({ workspace, stateRoot, entryScript, version: currentPackageVersion(), logger: makeLogger(true) });
|
|
550
630
|
if (result?.ok) logger.info("Autostart installed for future logins", { provider: result.provider });
|
|
551
631
|
else logger.warn("Autostart installation reported a problem; run `machine-mcp service status` for details", {
|
|
552
632
|
provider: result?.provider || "unknown",
|
|
@@ -554,6 +634,8 @@ async function installAutostartBestEffort({ workspace, stateRoot, entryScript, l
|
|
|
554
634
|
});
|
|
555
635
|
} catch (error) {
|
|
556
636
|
logger.warn("Autostart installation skipped", { error_class: classifyOperationalError(error) });
|
|
637
|
+
} finally {
|
|
638
|
+
serviceLock?.release?.();
|
|
557
639
|
}
|
|
558
640
|
}
|
|
559
641
|
|
|
@@ -585,13 +667,19 @@ async function uninstallCommand(args) {
|
|
|
585
667
|
console.log("Uninstall cancelled. Re-run with `machine-mcp uninstall --yes` to skip confirmation.");
|
|
586
668
|
return;
|
|
587
669
|
}
|
|
670
|
+
await withReleaseRuntimeLock(stateRoot, () => uninstallStateRoot({ stateRoot, deleteRemote }));
|
|
671
|
+
}
|
|
672
|
+
|
|
673
|
+
async function uninstallStateRoot({ stateRoot, deleteRemote }) {
|
|
588
674
|
const currentValidation = validateStateRootForRemoval(stateRoot);
|
|
589
675
|
const maintenance = currentValidation.exists ? acquireMaintenanceLock(stateRoot, { operation: "uninstall" }) : null;
|
|
590
676
|
if (maintenance && !maintenance.acquired) {
|
|
591
677
|
const pid = maintenance.owner?.pid ? `pid ${maintenance.owner.pid}` : "another process";
|
|
592
678
|
throw new Error(`another state maintenance operation is active (${pid})`);
|
|
593
679
|
}
|
|
680
|
+
let serviceLock = null;
|
|
594
681
|
try {
|
|
682
|
+
serviceLock = await acquireMachineServiceLockWithWait({ operation: "uninstall" });
|
|
595
683
|
if (currentValidation.exists) validateStateRootForRemoval(stateRoot);
|
|
596
684
|
assertNoActiveJobsForUninstall(stateRoot);
|
|
597
685
|
const autostartRemoved = await removeAutostartBestEffort(stateRoot);
|
|
@@ -608,16 +696,24 @@ async function uninstallCommand(args) {
|
|
|
608
696
|
console.log("If installed globally, remove the npm package with:");
|
|
609
697
|
console.log(" npm uninstall -g machine-bridge-mcp");
|
|
610
698
|
} finally {
|
|
699
|
+
serviceLock?.release?.();
|
|
611
700
|
maintenance?.release?.();
|
|
612
701
|
}
|
|
613
702
|
}
|
|
614
703
|
|
|
615
704
|
function assertNoActiveJobsForUninstall(stateRoot) {
|
|
705
|
+
for (const state of knownProfileStates(stateRoot)) {
|
|
706
|
+
pruneRetiredManagedJobDirectories(join(state.paths.profileDir, "jobs"), { warn() {} });
|
|
707
|
+
}
|
|
616
708
|
const activeJobs = activeStateJobs(stateRoot);
|
|
617
709
|
if (!activeJobs.length) return;
|
|
618
|
-
const
|
|
710
|
+
const retiredBlocked = activeJobs.some((item) => item.state_kind === "retired_managed_job");
|
|
711
|
+
const detail = activeJobs.slice(0, 5).map((item) => item.state_kind === "retired_managed_job" ? `retired-managed-job:${item.status}` : `${item.job_id}:${item.status}`).join(", ");
|
|
619
712
|
const suffix = activeJobs.length > 5 ? `, and ${activeJobs.length - 5} more` : "";
|
|
620
|
-
|
|
713
|
+
const guidance = retiredBlocked
|
|
714
|
+
? "run machine-mcp job list to retry safe retired cleanup; if retired state remains unreadable, inspect the owner-only state root instead of deleting it blindly; cancel any active jobs before retrying"
|
|
715
|
+
: "inspect with machine-mcp job list/read and cancel active jobs before retrying";
|
|
716
|
+
throw new Error(`refusing to uninstall while managed-job state is active or requires inspection (${detail}${suffix}); ${guidance}`);
|
|
621
717
|
}
|
|
622
718
|
|
|
623
719
|
function assertNoActiveLocksForUninstall(stateRoot) {
|
|
@@ -635,9 +731,9 @@ async function deleteKnownWorkers(stateRoot) {
|
|
|
635
731
|
}
|
|
636
732
|
const failures = [];
|
|
637
733
|
for (const name of names) {
|
|
638
|
-
const result = await runWrangler(["delete", name, "--force"], { capture: true, allowFailure: true });
|
|
734
|
+
const result = await runWrangler(["delete", name, "--force"], { capture: true, allowFailure: true, stateRoot });
|
|
639
735
|
const detail = (result.stderr || result.stdout || "unknown error").trim();
|
|
640
|
-
if (result.code === 0
|
|
736
|
+
if (result.code === 0) {
|
|
641
737
|
console.log(`Deleted Worker: ${name}`);
|
|
642
738
|
} else {
|
|
643
739
|
failures.push({ name, detail: sanitizeLines(detail) || "unknown error" });
|
|
@@ -694,14 +790,7 @@ function escapeRegExp(value) {
|
|
|
694
790
|
return String(value).replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
695
791
|
}
|
|
696
792
|
|
|
697
|
-
|
|
698
|
-
if (value === undefined || value === null || value === false) return undefined;
|
|
699
|
-
const name = String(value).trim();
|
|
700
|
-
if (!/^[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?$/.test(name)) {
|
|
701
|
-
throw new Error("--worker-name must be 1-63 lowercase letters, digits, or hyphens, and cannot start or end with a hyphen");
|
|
702
|
-
}
|
|
703
|
-
return name;
|
|
704
|
-
}
|
|
793
|
+
|
|
705
794
|
|
|
706
795
|
export function isSupportedNodeVersion(version = process.versions.node) {
|
|
707
796
|
const major = Number(String(version || "").replace(/^v/, "").split(".")[0]);
|
|
@@ -737,28 +826,23 @@ Usage:
|
|
|
737
826
|
|
|
738
827
|
Commands:
|
|
739
828
|
start Deploy/update Worker, take over autostart, run foreground daemon
|
|
829
|
+
activate Deploy/update Worker, replace autostart, start and verify background daemon
|
|
740
830
|
stdio Run a local MCP stdio server for Claude, Cursor, Codex, and compatible clients
|
|
741
831
|
client-config Print stdio client configuration snippets
|
|
742
832
|
workspace show Show remembered workspace
|
|
743
833
|
workspace set Re-select workspace; prompts with current/default path
|
|
744
834
|
service status Show autostart status
|
|
745
835
|
service install Install login autostart for remembered/current workspace
|
|
746
|
-
service start
|
|
836
|
+
service start Ensure the installed autostart service is running (idempotent)
|
|
837
|
+
service restart Schedule an explicit service-manager restart and return before handoff
|
|
747
838
|
service stop Stop the installed autostart service
|
|
748
839
|
service uninstall Remove only the autostart entry
|
|
749
840
|
status Print redacted local profile state and Worker health
|
|
750
841
|
doctor Check Node, Wrangler, Cloudflare login, Worker health
|
|
751
842
|
full-test Run real local full-profile capability tests in a temporary sandbox
|
|
752
843
|
rotate-secrets Rotate account-admin, device identity, and global token-version secrets
|
|
753
|
-
account list|add|role|enable|disable|rotate-password|remove
|
|
754
|
-
Manage
|
|
755
|
-
approval list Show pending high-impact operations and active capability leases
|
|
756
|
-
approval approve APPROVAL_ID [--duration 1h] [--full]
|
|
757
|
-
Approve its scope, or open an explicit full window (maximum 8h)
|
|
758
|
-
approval grant SCOPE --account ACCOUNT_ID --client CLIENT_ID [--duration 1h]
|
|
759
|
-
Pre-authorize a bounded scope; use * values only intentionally
|
|
760
|
-
approval revoke LEASE_ID | approval clear
|
|
761
|
-
Revoke one or all local capability leases
|
|
844
|
+
account list|clients|revoke-client|add|role|enable|disable|rotate-password|remove
|
|
845
|
+
Manage remote accounts, trusted clients, and targeted revocation
|
|
762
846
|
resource generate-ssh-key NAME [PATH]
|
|
763
847
|
Generate/reuse an Ed25519 key locally and register its private file by alias
|
|
764
848
|
browser status Show browser-extension bridge and connection status
|
|
@@ -797,13 +881,11 @@ Uninstall options:
|
|
|
797
881
|
}
|
|
798
882
|
|
|
799
883
|
function currentPackageVersion() {
|
|
800
|
-
|
|
801
|
-
return String(pkg.version);
|
|
884
|
+
return packageVersion;
|
|
802
885
|
}
|
|
803
886
|
|
|
804
887
|
function version() {
|
|
805
|
-
|
|
806
|
-
console.log(`${pkg.name} ${pkg.version}`);
|
|
888
|
+
console.log(`${packageName} ${packageVersion}`);
|
|
807
889
|
}
|
|
808
890
|
|
|
809
891
|
function sleep(ms) {
|