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/service.mjs
CHANGED
|
@@ -1,14 +1,20 @@
|
|
|
1
|
-
import { closeSync, constants as fsConstants, existsSync, ftruncateSync, lstatSync, mkdirSync, readSync, realpathSync,
|
|
1
|
+
import { closeSync, constants as fsConstants, existsSync, ftruncateSync, lstatSync, mkdirSync, readSync, realpathSync, statSync, writeSync } from "node:fs";
|
|
2
2
|
import os from "node:os";
|
|
3
3
|
import path from "node:path";
|
|
4
4
|
import { runExecutable } from "./shell.mjs";
|
|
5
|
-
import {
|
|
5
|
+
import { expandHome } from "./state.mjs";
|
|
6
|
+
import { ensureOwnerOnlyDir } from "./secure-file.mjs";
|
|
6
7
|
import { replaceFileAtomicallySync } from "./exclusive-file.mjs";
|
|
7
8
|
import { openRegularFileSync, readBoundedRegularFileSync } from "./secure-file.mjs";
|
|
8
|
-
import { waitForInactiveStatus } from "./service-convergence.mjs";
|
|
9
|
+
import { waitForInactiveStatus, waitForStableActiveStatus, waitForStatus } from "./service-convergence.mjs";
|
|
10
|
+
import { launchdStatusSummary, systemdStatusSummary } from "./service-status.mjs";
|
|
11
|
+
import { systemdRemovalDecision } from "./systemd-removal.mjs";
|
|
12
|
+
import { removeServiceDefinitionIfCurrent, snapshotServiceDefinition } from "./service-definition.mjs";
|
|
9
13
|
import { writeServiceEnvironment } from "./service-environment.mjs";
|
|
14
|
+
import { beginServiceOwnerUpdate, removeServiceOwner } from "./service-owner.mjs";
|
|
10
15
|
import {
|
|
11
16
|
installWindowsTask,
|
|
17
|
+
restartWindowsTask,
|
|
12
18
|
startWindowsTask,
|
|
13
19
|
statusWindowsTask,
|
|
14
20
|
stopWindowsTask,
|
|
@@ -18,7 +24,8 @@ export { windowsCommandLineArgument } from "./windows-service.mjs";
|
|
|
18
24
|
|
|
19
25
|
const LABEL = "dev.machine-bridge-mcp.daemon";
|
|
20
26
|
const SERVICE_COMMAND_OUTPUT_BYTES = 64 * 1024;
|
|
21
|
-
const
|
|
27
|
+
const SERVICE_COMMAND_TIMEOUT_MS = 30_000;
|
|
28
|
+
const AUTOSTART_LOG_SCHEMA_VERSION = 4;
|
|
22
29
|
|
|
23
30
|
function serviceRun(command, args) {
|
|
24
31
|
return runServiceCommand(command, args);
|
|
@@ -28,24 +35,93 @@ export function runServiceCommand(command, args, execute = runExecutable) {
|
|
|
28
35
|
return execute(command, args, {
|
|
29
36
|
capture: true,
|
|
30
37
|
allowFailure: true,
|
|
38
|
+
timeoutMs: SERVICE_COMMAND_TIMEOUT_MS,
|
|
31
39
|
maxOutputBytes: SERVICE_COMMAND_OUTPUT_BYTES,
|
|
32
40
|
});
|
|
33
41
|
}
|
|
34
42
|
|
|
35
|
-
export async function installAutostart({ workspace, stateRoot, entryScript, logger = console
|
|
43
|
+
export async function installAutostart({ workspace, stateRoot, entryScript, version, logger = console,
|
|
44
|
+
installProvider = defaultInstallProvider, beginOwnerUpdate = beginServiceOwnerUpdate,
|
|
45
|
+
writeEnvironment = writeServiceEnvironment, deferOwnerCommit = false } = {}) {
|
|
36
46
|
const spec = serviceSpec({ workspace, stateRoot, entryScript });
|
|
37
|
-
const
|
|
47
|
+
const ownerUpdate = beginOwnerUpdate({ ...spec, version });
|
|
48
|
+
let serviceEnvironment;
|
|
49
|
+
try { serviceEnvironment = writeEnvironment(spec.stateRoot); }
|
|
50
|
+
catch (error) {
|
|
51
|
+
try { ownerUpdate.rollback(); }
|
|
52
|
+
catch (rollbackError) {
|
|
53
|
+
throw new AggregateError([error, rollbackError],
|
|
54
|
+
"service environment preparation failed and the previous machine service owner could not be restored");
|
|
55
|
+
}
|
|
56
|
+
throw error;
|
|
57
|
+
}
|
|
38
58
|
let result;
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
59
|
+
try { result = await installProvider(spec, logger); }
|
|
60
|
+
catch (error) {
|
|
61
|
+
throw new Error(
|
|
62
|
+
"autostart installation threw after its machine service owner became pending; service start is blocked until reinstall",
|
|
63
|
+
{ cause: error },
|
|
64
|
+
);
|
|
65
|
+
}
|
|
66
|
+
if (result?.ok !== true) {
|
|
67
|
+
return withDeferredOwnerTransaction({
|
|
68
|
+
...result,
|
|
69
|
+
service_environment: serviceEnvironment,
|
|
70
|
+
service_owner: { status: "pending", version },
|
|
71
|
+
reason: result?.reason || "installation_failed_owner_pending",
|
|
72
|
+
}, ownerUpdate, deferOwnerCommit);
|
|
73
|
+
}
|
|
74
|
+
if (deferOwnerCommit) {
|
|
75
|
+
return withDeferredOwnerTransaction({
|
|
76
|
+
...result,
|
|
77
|
+
service_environment: serviceEnvironment,
|
|
78
|
+
service_owner: { status: "pending", version },
|
|
79
|
+
}, ownerUpdate, true);
|
|
80
|
+
}
|
|
81
|
+
let owner;
|
|
82
|
+
try { owner = ownerUpdate.commit(); }
|
|
83
|
+
catch (error) {
|
|
84
|
+
throw new Error(
|
|
85
|
+
"autostart definition was installed but its machine service owner could not be committed; the pending owner was retained and service start is blocked until reinstall",
|
|
86
|
+
{ cause: error },
|
|
87
|
+
);
|
|
88
|
+
}
|
|
89
|
+
return { ...result, service_environment: serviceEnvironment, service_owner: { status: owner.status, version: owner.version } };
|
|
43
90
|
}
|
|
44
91
|
|
|
92
|
+
function withDeferredOwnerTransaction(result, ownerUpdate, enabled) {
|
|
93
|
+
if (!enabled) return result;
|
|
94
|
+
if (!ownerUpdate?.owner || ownerUpdate.owner.status !== "pending"
|
|
95
|
+
|| typeof ownerUpdate.commit !== "function" || typeof ownerUpdate.rollback !== "function") {
|
|
96
|
+
throw new Error("deferred machine service owner transaction is unavailable");
|
|
97
|
+
}
|
|
98
|
+
Object.defineProperty(result, "serviceOwnerTransaction", {
|
|
99
|
+
value: Object.freeze({
|
|
100
|
+
owner: ownerUpdate.owner,
|
|
101
|
+
commit: () => ownerUpdate.commit(),
|
|
102
|
+
rollback: () => ownerUpdate.rollback(),
|
|
103
|
+
}),
|
|
104
|
+
enumerable: false,
|
|
105
|
+
configurable: false,
|
|
106
|
+
writable: false,
|
|
107
|
+
});
|
|
108
|
+
return result;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
async function defaultInstallProvider(spec, logger) {
|
|
112
|
+
if (process.platform === "darwin") return installLaunchd(spec, logger);
|
|
113
|
+
if (process.platform === "win32") return installWindowsTask(spec, logger, { run: serviceRun });
|
|
114
|
+
return installSystemd(spec, logger);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
|
|
45
118
|
export async function uninstallAutostart({ stateRoot, logger = console } = {}) {
|
|
46
|
-
|
|
47
|
-
if (process.platform === "
|
|
48
|
-
|
|
119
|
+
let result;
|
|
120
|
+
if (process.platform === "darwin") result = await uninstallLaunchd(logger);
|
|
121
|
+
else if (process.platform === "win32") result = await uninstallWindowsTask(logger, { run: serviceRun, stateRoot });
|
|
122
|
+
else result = await uninstallSystemd(logger);
|
|
123
|
+
if (result?.ok === true) removeServiceOwner();
|
|
124
|
+
return result;
|
|
49
125
|
}
|
|
50
126
|
|
|
51
127
|
export async function autostartStatus() {
|
|
@@ -57,25 +133,19 @@ export async function autostartStatus() {
|
|
|
57
133
|
export async function startAutostart({ logger = console } = {}) {
|
|
58
134
|
if (process.platform === "darwin") return startLaunchd(logger);
|
|
59
135
|
if (process.platform === "win32") return startWindowsTask(logger, { run: serviceRun });
|
|
60
|
-
return
|
|
136
|
+
return startSystemd(logger);
|
|
61
137
|
}
|
|
62
138
|
|
|
63
|
-
export async function
|
|
64
|
-
if (process.platform === "darwin") return
|
|
65
|
-
if (process.platform === "win32") return
|
|
66
|
-
return
|
|
139
|
+
export async function restartAutostart({ logger = console } = {}) {
|
|
140
|
+
if (process.platform === "darwin") return restartLaunchd(logger);
|
|
141
|
+
if (process.platform === "win32") return restartWindowsTask(logger, { run: serviceRun });
|
|
142
|
+
return restartSystemd(logger);
|
|
67
143
|
}
|
|
68
144
|
|
|
69
|
-
export function
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
return {
|
|
74
|
-
...result,
|
|
75
|
-
ok: result?.code === 0 || alreadyStopped,
|
|
76
|
-
provider,
|
|
77
|
-
already_stopped: alreadyStopped,
|
|
78
|
-
};
|
|
145
|
+
export async function stopAutostart({ logger = console } = {}) {
|
|
146
|
+
if (process.platform === "darwin") return stopLaunchdService(logger);
|
|
147
|
+
if (process.platform === "win32") return stopWindowsTask(logger, { run: serviceRun });
|
|
148
|
+
return stopSystemdService(logger);
|
|
79
149
|
}
|
|
80
150
|
|
|
81
151
|
export function trimAutostartLogs(stateRoot, options = {}) {
|
|
@@ -84,37 +154,43 @@ export function trimAutostartLogs(stateRoot, options = {}) {
|
|
|
84
154
|
const keepBytes = Math.min(maxBytes, Number.isFinite(Number(options.keepBytes)) ? Math.max(1024, Number(options.keepBytes)) : 1024 * 1024);
|
|
85
155
|
const schemaVersion = String(AUTOSTART_LOG_SCHEMA_VERSION);
|
|
86
156
|
const logs = path.join(root, "logs");
|
|
157
|
+
ensureOwnerOnlyDir(logs);
|
|
87
158
|
const schemaFile = path.join(logs, ".log-schema");
|
|
88
159
|
const reset = readLogSchema(schemaFile) !== schemaVersion;
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
const
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
label: "autostart log path",
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
160
|
+
const openedLogs = [];
|
|
161
|
+
try {
|
|
162
|
+
for (const name of ["daemon.out.log", "daemon.err.log"]) {
|
|
163
|
+
const file = path.join(logs, name);
|
|
164
|
+
ensurePrivateLogFile(file);
|
|
165
|
+
openedLogs.push(openRegularFileSync(file, fsConstants.O_RDWR, {
|
|
166
|
+
label: "autostart log path", chmod: 0o600, rejectMultipleLinks: true,
|
|
167
|
+
}));
|
|
168
|
+
}
|
|
169
|
+
for (const opened of openedLogs) {
|
|
99
170
|
if (reset) {
|
|
100
|
-
ftruncateSync(fd, 0);
|
|
171
|
+
ftruncateSync(opened.fd, 0);
|
|
101
172
|
} else if (opened.info.size > maxBytes) {
|
|
102
|
-
const tail = readLogTail(fd, opened.info.size, keepBytes);
|
|
103
|
-
ftruncateSync(fd, 0);
|
|
104
|
-
if (tail.length) writeSync(fd, tail, 0, tail.length, 0);
|
|
173
|
+
const tail = readLogTail(opened.fd, opened.info.size, keepBytes);
|
|
174
|
+
ftruncateSync(opened.fd, 0);
|
|
175
|
+
if (tail.length) writeSync(opened.fd, tail, 0, tail.length, 0);
|
|
105
176
|
}
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
177
|
+
}
|
|
178
|
+
writePrivateServiceFile(schemaFile, `${schemaVersion}\n`);
|
|
179
|
+
} finally {
|
|
180
|
+
for (const opened of openedLogs) {
|
|
181
|
+
try { closeSync(opened.fd); }
|
|
182
|
+
catch { /* Descriptor cleanup cannot improve the already-completed log rotation outcome. */ }
|
|
110
183
|
}
|
|
111
184
|
}
|
|
112
|
-
|
|
113
|
-
try { writePrivateServiceFile(schemaFile, `${schemaVersion}\n`); } catch {}
|
|
114
185
|
}
|
|
115
186
|
|
|
116
187
|
function readLogSchema(file) {
|
|
117
|
-
try {
|
|
188
|
+
try {
|
|
189
|
+
return readBoundedRegularFileSync(file, 64, "autostart log schema", {
|
|
190
|
+
verifyPathIdentity: true,
|
|
191
|
+
rejectMultipleLinks: true,
|
|
192
|
+
}).toString("utf8").trim();
|
|
193
|
+
} catch (error) { if (error?.code === "ENOENT") return null; throw error; }
|
|
118
194
|
}
|
|
119
195
|
|
|
120
196
|
function readLogTail(fd, size, limit) {
|
|
@@ -172,33 +248,37 @@ export function stableNodeExecutable(options = {}) {
|
|
|
172
248
|
if (!sameExecutable) continue;
|
|
173
249
|
if (platform !== "win32" && (statSync(candidate).mode & 0o111) === 0) continue;
|
|
174
250
|
return candidate;
|
|
175
|
-
} catch {}
|
|
251
|
+
} catch { /* Inaccessible or transient PATH candidates are skipped in favor of the known executable. */ }
|
|
176
252
|
}
|
|
177
253
|
return execPath;
|
|
178
254
|
}
|
|
179
255
|
|
|
180
256
|
export function serviceEnvironmentPath(options = {}) {
|
|
181
257
|
const platform = String(options.platform || process.platform);
|
|
258
|
+
const pathApi = platform === "win32" ? path.win32 : path;
|
|
182
259
|
const delimiter = String(options.delimiter || (platform === "win32" ? ";" : ":"));
|
|
183
260
|
const pathEnv = String(options.pathEnv ?? process.env.PATH ?? "");
|
|
184
261
|
const node = String(options.node || process.execPath || "");
|
|
185
262
|
const entryScript = String(options.entryScript || "");
|
|
263
|
+
const entryDirectory = entryScript ? pathApi.dirname(pathApi.resolve(entryScript)) : "";
|
|
186
264
|
const defaults = platform === "darwin"
|
|
187
265
|
? ["/opt/homebrew/bin", "/usr/local/bin", "/usr/bin", "/bin", "/usr/sbin", "/sbin"]
|
|
188
266
|
: platform === "win32"
|
|
189
267
|
? []
|
|
190
268
|
: ["/usr/local/bin", "/usr/bin", "/bin", "/usr/local/sbin", "/usr/sbin", "/sbin"];
|
|
269
|
+
const inheritedEntries = stripNpmLifecyclePathPrefix(pathEnv.split(delimiter));
|
|
191
270
|
const candidates = [
|
|
192
|
-
node ?
|
|
193
|
-
|
|
194
|
-
...
|
|
271
|
+
node ? pathApi.dirname(pathApi.resolve(node)) : "",
|
|
272
|
+
entryDirectory,
|
|
273
|
+
...inheritedEntries,
|
|
195
274
|
...defaults,
|
|
196
275
|
];
|
|
197
276
|
const seen = new Set();
|
|
198
277
|
const entries = [];
|
|
199
278
|
for (const raw of candidates) {
|
|
200
|
-
if (!raw || !
|
|
201
|
-
const normalized =
|
|
279
|
+
if (!raw || !pathApi.isAbsolute(raw)) continue;
|
|
280
|
+
const normalized = pathApi.resolve(raw);
|
|
281
|
+
if (isInactiveCandidateRuntimePath(normalized, entryDirectory, platform)) continue;
|
|
202
282
|
const key = platform === "win32" ? normalized.toLowerCase() : normalized;
|
|
203
283
|
if (seen.has(key)) continue;
|
|
204
284
|
seen.add(key);
|
|
@@ -207,6 +287,33 @@ export function serviceEnvironmentPath(options = {}) {
|
|
|
207
287
|
return entries.join(delimiter);
|
|
208
288
|
}
|
|
209
289
|
|
|
290
|
+
function stripNpmLifecyclePathPrefix(entries) {
|
|
291
|
+
let lastMarker = -1;
|
|
292
|
+
for (let index = 0; index < entries.length; index += 1) {
|
|
293
|
+
const portable = String(entries[index] || "").replaceAll("\\", "/").toLowerCase();
|
|
294
|
+
if (portable.endsWith("/node-gyp-bin") && portable.includes("/@npmcli/run-script/")) lastMarker = index;
|
|
295
|
+
}
|
|
296
|
+
return lastMarker >= 0 ? entries.slice(lastMarker + 1) : entries;
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
function isInactiveCandidateRuntimePath(candidate, entryDirectory, platform) {
|
|
300
|
+
if (!entryDirectory) return false;
|
|
301
|
+
const pathApi = platform === "win32" ? path.win32 : path;
|
|
302
|
+
const normalize = (value) => {
|
|
303
|
+
const resolved = pathApi.resolve(value);
|
|
304
|
+
return platform === "win32" ? resolved.toLowerCase() : resolved;
|
|
305
|
+
};
|
|
306
|
+
const current = normalize(entryDirectory);
|
|
307
|
+
const portable = current.replaceAll("\\", "/");
|
|
308
|
+
const marker = "/release-channels/runtimes/";
|
|
309
|
+
const markerIndex = portable.indexOf(marker);
|
|
310
|
+
if (markerIndex < 0) return false;
|
|
311
|
+
const runtimeContainer = portable.slice(0, markerIndex + marker.length - 1);
|
|
312
|
+
const normalizedCandidate = normalize(candidate).replaceAll("\\", "/");
|
|
313
|
+
return normalizedCandidate !== portable
|
|
314
|
+
&& (normalizedCandidate === runtimeContainer || normalizedCandidate.startsWith(`${runtimeContainer}/`));
|
|
315
|
+
}
|
|
316
|
+
|
|
210
317
|
export function daemonArgs(spec) {
|
|
211
318
|
return [
|
|
212
319
|
spec.entryScript,
|
|
@@ -223,7 +330,7 @@ function ensurePrivateLogFile(file) {
|
|
|
223
330
|
const opened = openRegularFileSync(
|
|
224
331
|
file,
|
|
225
332
|
Number(fsConstants.O_WRONLY) | Number(fsConstants.O_CREAT) | Number(fsConstants.O_APPEND),
|
|
226
|
-
{ label: "autostart log path", mode: 0o600, chmod: 0o600 },
|
|
333
|
+
{ label: "autostart log path", mode: 0o600, chmod: 0o600, rejectMultipleLinks: true },
|
|
227
334
|
);
|
|
228
335
|
closeSync(opened.fd);
|
|
229
336
|
}
|
|
@@ -260,31 +367,94 @@ async function installLaunchd(spec, logger) {
|
|
|
260
367
|
|
|
261
368
|
async function startLaunchd(logger) {
|
|
262
369
|
const plistPath = launchdPlistPath();
|
|
263
|
-
const
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
370
|
+
const domainTarget = launchdDomainTarget();
|
|
371
|
+
const serviceTarget = launchdServiceTarget();
|
|
372
|
+
if (!existsSync(plistPath)) return { ok: false, provider: "launchd", installed: false, loaded: false, active: false, reason: "not_installed" };
|
|
373
|
+
const before = await statusLaunchd();
|
|
374
|
+
if (before.status_available !== true || typeof before.active !== "boolean") {
|
|
375
|
+
return { ok: false, provider: "launchd", installed: true, loaded: null, active: null, reason: "status_unavailable", status: before };
|
|
376
|
+
}
|
|
377
|
+
if (before.active) {
|
|
378
|
+
const existing = await waitForStableActiveStatus(statusLaunchd);
|
|
379
|
+
if (existing.stable) {
|
|
380
|
+
logger.info?.("launchd service is already running");
|
|
381
|
+
return { ...existing.status, ok: true, active_before: true, already_running: true, reason: "already_running" };
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
const boot = before.loaded
|
|
385
|
+
? { code: 0, stdout: "", stderr: "", already_loaded: true }
|
|
386
|
+
: await serviceRun("launchctl", ["bootstrap", domainTarget, plistPath]);
|
|
387
|
+
const kick = await serviceRun("launchctl", ["kickstart", serviceTarget]);
|
|
388
|
+
const stability = await waitForStableActiveStatus(statusLaunchd);
|
|
389
|
+
const after = stability.status;
|
|
390
|
+
const ok = stability.stable;
|
|
270
391
|
if (ok) logger.info?.("launchd service started");
|
|
271
392
|
else logger.warn?.("launchd service failed to start");
|
|
272
|
-
return {
|
|
393
|
+
return {
|
|
394
|
+
ok,
|
|
395
|
+
provider: "launchd",
|
|
396
|
+
installed: true,
|
|
397
|
+
loaded: after?.loaded === true,
|
|
398
|
+
active_before: false,
|
|
399
|
+
active: after?.active === true,
|
|
400
|
+
bootstrap: boot,
|
|
401
|
+
kickstart: kick,
|
|
402
|
+
};
|
|
273
403
|
}
|
|
274
404
|
|
|
275
|
-
async function
|
|
405
|
+
async function restartLaunchd(logger) {
|
|
276
406
|
const plistPath = launchdPlistPath();
|
|
277
|
-
|
|
278
|
-
const serviceTarget = launchdServiceTarget();
|
|
407
|
+
if (!existsSync(plistPath)) return { ok: false, provider: "launchd", installed: false, reason: "not_installed" };
|
|
279
408
|
const before = await statusLaunchd();
|
|
409
|
+
if (before.status_available !== true || typeof before.active !== "boolean") {
|
|
410
|
+
return { ok: false, provider: "launchd", installed: true, active: null, restarted: false, reason: "status_unavailable", status: before };
|
|
411
|
+
}
|
|
280
412
|
if (!before.active) {
|
|
413
|
+
const started = await startLaunchd(logger);
|
|
414
|
+
return { ...started, restarted: false, reason: started.ok ? "started_inactive_service" : started.reason || "start_failed" };
|
|
415
|
+
}
|
|
416
|
+
const target = launchdServiceTarget();
|
|
417
|
+
const previousPid = before.pid;
|
|
418
|
+
const kick = await serviceRun("launchctl", ["kickstart", "-k", target]);
|
|
419
|
+
const changed = await waitForStatus(
|
|
420
|
+
statusLaunchd,
|
|
421
|
+
(status) => status?.active === true && (!previousPid || status.pid !== previousPid),
|
|
422
|
+
);
|
|
423
|
+
const stability = changed?.active === true && (!previousPid || changed.pid !== previousPid)
|
|
424
|
+
? await waitForStableActiveStatus(statusLaunchd, { identity: (status) => status?.pid || null })
|
|
425
|
+
: { stable: false, status: changed };
|
|
426
|
+
const after = stability.status;
|
|
427
|
+
const ok = kick.code === 0 && stability.stable && (!previousPid || after?.pid !== previousPid);
|
|
428
|
+
if (ok) logger.info?.("launchd service restarted");
|
|
429
|
+
else logger.warn?.("launchd service restart could not be verified");
|
|
430
|
+
return { ok, provider: "launchd", installed: true, active_before: true, active: after?.active === true && stability.stable, restarted: ok, kickstart: kick };
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
export async function stopLaunchdService(logger = console, options = {}) {
|
|
434
|
+
const plistPath = launchdPlistPath();
|
|
435
|
+
const run = typeof options.run === "function" ? options.run : serviceRun;
|
|
436
|
+
const readStatus = typeof options.readStatus === "function" ? options.readStatus : statusLaunchd;
|
|
437
|
+
const waitForUnloaded = typeof options.waitForUnloaded === "function"
|
|
438
|
+
? options.waitForUnloaded
|
|
439
|
+
: callback => waitForStatus(callback, launchdStatusIsSafelyUnloaded, { attempts: 100, delayMs: 100 });
|
|
440
|
+
const before = await readStatus();
|
|
441
|
+
if (!before.loaded) {
|
|
442
|
+
if (!launchdStatusIsSafelyUnloaded(before)) {
|
|
443
|
+
return {
|
|
444
|
+
ok: false, provider: "launchd", installed: before?.installed === true, loaded: null,
|
|
445
|
+
active_before: null, active: null, restore_required: null, already_stopped: false,
|
|
446
|
+
reason: "status_unavailable", status: before,
|
|
447
|
+
};
|
|
448
|
+
}
|
|
281
449
|
logger.info?.("launchd service is not loaded");
|
|
282
450
|
return {
|
|
283
451
|
ok: true,
|
|
284
452
|
provider: "launchd",
|
|
285
|
-
installed:
|
|
453
|
+
installed: before?.installed === true,
|
|
454
|
+
loaded: false,
|
|
286
455
|
active_before: false,
|
|
287
456
|
active: false,
|
|
457
|
+
restore_required: false,
|
|
288
458
|
already_stopped: true,
|
|
289
459
|
code: 0,
|
|
290
460
|
stdout: "",
|
|
@@ -292,44 +462,61 @@ async function stopLaunchd(logger) {
|
|
|
292
462
|
};
|
|
293
463
|
}
|
|
294
464
|
|
|
295
|
-
const
|
|
465
|
+
const uid = options.uid === undefined ? process.getuid?.() : options.uid;
|
|
466
|
+
const domainTarget = launchdDomainTarget(uid);
|
|
467
|
+
const serviceTarget = launchdServiceTarget(uid);
|
|
468
|
+
const byServiceTarget = await run("launchctl", ["bootout", serviceTarget]);
|
|
296
469
|
const byPlist = byServiceTarget.code === 0
|
|
297
470
|
? null
|
|
298
|
-
: await
|
|
299
|
-
const after = await
|
|
471
|
+
: await run("launchctl", ["bootout", domainTarget, plistPath]);
|
|
472
|
+
const after = await waitForUnloaded(readStatus);
|
|
300
473
|
const rawResult = byPlist || byServiceTarget;
|
|
301
|
-
const
|
|
302
|
-
const ok = !active;
|
|
474
|
+
const ok = launchdStatusIsSafelyUnloaded(after);
|
|
303
475
|
if (ok) logger.info?.("launchd service stopped");
|
|
304
|
-
else logger.warn?.("launchd service
|
|
476
|
+
else logger.warn?.("launchd service removal from the launchd domain could not be verified");
|
|
305
477
|
return {
|
|
306
478
|
...rawResult,
|
|
307
479
|
ok,
|
|
308
480
|
provider: "launchd",
|
|
309
|
-
installed:
|
|
310
|
-
|
|
311
|
-
active,
|
|
481
|
+
installed: after?.installed === true,
|
|
482
|
+
loaded: ok ? false : after?.loaded ?? null,
|
|
483
|
+
active_before: before.active === true,
|
|
484
|
+
active: ok ? false : after?.active ?? null,
|
|
485
|
+
// Once bootout is dispatched, an initially active service may still
|
|
486
|
+
// disappear after this observation window. Preserve rollback intent even
|
|
487
|
+
// when stop settlement itself is inconclusive.
|
|
488
|
+
restore_required: before.active === true,
|
|
489
|
+
mutation_attempted: true,
|
|
312
490
|
already_stopped: false,
|
|
313
491
|
code: ok ? 0 : rawResult.code,
|
|
492
|
+
reason: ok ? "stopped" : "stop_not_observed",
|
|
493
|
+
status: after,
|
|
314
494
|
bootout_service_target: byServiceTarget,
|
|
315
495
|
...(byPlist ? { bootout_plist_fallback: byPlist } : {}),
|
|
316
496
|
};
|
|
317
497
|
}
|
|
318
498
|
|
|
499
|
+
function launchdStatusIsSafelyUnloaded(status) {
|
|
500
|
+
return status?.status_available === true && status?.loaded === false && status?.active === false;
|
|
501
|
+
}
|
|
502
|
+
|
|
319
503
|
async function uninstallLaunchd(logger) {
|
|
320
|
-
const stopped = await stopLaunchd(logger);
|
|
321
504
|
const plistPath = launchdPlistPath();
|
|
505
|
+
const definitionIdentity = snapshotServiceDefinition(plistPath, "launchd service definition");
|
|
506
|
+
const stopped = await stopLaunchdService(logger);
|
|
322
507
|
if (!stopped.ok) return { ok: false, provider: "launchd", path: plistPath, stop: stopped };
|
|
323
|
-
if (
|
|
508
|
+
if (!removeServiceDefinitionIfCurrent(plistPath, definitionIdentity, "launchd service definition")) {
|
|
509
|
+
logger.warn?.("launchd service definition changed during removal; the replacement was retained.");
|
|
510
|
+
return { ok: false, provider: "launchd", path: plistPath, stop: stopped, reason: "definition_changed" };
|
|
511
|
+
}
|
|
324
512
|
logger.info?.("Autostart removed.");
|
|
325
513
|
return { ok: true, provider: "launchd", path: plistPath, stop: stopped };
|
|
326
514
|
}
|
|
327
515
|
|
|
328
516
|
async function statusLaunchd() {
|
|
329
517
|
const plistPath = launchdPlistPath();
|
|
330
|
-
const
|
|
331
|
-
|
|
332
|
-
return { ok: existsSync(plistPath), provider: "launchd", installed: existsSync(plistPath), path: plistPath, active: result.code === 0, detail: result.stdout || result.stderr };
|
|
518
|
+
const result = await serviceRun("launchctl", ["print", launchdServiceTarget()]);
|
|
519
|
+
return launchdStatusSummary({ installed: existsSync(plistPath), definition: LABEL, result });
|
|
333
520
|
}
|
|
334
521
|
|
|
335
522
|
export function launchdPlist({ args, pathEnv, stdout, stderr }) {
|
|
@@ -377,26 +564,132 @@ async function installSystemd(spec, logger) {
|
|
|
377
564
|
|
|
378
565
|
async function uninstallSystemd(logger) {
|
|
379
566
|
const servicePath = systemdPath();
|
|
567
|
+
const definitionIdentity = snapshotServiceDefinition(servicePath, "systemd service definition");
|
|
568
|
+
const definitionPresent = definitionIdentity !== null;
|
|
380
569
|
const disable = await serviceRun("systemctl", ["--user", "disable", "--now", "machine-bridge-mcp.service"]);
|
|
381
570
|
const activeCheck = await serviceRun("systemctl", ["--user", "is-active", "machine-bridge-mcp.service"]);
|
|
382
|
-
const
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
571
|
+
const status = systemdStatusSummary({ installed: definitionPresent, definition: "machine-bridge-mcp.service", result: activeCheck });
|
|
572
|
+
const decision = systemdRemovalDecision({ definitionPresent, disableCode: disable.code, status });
|
|
573
|
+
if (!decision.removable) {
|
|
574
|
+
logger.warn?.("systemd service removal could not be verified; its definition was not removed.");
|
|
575
|
+
return { ok: false, provider: "systemd", path: servicePath, disable, active_check: activeCheck, status, active: status.active, reason: decision.reason };
|
|
576
|
+
}
|
|
577
|
+
if (!removeServiceDefinitionIfCurrent(servicePath, definitionIdentity, "systemd service definition")) {
|
|
578
|
+
logger.warn?.("systemd service definition changed during removal; the replacement was retained.");
|
|
579
|
+
return { ok: false, provider: "systemd", path: servicePath, disable, active_check: activeCheck, status, active: false, reason: "definition_changed" };
|
|
386
580
|
}
|
|
387
|
-
if (existsSync(servicePath)) rmSync(servicePath, { force: true });
|
|
388
581
|
const reload = await serviceRun("systemctl", ["--user", "daemon-reload"]);
|
|
389
|
-
const ok = reload.code === 0
|
|
390
|
-
${disable.stderr}`));
|
|
582
|
+
const ok = reload.code === 0;
|
|
391
583
|
if (ok) logger.info?.("Autostart removed.");
|
|
392
584
|
else logger.warn?.("Autostart removal reported an error.");
|
|
393
|
-
return { ok, provider: "systemd", path: servicePath, disable, active_check: activeCheck, reload, active: false };
|
|
585
|
+
return { ok, provider: "systemd", path: servicePath, disable, active_check: activeCheck, status, reload, active: false, already_absent: decision.alreadyAbsent, reason: ok ? decision.reason : "reload_failed" };
|
|
586
|
+
}
|
|
587
|
+
|
|
588
|
+
export async function stopSystemdService(logger = console, options = {}) {
|
|
589
|
+
const run = typeof options.run === "function" ? options.run : serviceRun;
|
|
590
|
+
const readStatus = typeof options.readStatus === "function" ? options.readStatus : statusSystemd;
|
|
591
|
+
const waitForInactive = typeof options.waitForInactive === "function"
|
|
592
|
+
? options.waitForInactive
|
|
593
|
+
: callback => waitForInactiveStatus(callback);
|
|
594
|
+
const before = await readStatus();
|
|
595
|
+
if (systemdStatusIsInactive(before)) {
|
|
596
|
+
logger.info?.("systemd service is not active");
|
|
597
|
+
return {
|
|
598
|
+
ok: true,
|
|
599
|
+
provider: "systemd",
|
|
600
|
+
installed: before?.installed === true,
|
|
601
|
+
active_before: false,
|
|
602
|
+
active: false,
|
|
603
|
+
restore_required: false,
|
|
604
|
+
already_stopped: true,
|
|
605
|
+
state: before?.state || "inactive",
|
|
606
|
+
};
|
|
607
|
+
}
|
|
608
|
+
if (before?.active !== true && ["unknown", "maintenance"].includes(before?.state)) {
|
|
609
|
+
return {
|
|
610
|
+
ok: false,
|
|
611
|
+
provider: "systemd",
|
|
612
|
+
installed: before?.installed === true,
|
|
613
|
+
active_before: null,
|
|
614
|
+
active: null,
|
|
615
|
+
restore_required: null,
|
|
616
|
+
reason: "status_unavailable",
|
|
617
|
+
status: before,
|
|
618
|
+
};
|
|
619
|
+
}
|
|
620
|
+
const command = await run("systemctl", ["--user", "stop", "machine-bridge-mcp.service"]);
|
|
621
|
+
const after = await waitForInactive(readStatus);
|
|
622
|
+
const inactive = systemdStatusIsInactive(after);
|
|
623
|
+
if (inactive) logger.info?.("systemd service stopped");
|
|
624
|
+
else logger.warn?.("systemd service stop could not be verified");
|
|
625
|
+
return {
|
|
626
|
+
ok: inactive,
|
|
627
|
+
provider: "systemd",
|
|
628
|
+
installed: after?.installed === true,
|
|
629
|
+
active_before: before?.active === true,
|
|
630
|
+
active: inactive ? false : after?.active ?? null,
|
|
631
|
+
restore_required: inactive && systemdStatusRequiresRestore(before),
|
|
632
|
+
already_stopped: false,
|
|
633
|
+
command,
|
|
634
|
+
status: after,
|
|
635
|
+
reason: inactive ? "stopped" : "stop_not_observed",
|
|
636
|
+
};
|
|
637
|
+
}
|
|
638
|
+
|
|
639
|
+
function systemdStatusIsInactive(status) {
|
|
640
|
+
if (status?.active !== false) return false;
|
|
641
|
+
if (["inactive", "failed"].includes(status?.state)) return true;
|
|
642
|
+
return status?.installed === false && status?.state === "unknown";
|
|
643
|
+
}
|
|
644
|
+
function systemdStatusRequiresRestore(status) {
|
|
645
|
+
return status?.active === true || ["activating", "reloading"].includes(status?.state);
|
|
646
|
+
}
|
|
647
|
+
|
|
648
|
+
async function startSystemd(logger) {
|
|
649
|
+
const before = await statusSystemd();
|
|
650
|
+
if (typeof before.active !== "boolean") {
|
|
651
|
+
return { ok: false, provider: "systemd", installed: before.installed === true, active: null, reason: "status_unavailable", status: before };
|
|
652
|
+
}
|
|
653
|
+
if (before.installed !== true) {
|
|
654
|
+
return { ok: false, provider: "systemd", installed: false, active: false, reason: "not_installed", status: before };
|
|
655
|
+
}
|
|
656
|
+
if (before.active) {
|
|
657
|
+
const existing = await waitForStableActiveStatus(statusSystemd);
|
|
658
|
+
if (existing.stable) {
|
|
659
|
+
logger.info?.("systemd service is already running");
|
|
660
|
+
return { ...existing.status, ok: true, active_before: true, already_running: true, reason: "already_running" };
|
|
661
|
+
}
|
|
662
|
+
}
|
|
663
|
+
const command = await serviceRun("systemctl", ["--user", "start", "machine-bridge-mcp.service"]);
|
|
664
|
+
const stability = await waitForStableActiveStatus(statusSystemd);
|
|
665
|
+
const after = stability.status;
|
|
666
|
+
const ok = command.code === 0 && stability.stable;
|
|
667
|
+
if (ok) logger.info?.("systemd service started");
|
|
668
|
+
else logger.warn?.("systemd service failed to start");
|
|
669
|
+
return { ok, provider: "systemd", installed: after.installed, active_before: false, active: after.active, command };
|
|
670
|
+
}
|
|
671
|
+
|
|
672
|
+
async function restartSystemd(logger) {
|
|
673
|
+
const before = await statusSystemd();
|
|
674
|
+
if (typeof before.active !== "boolean") {
|
|
675
|
+
return { ok: false, provider: "systemd", installed: before.installed === true, active: null, restarted: false, reason: "status_unavailable", status: before };
|
|
676
|
+
}
|
|
677
|
+
if (before.installed !== true) {
|
|
678
|
+
return { ok: false, provider: "systemd", installed: false, active: false, restarted: false, reason: "not_installed", status: before };
|
|
679
|
+
}
|
|
680
|
+
const command = await serviceRun("systemctl", ["--user", "restart", "machine-bridge-mcp.service"]);
|
|
681
|
+
const stability = await waitForStableActiveStatus(statusSystemd);
|
|
682
|
+
const after = stability.status;
|
|
683
|
+
const ok = command.code === 0 && stability.stable;
|
|
684
|
+
if (ok) logger.info?.("systemd service restarted");
|
|
685
|
+
else logger.warn?.("systemd service restart could not be verified");
|
|
686
|
+
return { ok, provider: "systemd", installed: after.installed, active: after.active, restarted: ok, command };
|
|
394
687
|
}
|
|
395
688
|
|
|
396
689
|
async function statusSystemd() {
|
|
397
690
|
const servicePath = systemdPath();
|
|
398
|
-
const result = await serviceRun("systemctl", ["--user", "
|
|
399
|
-
return {
|
|
691
|
+
const result = await serviceRun("systemctl", ["--user", "is-active", "machine-bridge-mcp.service"]);
|
|
692
|
+
return systemdStatusSummary({ installed: existsSync(servicePath), definition: "machine-bridge-mcp.service", result });
|
|
400
693
|
}
|
|
401
694
|
|
|
402
695
|
export function systemdUnit(spec) {
|