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/runtime.mjs
CHANGED
|
@@ -1,44 +1,54 @@
|
|
|
1
1
|
import { randomBytes } from "node:crypto";
|
|
2
2
|
import { realpathSync, rmSync } from "node:fs";
|
|
3
|
-
import {
|
|
3
|
+
import { realpath, stat } from "node:fs/promises";
|
|
4
4
|
import { dirname, isAbsolute, relative, resolve, sep } from "node:path";
|
|
5
|
-
import { isRelayReadyContext } from "./relay-connection.mjs";
|
|
5
|
+
import { isRelayReadyContext } from "./relay-connection-classification.mjs";
|
|
6
6
|
import { ProcessSessionManager } from "./process-sessions.mjs";
|
|
7
|
-
import { MAX_CONCURRENT_TOOL_CALLS } from "./execution-limits.mjs";
|
|
7
|
+
import { CONTROL_PLANE_TOOL_NAMES, MAX_CONCURRENT_TOOL_CALLS, RESERVED_CONTROL_TOOL_CALLS, executionGuardrailsSnapshot } from "./execution-limits.mjs";
|
|
8
8
|
export { MAX_COMMAND_BYTES } from "./process-contract.mjs";
|
|
9
9
|
import { normalizePolicy, PolicyGate } from "./tools.mjs";
|
|
10
|
-
import { publicError } from "./errors.mjs";
|
|
10
|
+
import { BridgeError, publicError } from "./errors.mjs";
|
|
11
11
|
import { ProcessTracker } from "./process-tracker.mjs";
|
|
12
12
|
import { CallRegistry } from "./call-registry.mjs";
|
|
13
13
|
import { RuntimeObservability } from "./observability.mjs";
|
|
14
14
|
import { ToolExecutor } from "./tool-executor.mjs";
|
|
15
15
|
import { boundedErrorMessage, ProcessExecutionService } from "./process-execution.mjs";
|
|
16
16
|
import { GitService } from "./git-service.mjs";
|
|
17
|
+
import { FileMutationCoordinator } from "./file-mutation-coordinator.mjs";
|
|
18
|
+
import { createTrustedGitResolver } from "./trusted-git-executable.mjs";
|
|
17
19
|
import { LifecycleController } from "./lifecycle.mjs";
|
|
18
20
|
import { MAX_WRITE_BYTES, sha256, WorkspaceFileService } from "./workspace-file-service.mjs";
|
|
21
|
+
import { projectRuntimeInfo } from "./runtime-info-projection.mjs";
|
|
22
|
+
import { projectOverviewDetail, projectProjectOverview } from "../shared/project-overview-projection.mjs";
|
|
19
23
|
export { MAX_WRITE_BYTES, sha256 } from "./workspace-file-service.mjs";
|
|
20
24
|
import { classifyOperationalError } from "./log.mjs";
|
|
21
|
-
import {
|
|
22
|
-
import { generateRegisteredSshKey } from "./resource-operations.mjs";
|
|
23
|
-
import { expandHome } from "./state.mjs";
|
|
25
|
+
import { ManagedJobManager } from "./managed-jobs.mjs";
|
|
24
26
|
import { AgentContextManager } from "./agent-context.mjs";
|
|
25
27
|
import { AppAutomationManager } from "./app-automation.mjs";
|
|
28
|
+
import { projectApplicationCapabilities } from "./application-capability-projection.mjs";
|
|
29
|
+
import { applicationBackgroundInputConfiguration } from "./macos-background-input.mjs";
|
|
26
30
|
import { BrowserBridgeManager } from "./browser-bridge.mjs";
|
|
31
|
+
import { ComputerUseManager } from "./computer-use.mjs";
|
|
27
32
|
import { CapabilityObserver } from "./capability-observer.mjs";
|
|
28
|
-
import { readBoundedRegularFileSync } from "./secure-file.mjs";
|
|
29
33
|
import { isPlainRecord } from "./records.mjs";
|
|
30
34
|
import { AccountAccessGate } from "./account-access.mjs";
|
|
31
35
|
import { buildProjectOverview, buildRuntimeInfo } from "./runtime-reporting.mjs";
|
|
32
36
|
import { diagnoseRuntime as runRuntimeDiagnostics } from "./runtime-diagnostics.mjs";
|
|
33
37
|
import { bindRuntimeToolHandlers, runtimeToolHandlerNames as registeredRuntimeToolHandlerNames } from "./runtime-tool-handlers.mjs";
|
|
34
38
|
import { OperationAuthorizer } from "./operation-authorization.mjs";
|
|
35
|
-
import {
|
|
39
|
+
import { SecurityAuditLog } from "./security-audit-log.mjs";
|
|
40
|
+
import { delegatedProcessIsolationStatus } from "./delegated-process-sandbox.mjs";
|
|
41
|
+
import { policyForContext } from "./authority-context.mjs";
|
|
42
|
+
import { createRuntimeRelayConnection, normalizeRelayToolCall } from "./runtime-relay.mjs";
|
|
43
|
+
import { handleRuntimeRelayControlMessage } from "./runtime-relay-control.mjs";
|
|
36
44
|
import { RelayCallRecovery } from "./relay-call-recovery.mjs";
|
|
37
|
-
import {
|
|
38
|
-
import {
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
} from "./
|
|
45
|
+
import { RuntimeResourceService } from "./runtime-resource-service.mjs";
|
|
46
|
+
import { assertContainedPath, createRuntimeDir, redactRuntimeErrorMessage } from "./runtime-paths.mjs";
|
|
47
|
+
import { pathEntryIfExists } from "./path-inspection.mjs";
|
|
48
|
+
import { ResourceCoordinator } from "./resource-admission.mjs";
|
|
49
|
+
import { RemoteActivityIdleSleepGuard } from "./remote-activity-idle-sleep-guard.mjs";
|
|
50
|
+
import { runRuntimeDirectProcess, runRuntimeExecCommand, runRuntimeLocalCommand } from "./runtime-process-routing.mjs";
|
|
51
|
+
import { resolveTaskCapabilities as resolveRuntimeTaskCapabilities, sessionBootstrap as buildRuntimeSessionBootstrap } from "./runtime-capabilities.mjs";
|
|
42
52
|
|
|
43
53
|
const SLOW_TOOL_CALL_MS = 30_000;
|
|
44
54
|
|
|
@@ -47,7 +57,7 @@ export function runtimeToolHandlerNames() {
|
|
|
47
57
|
}
|
|
48
58
|
|
|
49
59
|
export class LocalRuntime {
|
|
50
|
-
constructor({ workerUrl = "", deviceIdentity = null, expectedRelayVersion = "", workspace, policy, logger = console, onSuperseded = null, onFatal = null, jobRoot = "",
|
|
60
|
+
constructor({ workerUrl = "", deviceIdentity = null, expectedRelayVersion = "", workspace, policy, logger = console, onSuperseded = null, onFatal = null, jobRoot = "", securityStateRoot = "", resources = {}, resourceStatePath = "", browserStateRoot = "", agentHome = process.env.HOME || process.env.USERPROFILE || "", codexHome = process.env.CODEX_HOME || "", recoverJobs = true, applicationAutomation = {}, deviceRootStatus = null, resolveGitExecutable = null, processResourceWaitMs = undefined, resourceCoordinatorRoot = "", resourceCoordinatorOptions = null }) {
|
|
51
61
|
const remoteWorkerUrl = workerUrl ? String(workerUrl) : "";
|
|
52
62
|
this.workspaceInput = resolve(workspace || process.cwd());
|
|
53
63
|
this.workspace = realpathSync.native ? realpathSync.native(this.workspaceInput) : realpathSync(this.workspaceInput);
|
|
@@ -58,18 +68,27 @@ export class LocalRuntime {
|
|
|
58
68
|
this.logger = logger;
|
|
59
69
|
this.onSuperseded = typeof onSuperseded === "function" ? onSuperseded : null;
|
|
60
70
|
this.resourceStatePath = resourceStatePath ? resolve(resourceStatePath) : "";
|
|
71
|
+
this.deviceRootStatus = deviceRootStatus && typeof deviceRootStatus === "object" ? Object.freeze({ ...deviceRootStatus }) : null;
|
|
61
72
|
this.processTracker = new ProcessTracker();
|
|
73
|
+
this.resourceCoordinator = new ResourceCoordinator({ ...(resourceCoordinatorOptions || {}), ...(resourceCoordinatorRoot ? { root: resourceCoordinatorRoot } : {}) });
|
|
74
|
+
if (processResourceWaitMs !== undefined && (!Number.isInteger(processResourceWaitMs) || processResourceWaitMs < 0)) {
|
|
75
|
+
throw new TypeError("processResourceWaitMs must be a non-negative integer when configured");
|
|
76
|
+
}
|
|
77
|
+
const resourceWaitMs = processResourceWaitMs === undefined ? undefined : Math.min(processResourceWaitMs, 30 * 60_000);
|
|
62
78
|
this.lifecycle = new LifecycleController("local runtime");
|
|
63
79
|
this.observability = new RuntimeObservability();
|
|
64
80
|
this.relayInstanceId = `daemon_${randomBytes(18).toString("base64url")}`;
|
|
65
81
|
this.activeRelayCalls = new Set();
|
|
66
82
|
this.suppressedRelayResults = new Map();
|
|
67
|
-
this.relayResumeSessionId = 0;
|
|
83
|
+
this.relayResumeSessionId = 0; this.relayResumeMissingIds = [];
|
|
84
|
+
this.remoteActivityIdleSleepGuard = new RemoteActivityIdleSleepGuard({ logger: this.logger });
|
|
68
85
|
this.callRegistry = new CallRegistry({
|
|
69
86
|
maximum: MAX_CONCURRENT_TOOL_CALLS,
|
|
87
|
+
reserved: RESERVED_CONTROL_TOOL_CALLS,
|
|
88
|
+
reservedTools: CONTROL_PLANE_TOOL_NAMES,
|
|
70
89
|
onCancel: (record) => {
|
|
71
90
|
this.processSessionManager?.notifyCancellation();
|
|
72
|
-
this.browserBridgeManager?.cancelCall(record.id);
|
|
91
|
+
this.browserBridgeManager?.cancelCall(record.id, record.controller.signal.reason);
|
|
73
92
|
this.processTracker.terminateCall(record.id);
|
|
74
93
|
this.logger.event?.("debug", "tool.call.cancel_requested", {
|
|
75
94
|
call_id: shortCallId(record.id), tool: record.tool, origin: record.origin,
|
|
@@ -77,18 +96,20 @@ export class LocalRuntime {
|
|
|
77
96
|
},
|
|
78
97
|
onFinish: (record) => this.processTracker.releaseCall(record.id),
|
|
79
98
|
});
|
|
80
|
-
this.
|
|
99
|
+
this.fileMutationCoordinator = new FileMutationCoordinator();
|
|
81
100
|
this.capabilityObserver = new CapabilityObserver();
|
|
82
101
|
this.runtimeDir = createRuntimeDir();
|
|
102
|
+
this.resolveGitExecutable = createTrustedGitResolver({ resolve: resolveGitExecutable, workspace: this.workspace, stateRoot: browserStateRoot, runtimeDir: this.runtimeDir, home: agentHome });
|
|
83
103
|
this.workspaceFileService = new WorkspaceFileService({
|
|
84
104
|
workspace: this.workspace,
|
|
85
105
|
policy: this.policy,
|
|
86
106
|
policyGate: this.policyGate,
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
107
|
+
policyForContext: (context) => this.effectivePolicy(context),
|
|
108
|
+
resolveExistingPath: (value, context) => this.resolveExistingPath(value, context),
|
|
109
|
+
resolveWritePath: (value, context) => this.resolveWritePath(value, context),
|
|
110
|
+
displayPath: (value, context) => this.displayPath(value, context),
|
|
90
111
|
throwIfCancelled: (context) => this.throwIfCancelled(context),
|
|
91
|
-
|
|
112
|
+
withMutationPaths: (paths, operation) => this.fileMutationCoordinator.withPaths(paths, operation),
|
|
92
113
|
});
|
|
93
114
|
if (typeof jobRoot !== "string" || !jobRoot.trim()) throw new Error("persistent managed-job root is required");
|
|
94
115
|
this.managedJobManager = new ManagedJobManager({
|
|
@@ -96,31 +117,38 @@ export class LocalRuntime {
|
|
|
96
117
|
workspace: this.workspace,
|
|
97
118
|
policy: this.policy,
|
|
98
119
|
authorizeTool: (tool) => this.policyGate.assert(tool),
|
|
120
|
+
policyForContext: (context) => this.effectivePolicy(context),
|
|
99
121
|
resources,
|
|
100
122
|
resourceStatePath,
|
|
101
123
|
stateRoot: browserStateRoot,
|
|
102
124
|
logger: this.logger,
|
|
103
125
|
recover: recoverJobs,
|
|
126
|
+
runnerEnvironmentOverrides: resourceCoordinatorRoot ? { AGENT_RESOURCE_COORDINATOR_ROOT: resolve(resourceCoordinatorRoot) } : {},
|
|
104
127
|
});
|
|
105
128
|
this.processSessionManager = new ProcessSessionManager({
|
|
106
129
|
workspace: this.workspace,
|
|
107
130
|
policy: this.policy,
|
|
108
131
|
authorizeTool: (tool) => this.policyGate.assert(tool),
|
|
132
|
+
policyForContext: (context) => this.effectivePolicy(context),
|
|
109
133
|
runtimeDir: this.runtimeDir,
|
|
110
134
|
processTracker: this.processTracker,
|
|
111
|
-
|
|
112
|
-
|
|
135
|
+
resourceCoordinator: this.resourceCoordinator,
|
|
136
|
+
resourceWaitMs,
|
|
137
|
+
resolveCwd: async (input, context) => {
|
|
138
|
+
const cwd = await this.resolveExistingPath(input, context);
|
|
113
139
|
if (!(await stat(cwd)).isDirectory()) throw new Error("cwd is not a directory");
|
|
114
140
|
return cwd;
|
|
115
141
|
},
|
|
116
|
-
displayPath: (value) => this.displayPath(value),
|
|
142
|
+
displayPath: (value, context) => this.displayPath(value, context),
|
|
117
143
|
throwIfCancelled: (context) => this.throwIfCancelled(context),
|
|
144
|
+
remoteActivityGuard: this.remoteActivityIdleSleepGuard,
|
|
118
145
|
});
|
|
119
146
|
this.agentContextManager = new AgentContextManager({
|
|
120
147
|
workspace: this.workspace,
|
|
121
148
|
policy: this.policy,
|
|
122
|
-
|
|
123
|
-
|
|
149
|
+
policyForContext: (context) => this.effectivePolicy(context),
|
|
150
|
+
displayPath: (value, context) => this.displayPath(value, context),
|
|
151
|
+
resolveExistingPath: (value, context) => this.resolveExistingPath(value, context),
|
|
124
152
|
throwIfCancelled: (context) => this.throwIfCancelled(context),
|
|
125
153
|
home: agentHome,
|
|
126
154
|
codexHome,
|
|
@@ -129,37 +157,42 @@ export class LocalRuntime {
|
|
|
129
157
|
workspace: this.workspace,
|
|
130
158
|
policy: this.policy,
|
|
131
159
|
policyGate: this.policyGate,
|
|
160
|
+
policyForContext: (context) => this.effectivePolicy(context),
|
|
132
161
|
runtimeDir: this.runtimeDir,
|
|
133
162
|
processTracker: this.processTracker,
|
|
134
|
-
|
|
163
|
+
resourceCoordinator: this.resourceCoordinator,
|
|
164
|
+
resourceWaitMs,
|
|
165
|
+
resolveExistingPath: (value, context) => this.resolveExistingPath(value, context),
|
|
135
166
|
resolveLocalCommand: (args, context) => this.agentContextManager.resolveLocalCommand(args, context),
|
|
136
|
-
displayPath: (value) => this.displayPath(value),
|
|
167
|
+
displayPath: (value, context) => this.displayPath(value, context),
|
|
137
168
|
throwIfCancelled: (context) => this.throwIfCancelled(context),
|
|
138
|
-
retainCompletedOutput: (value) => this.processSessionManager.retainCompletedOutput(value),
|
|
169
|
+
retainCompletedOutput: (value, context) => this.processSessionManager.retainCompletedOutput(value, context),
|
|
139
170
|
});
|
|
140
171
|
this.gitService = new GitService({
|
|
141
|
-
resolveExistingPath: (value) => this.resolveExistingPath(value),
|
|
142
|
-
|
|
143
|
-
|
|
172
|
+
resolveExistingPath: (value, context) => this.resolveExistingPath(value, context),
|
|
173
|
+
resolveWritePath: (value, context) => this.resolveWritePath(value, context),
|
|
174
|
+
displayPath: (value, context) => this.displayPath(value, context),
|
|
175
|
+
runInternalProcess: (...args) => this.processExecutionService.runFixedInternal(...args),
|
|
176
|
+
gitExecutable: () => this.resolveGitExecutable(),
|
|
144
177
|
maximumBytes: MAX_WRITE_BYTES,
|
|
145
178
|
});
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
...applicationAutomation,
|
|
151
|
-
policy: this.policy,
|
|
179
|
+
this.runtimeResourceService = new RuntimeResourceService({
|
|
180
|
+
workspace: this.workspace,
|
|
181
|
+
resourceStatePath: this.resourceStatePath,
|
|
182
|
+
currentResources: () => this.managedJobManager.currentResources(),
|
|
152
183
|
authorizeTool: (tool) => this.policyGate.assert(tool),
|
|
153
|
-
displayPath: (value) => this.displayPath(value),
|
|
154
|
-
runProcess,
|
|
155
|
-
readResourceText,
|
|
156
|
-
throwIfCancelled: (context) => this.throwIfCancelled(context),
|
|
157
184
|
});
|
|
185
|
+
const runProcess = (cmd, argv, timeoutMs, allowFailure, maxOutputBytes, context, cwd, stdin, options) => this.runProcess(cmd, argv, timeoutMs, allowFailure, maxOutputBytes, context, cwd, stdin, options);
|
|
186
|
+
const readResourceText = (name) => this.runtimeResourceService.readText(name);
|
|
187
|
+
const readResourceBinary = (name) => this.runtimeResourceService.readBinary(name);
|
|
188
|
+
this.appAutomationManager = createAppAutomationManager(this, applicationAutomation, runProcess, readResourceText);
|
|
189
|
+
this.securityAudit = new SecurityAuditLog({ root: securityStateRoot });
|
|
158
190
|
this.operationAuthorizer = new OperationAuthorizer({
|
|
159
191
|
workspace: this.workspace,
|
|
160
|
-
root:
|
|
161
|
-
resolveExistingPath: (value) => this.resolveExistingPath(value),
|
|
162
|
-
resolveWritePath: (value) => this.resolveWritePath(value),
|
|
192
|
+
root: securityStateRoot,
|
|
193
|
+
resolveExistingPath: (value, context) => this.resolveExistingPath(value, context),
|
|
194
|
+
resolveWritePath: (value, context) => this.resolveWritePath(value, context),
|
|
195
|
+
protectedRoots: [securityStateRoot, browserStateRoot],
|
|
163
196
|
});
|
|
164
197
|
this.browserBridgeManager = new BrowserBridgeManager({
|
|
165
198
|
policy: this.policy,
|
|
@@ -171,6 +204,12 @@ export class LocalRuntime {
|
|
|
171
204
|
throwIfCancelled: (context) => this.throwIfCancelled(context),
|
|
172
205
|
logger: this.logger,
|
|
173
206
|
});
|
|
207
|
+
this.computerUseManager = new ComputerUseManager({
|
|
208
|
+
authorizeTool: (tool) => this.policyGate.assert(tool),
|
|
209
|
+
browserBridgeManager: this.browserBridgeManager,
|
|
210
|
+
appAutomationManager: this.appAutomationManager,
|
|
211
|
+
throwIfCancelled: (context) => this.throwIfCancelled(context),
|
|
212
|
+
});
|
|
174
213
|
this.toolExecutor = new ToolExecutor({
|
|
175
214
|
handlers: bindRuntimeToolHandlers(this),
|
|
176
215
|
policyGate: this.policyGate,
|
|
@@ -178,8 +217,11 @@ export class LocalRuntime {
|
|
|
178
217
|
operationAuthorizer: this.operationAuthorizer,
|
|
179
218
|
callRegistry: this.callRegistry,
|
|
180
219
|
observability: this.observability,
|
|
220
|
+
securityAudit: this.securityAudit,
|
|
181
221
|
logger: this.logger,
|
|
182
|
-
|
|
222
|
+
onAuthorizedRelayActivityStart: () => this.remoteActivityIdleSleepGuard.beginActivity(),
|
|
223
|
+
onAuthorizedRelayActivityEnd: () => this.remoteActivityIdleSleepGuard.endActivity(),
|
|
224
|
+
safeMessage: (error, args, context) => this.safeErrorMessage(error, args, context),
|
|
183
225
|
slowMs: SLOW_TOOL_CALL_MS,
|
|
184
226
|
});
|
|
185
227
|
this.relay = createRuntimeRelayConnection(this, {
|
|
@@ -195,15 +237,25 @@ export class LocalRuntime {
|
|
|
195
237
|
terminate: () => this.terminateActiveProcesses("SIGTERM", true),
|
|
196
238
|
});
|
|
197
239
|
}
|
|
198
|
-
|
|
199
240
|
tools() { return this.policyGate.names().filter((name) => name !== "server_info"); }
|
|
200
241
|
|
|
201
|
-
|
|
202
|
-
|
|
242
|
+
effectiveToolNames(context = {}) {
|
|
243
|
+
const policyNames = this.policyGate.names();
|
|
244
|
+
const principal = context?.authority?.principal;
|
|
245
|
+
if (principal?.kind !== "account") return policyNames;
|
|
246
|
+
const accountNames = new Set(this.accountAccessGate.names(principal.role));
|
|
247
|
+
return policyNames.filter((name) => accountNames.has(name));
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
serverInfo(args = {}, context = {}) { return projectRuntimeInfo(this.runtimeInfo(context), args.detail); }
|
|
251
|
+
|
|
252
|
+
runtimeInfo(context = {}) {
|
|
253
|
+
const info = buildRuntimeInfo({
|
|
203
254
|
workspace: this.workspace,
|
|
204
|
-
displayPath: (value) => this.displayPath(value),
|
|
205
|
-
policy: this.
|
|
206
|
-
toolNames: this.
|
|
255
|
+
displayPath: (value) => this.displayPath(value, context),
|
|
256
|
+
policy: this.effectivePolicy(context),
|
|
257
|
+
toolNames: this.effectiveToolNames(context).filter((name) => name !== "server_info"),
|
|
258
|
+
daemonToolNames: this.tools(),
|
|
207
259
|
capabilityObserver: this.capabilityObserver,
|
|
208
260
|
observability: this.observability,
|
|
209
261
|
callRegistry: this.callRegistry,
|
|
@@ -213,7 +265,17 @@ export class LocalRuntime {
|
|
|
213
265
|
processTracker: this.processTracker,
|
|
214
266
|
processSessionManager: this.processSessionManager,
|
|
215
267
|
managedJobManager: this.managedJobManager,
|
|
268
|
+
securityAudit: this.securityAudit.snapshot(), deviceRootStatus: this.deviceRootStatus, context,
|
|
216
269
|
});
|
|
270
|
+
return {
|
|
271
|
+
...info,
|
|
272
|
+
trust: {
|
|
273
|
+
...info.trust,
|
|
274
|
+
daemon_session: { ephemeral: true, certificate_lifetime_seconds: 86400, reconnect_prompts: false },
|
|
275
|
+
delegated_process_isolation: delegatedProcessIsolationStatus(),
|
|
276
|
+
routine_operation_prompts: false,
|
|
277
|
+
},
|
|
278
|
+
};
|
|
217
279
|
}
|
|
218
280
|
|
|
219
281
|
async start() {
|
|
@@ -225,27 +287,34 @@ export class LocalRuntime {
|
|
|
225
287
|
});
|
|
226
288
|
}
|
|
227
289
|
try {
|
|
228
|
-
await this.relay.start();
|
|
290
|
+
const relayReady = await this.relay.start();
|
|
291
|
+
if (this.lifecycle.snapshot().state !== "starting") return;
|
|
292
|
+
if (relayReady !== true) throw new BridgeError("cancelled", "runtime relay startup was cancelled", { retryable: true });
|
|
229
293
|
this.lifecycle.markRunning();
|
|
230
294
|
} catch (error) {
|
|
295
|
+
if (this.lifecycle.snapshot().state !== "starting") return;
|
|
231
296
|
this.lifecycle.markFailed(error);
|
|
232
297
|
throw error;
|
|
233
298
|
}
|
|
234
299
|
}
|
|
235
300
|
|
|
236
|
-
stop() {
|
|
301
|
+
async stop() {
|
|
237
302
|
if (!this.lifecycle.beginStop()) return;
|
|
238
303
|
try {
|
|
239
304
|
this.relay?.stop();
|
|
240
305
|
this.relayCallRecovery.stop();
|
|
241
|
-
this.callRegistry.
|
|
242
|
-
this.
|
|
243
|
-
this.processSessionManager.
|
|
306
|
+
await this.callRegistry.cancelAllAndWait("runtime stopped");
|
|
307
|
+
await this.processTracker.drain("SIGKILL");
|
|
308
|
+
await this.processSessionManager.clearAndWait();
|
|
309
|
+
this.remoteActivityIdleSleepGuard.stop();
|
|
310
|
+
await this.securityAudit.close();
|
|
244
311
|
this.browserBridgeManager?.stop();
|
|
245
312
|
rmSync(this.runtimeDir, { recursive: true, force: true });
|
|
246
|
-
}
|
|
247
|
-
this.lifecycle.
|
|
313
|
+
} catch (error) {
|
|
314
|
+
this.lifecycle.markStopFailed(error);
|
|
315
|
+
throw error;
|
|
248
316
|
}
|
|
317
|
+
this.lifecycle.markStopped();
|
|
249
318
|
}
|
|
250
319
|
|
|
251
320
|
send(value) {
|
|
@@ -255,70 +324,28 @@ export class LocalRuntime {
|
|
|
255
324
|
async handleMessage(raw, relayContext = {}) {
|
|
256
325
|
let message;
|
|
257
326
|
try { message = JSON.parse(raw); } catch {
|
|
258
|
-
this.handleRelayProtocolViolation("invalid_server_json");
|
|
327
|
+
this.handleRelayProtocolViolation("invalid_server_json", relayContext);
|
|
259
328
|
return;
|
|
260
329
|
}
|
|
261
|
-
if (!isPlainRecord(message))
|
|
262
|
-
|
|
263
|
-
return;
|
|
330
|
+
if (!isPlainRecord(message)) return this.handleRelayProtocolViolation("invalid_server_message", relayContext);
|
|
331
|
+
if (message.type === "tool_call") {
|
|
332
|
+
if (!isRelayReadyContext(relayContext, this.relay)) return this.handleRelayProtocolViolation("tool_call_before_ready", relayContext);
|
|
333
|
+
return this.handleRelayToolCall(message, relayContext);
|
|
264
334
|
}
|
|
265
|
-
if (this.handleRelayControlMessage(message, relayContext)) return;
|
|
335
|
+
if (await this.handleRelayControlMessage(message, relayContext)) return;
|
|
266
336
|
if (message.type === "relay_probe") {
|
|
267
|
-
if (isRelayReadyContext(relayContext, this.relay)) return this.handleRelayProtocolViolation("unexpected_relay_probe");
|
|
337
|
+
if (isRelayReadyContext(relayContext, this.relay)) return this.handleRelayProtocolViolation("unexpected_relay_probe", relayContext);
|
|
268
338
|
this.handleRelayProbe(message, relayContext);
|
|
269
339
|
return;
|
|
270
340
|
}
|
|
271
|
-
|
|
272
|
-
if (!isRelayReadyContext(relayContext, this.relay)) return this.handleRelayProtocolViolation("tool_call_before_ready");
|
|
273
|
-
await this.handleRelayToolCall(message);
|
|
341
|
+
return this.handleRelayProtocolViolation("unexpected_server_message_type", relayContext);
|
|
274
342
|
}
|
|
275
343
|
|
|
276
|
-
handleRelayControlMessage(message, relayContext = {}) {
|
|
277
|
-
if (message.type === "welcome") {
|
|
278
|
-
this.relay?.observeWelcome(message);
|
|
279
|
-
return true;
|
|
280
|
-
}
|
|
281
|
-
if (message.type === "hello_ack") {
|
|
282
|
-
this.relayResumeSessionId = 0;
|
|
283
|
-
this.relay?.acknowledge(message);
|
|
284
|
-
return true;
|
|
285
|
-
}
|
|
286
|
-
if (message.type === "resume_calls") {
|
|
287
|
-
const sessionId = Number(relayContext.sessionId) || 0;
|
|
288
|
-
const resume = normalizeRelayResumeCalls(message);
|
|
289
|
-
if (!resume.ok || !sessionId || relayContext.authenticated !== true || relayContext.ready === true) {
|
|
290
|
-
this.handleRelayProtocolViolation("invalid_resume_calls");
|
|
291
|
-
return true;
|
|
292
|
-
}
|
|
293
|
-
this.reconcileRelayCalls(resume.ids);
|
|
294
|
-
this.relayResumeSessionId = sessionId;
|
|
295
|
-
return true;
|
|
296
|
-
}
|
|
297
|
-
if (message.type === "ready_ack") {
|
|
298
|
-
const sessionId = Number(relayContext.sessionId) || 0;
|
|
299
|
-
if (!sessionId || sessionId !== this.relayResumeSessionId) {
|
|
300
|
-
this.handleRelayProtocolViolation("resume_calls_required");
|
|
301
|
-
return true;
|
|
302
|
-
}
|
|
303
|
-
this.relay?.confirmReady(message);
|
|
304
|
-
this.relayResumeSessionId = 0;
|
|
305
|
-
return true;
|
|
306
|
-
}
|
|
307
|
-
if (message.type === "pong") return true;
|
|
308
|
-
if (message.type === "error") {
|
|
309
|
-
this.relay?.handleServerError(message);
|
|
310
|
-
return true;
|
|
311
|
-
}
|
|
312
|
-
if (message.type === "cancel_call") {
|
|
313
|
-
if (typeof message.id === "string") this.cancelRelayCall(message.id, "caller_cancelled");
|
|
314
|
-
return true;
|
|
315
|
-
}
|
|
316
|
-
return false;
|
|
317
|
-
}
|
|
344
|
+
handleRelayControlMessage(message, relayContext = {}) { return handleRuntimeRelayControlMessage(this, message, relayContext); }
|
|
318
345
|
|
|
319
|
-
handleRelayProtocolViolation(errorCode) {
|
|
346
|
+
handleRelayProtocolViolation(errorCode, relayContext = {}) {
|
|
320
347
|
if (this.relay) {
|
|
321
|
-
this.relay.handleServerError({ type: "error", error: errorCode });
|
|
348
|
+
this.relay.handleServerError({ type: "error", error: errorCode }, relayContext);
|
|
322
349
|
return;
|
|
323
350
|
}
|
|
324
351
|
this.logger.error?.("remote relay protocol error; upgrade and redeploy both components, then restart the daemon");
|
|
@@ -327,12 +354,14 @@ export class LocalRuntime {
|
|
|
327
354
|
handleRelayProbe(message, relayContext = {}) {
|
|
328
355
|
const id = typeof message?.id === "string" && /^probe_[A-Za-z0-9_-]{8,240}$/.test(message.id) ? message.id : "";
|
|
329
356
|
const relaySessionId = Number(relayContext.sessionId) || 0;
|
|
330
|
-
if (!id || !relaySessionId) return this.handleRelayProtocolViolation("invalid_relay_probe");
|
|
357
|
+
if (!id || !relaySessionId) return this.handleRelayProtocolViolation("invalid_relay_probe", relayContext);
|
|
331
358
|
const outcome = this.relay?.sendForSession?.({ type: "relay_probe_result", id }, relaySessionId);
|
|
332
|
-
if (!outcome?.ok
|
|
359
|
+
if (!outcome?.ok && !["send_failed", "transport_unavailable", "session_ended"].includes(outcome?.reason)) {
|
|
360
|
+
this.handleRelayProtocolViolation("relay_probe_delivery_failed");
|
|
361
|
+
}
|
|
333
362
|
}
|
|
334
363
|
|
|
335
|
-
async handleRelayToolCall(message) {
|
|
364
|
+
async handleRelayToolCall(message, relayContext = {}) {
|
|
336
365
|
const envelope = normalizeRelayToolCall(message);
|
|
337
366
|
if (!envelope.ok) {
|
|
338
367
|
this.logger.warn?.("Received an invalid tool request from the relay; the request was rejected.");
|
|
@@ -348,7 +377,7 @@ export class LocalRuntime {
|
|
|
348
377
|
return;
|
|
349
378
|
}
|
|
350
379
|
if (this.activeRelayCalls.has(envelope.id)) {
|
|
351
|
-
this.handleRelayProtocolViolation("duplicate_tool_call_id");
|
|
380
|
+
this.handleRelayProtocolViolation("duplicate_tool_call_id", relayContext);
|
|
352
381
|
return;
|
|
353
382
|
}
|
|
354
383
|
this.activeRelayCalls.add(envelope.id);
|
|
@@ -400,14 +429,17 @@ export class LocalRuntime {
|
|
|
400
429
|
}
|
|
401
430
|
|
|
402
431
|
reconcileRelayCalls(resumedCallIds) {
|
|
403
|
-
this.relayCallRecovery.reconcile(
|
|
432
|
+
return this.relayCallRecovery.reconcile(
|
|
404
433
|
resumedCallIds,
|
|
405
434
|
(callId) => this.cancelRelayCall(callId, "caller_no_longer_waiting"),
|
|
406
435
|
);
|
|
407
436
|
}
|
|
408
437
|
|
|
438
|
+
relayOwnedCallIds() { return this.relayCallRecovery?.ownedCallIds?.() ?? [...this.activeRelayCalls]; }
|
|
439
|
+
|
|
409
440
|
handleRelayDisconnect() {
|
|
410
441
|
this.relayResumeSessionId = 0;
|
|
442
|
+
this.relayResumeMissingIds = [];
|
|
411
443
|
this.relayCallRecovery.disconnected();
|
|
412
444
|
}
|
|
413
445
|
|
|
@@ -426,21 +458,25 @@ export class LocalRuntime {
|
|
|
426
458
|
});
|
|
427
459
|
}
|
|
428
460
|
|
|
429
|
-
async projectOverview(context = {}) {
|
|
430
|
-
|
|
461
|
+
async projectOverview(args = {}, context = {}) {
|
|
462
|
+
const effectivePolicy = this.effectivePolicy(context);
|
|
463
|
+
const overview = await buildProjectOverview({
|
|
431
464
|
workspace: this.workspace,
|
|
432
|
-
displayPath: (value) => this.displayPath(value),
|
|
433
|
-
policy:
|
|
434
|
-
toolNames: this.
|
|
465
|
+
displayPath: (value) => this.displayPath(value, context),
|
|
466
|
+
policy: effectivePolicy,
|
|
467
|
+
toolNames: this.effectiveToolNames(context).filter((name) => name !== "server_info"),
|
|
468
|
+
daemonPolicy: this.policy,
|
|
469
|
+
daemonToolNames: this.tools(),
|
|
435
470
|
capabilityObserver: this.capabilityObserver,
|
|
436
471
|
listTopLevel: (callContext) => this.listDir(".", callContext),
|
|
437
|
-
|
|
438
|
-
safeErrorMessage: (error) => this.safeErrorMessage(error),
|
|
472
|
+
resolveGitRoot: async (callContext) => (await this.gitService.context(".", callContext)).root || "",
|
|
473
|
+
safeErrorMessage: (error) => this.safeErrorMessage(error, {}, context),
|
|
439
474
|
throwIfCancelled: (callContext) => this.throwIfCancelled(callContext),
|
|
440
475
|
}, context);
|
|
476
|
+
return projectProjectOverview(overview, projectOverviewDetail(args));
|
|
441
477
|
}
|
|
442
478
|
|
|
443
|
-
listRoots() { return this.workspaceFileService.listRoots(); }
|
|
479
|
+
listRoots(context = {}) { return this.workspaceFileService.listRoots(context); }
|
|
444
480
|
|
|
445
481
|
listDir(pathValue, context = {}) { return this.workspaceFileService.listDir(pathValue, context); }
|
|
446
482
|
|
|
@@ -474,51 +510,35 @@ export class LocalRuntime {
|
|
|
474
510
|
return this.gitService.show(args, context);
|
|
475
511
|
}
|
|
476
512
|
|
|
513
|
+
gitCommit(args = {}, context = {}) {
|
|
514
|
+
return this.gitService.commit(args, context);
|
|
515
|
+
}
|
|
516
|
+
|
|
477
517
|
async diagnoseRuntime(context = {}) {
|
|
478
518
|
return runRuntimeDiagnostics({
|
|
479
519
|
policy: this.policy,
|
|
480
520
|
runtimeDir: this.runtimeDir,
|
|
481
521
|
workspace: this.workspace,
|
|
482
|
-
|
|
483
|
-
probeShell: (callContext) => this.processExecutionService.probeShell(callContext),
|
|
522
|
+
runFixedInternal: (...args) => this.processExecutionService.runFixedInternal(...args),
|
|
523
|
+
probeShell: (callContext, timeoutMs) => this.processExecutionService.probeShell(callContext, timeoutMs),
|
|
484
524
|
managedJobManager: this.managedJobManager,
|
|
525
|
+
resourceCoordinatorSnapshot: () => this.resourceCoordinator.snapshot({ cwd: this.workspace }),
|
|
526
|
+
relayStatus: () => this.relay?.status?.() || null,
|
|
527
|
+
controlPlaneState: {
|
|
528
|
+
lifecycle: this.lifecycle.snapshot(),
|
|
529
|
+
inFlightCalls: this.callRegistry.snapshot(),
|
|
530
|
+
processes: this.processTracker.snapshot(),
|
|
531
|
+
executionGuardrails: executionGuardrailsSnapshot(),
|
|
532
|
+
securityAudit: this.securityAudit.snapshot(),
|
|
533
|
+
idleSleepGuard: this.remoteActivityIdleSleepGuard.snapshot(),
|
|
534
|
+
},
|
|
485
535
|
throwIfCancelled: (callContext) => this.throwIfCancelled(callContext),
|
|
486
536
|
}, context);
|
|
487
537
|
}
|
|
488
538
|
|
|
489
539
|
async generateSshKeyResource(args = {}, context = {}) {
|
|
490
540
|
this.throwIfCancelled(context);
|
|
491
|
-
this.
|
|
492
|
-
if (!this.resourceStatePath) throw new Error("local resource state is unavailable in this runtime");
|
|
493
|
-
const home = process.env.HOME || process.env.USERPROFILE;
|
|
494
|
-
if (!home) throw new Error("HOME or USERPROFILE is required to choose a default SSH key path");
|
|
495
|
-
const target = args.path
|
|
496
|
-
? resolve(expandHome(String(args.path)))
|
|
497
|
-
: resolve(home, ".ssh", `machine-mcp-${args.name}-ed25519`);
|
|
498
|
-
const key = await generateRegisteredSshKey({
|
|
499
|
-
workspace: this.workspace,
|
|
500
|
-
stateDir: stateRootFromProfileStatePath(this.resourceStatePath),
|
|
501
|
-
name: args.name,
|
|
502
|
-
targetPath: target,
|
|
503
|
-
comment: args.comment || `machine-mcp:${args.name}`,
|
|
504
|
-
});
|
|
505
|
-
const exposePaths = args.expose_paths === true;
|
|
506
|
-
return {
|
|
507
|
-
name: key.name,
|
|
508
|
-
created: key.created,
|
|
509
|
-
registered: key.registered,
|
|
510
|
-
fingerprint: key.fingerprint,
|
|
511
|
-
key_type: key.keyType,
|
|
512
|
-
private_mode: key.privateMode,
|
|
513
|
-
public_mode: key.publicMode,
|
|
514
|
-
private_key_content_exposed: key.privateKeyContentExposed,
|
|
515
|
-
available_to_new_jobs_immediately: key.availableToNewJobsImmediately,
|
|
516
|
-
paths_exposed: exposePaths,
|
|
517
|
-
...(exposePaths ? {
|
|
518
|
-
private_key_path: resolve(key.privateKeyPath),
|
|
519
|
-
public_key_path: resolve(key.publicKeyPath),
|
|
520
|
-
} : {}),
|
|
521
|
-
};
|
|
541
|
+
return this.runtimeResourceService.generateSshKey(args);
|
|
522
542
|
}
|
|
523
543
|
|
|
524
544
|
async sessionBootstrap(args = {}, context = {}) {
|
|
@@ -526,7 +546,8 @@ export class LocalRuntime {
|
|
|
526
546
|
agentContextManager: this.agentContextManager,
|
|
527
547
|
appAutomationManager: this.appAutomationManager,
|
|
528
548
|
capabilityObserver: this.capabilityObserver,
|
|
529
|
-
policy: this.
|
|
549
|
+
policy: this.effectivePolicy(context),
|
|
550
|
+
availableTools: this.effectiveToolNames(context),
|
|
530
551
|
}, args, context);
|
|
531
552
|
}
|
|
532
553
|
|
|
@@ -535,51 +556,54 @@ export class LocalRuntime {
|
|
|
535
556
|
agentContextManager: this.agentContextManager,
|
|
536
557
|
appAutomationManager: this.appAutomationManager,
|
|
537
558
|
capabilityObserver: this.capabilityObserver,
|
|
538
|
-
policy: this.
|
|
559
|
+
policy: this.effectivePolicy(context),
|
|
560
|
+
availableTools: this.effectiveToolNames(context),
|
|
539
561
|
}, args, context);
|
|
540
562
|
}
|
|
541
563
|
|
|
542
|
-
|
|
543
|
-
const registry = this.managedJobManager.currentResources();
|
|
544
|
-
const resource = Object.hasOwn(registry, name) ? registry[name] : null;
|
|
545
|
-
if (!resource) throw new Error(`unknown local resource: ${name}`);
|
|
546
|
-
const inspected = inspectResourceFile(resource.path, { allowInsecurePermissions: resource.allowInsecurePermissions === true });
|
|
547
|
-
if (inspected.size > 1024 * 1024) throw new Error("local resource exceeds 1 MiB browser injection limit");
|
|
548
|
-
return { buffer: readBoundedRegularFileSync(resource.path, 1024 * 1024), path: resource.path, size: inspected.size };
|
|
549
|
-
}
|
|
564
|
+
runDirectProcess(args, context = {}) { return runRuntimeDirectProcess(this, args, context); }
|
|
550
565
|
|
|
551
|
-
|
|
552
|
-
const { buffer } = this.readLocalResourceBinary(name);
|
|
553
|
-
try {
|
|
554
|
-
return new TextDecoder("utf-8", { fatal: true }).decode(buffer);
|
|
555
|
-
} catch {
|
|
556
|
-
throw new Error(`local resource is not valid UTF-8 text: ${name}`);
|
|
557
|
-
}
|
|
558
|
-
}
|
|
566
|
+
runLocalCommand(args, context = {}) { return runRuntimeLocalCommand(this, args, context); }
|
|
559
567
|
|
|
560
|
-
|
|
561
|
-
return this.processExecutionService.runDirect(args, context);
|
|
562
|
-
}
|
|
568
|
+
execCommand(args, context = {}) { return runRuntimeExecCommand(this, args, context); }
|
|
563
569
|
|
|
564
|
-
|
|
565
|
-
|
|
570
|
+
terminateActiveProcesses(signal = "SIGTERM", escalate = false) {
|
|
571
|
+
this.processExecutionService.terminateAll(signal, escalate);
|
|
566
572
|
}
|
|
567
573
|
|
|
568
|
-
|
|
569
|
-
|
|
574
|
+
async applyAuthorityRevocation(revocation) {
|
|
575
|
+
let calls = 0; let sessions = 0; let jobs = 0;
|
|
576
|
+
const failures = [];
|
|
577
|
+
let sessionRevocation = null;
|
|
578
|
+
try { calls = this.callRegistry.cancelAuthority(revocation); } catch (error) { failures.push(error); }
|
|
579
|
+
try { sessionRevocation = Promise.resolve(this.processSessionManager.revokeAuthority(revocation)); }
|
|
580
|
+
catch (error) { failures.push(error); }
|
|
581
|
+
try { jobs = this.managedJobManager.revokeAuthority(revocation); } catch (error) { failures.push(error); }
|
|
582
|
+
if (sessionRevocation) {
|
|
583
|
+
try { sessions = await sessionRevocation; } catch (error) { failures.push(error); }
|
|
584
|
+
}
|
|
585
|
+
if (failures.length) {
|
|
586
|
+
throw new BridgeError("unavailable", "local authority revocation was incomplete; retained revocation must be retried", {
|
|
587
|
+
cause: new AggregateError(failures, "local authority revocation failures"), retryable: true,
|
|
588
|
+
});
|
|
589
|
+
}
|
|
590
|
+
this.logger.event?.("debug", "authority.revocation.applied", {
|
|
591
|
+
calls_cancelled: calls, process_sessions_revoked: sessions, managed_jobs_cancelled: jobs,
|
|
592
|
+
}, "Revoked authority removed local execution ownership");
|
|
593
|
+
return { calls_cancelled: calls, process_sessions_revoked: sessions, managed_jobs_cancelled: jobs };
|
|
570
594
|
}
|
|
571
595
|
|
|
572
|
-
|
|
573
|
-
this.processExecutionService.
|
|
596
|
+
runProcess(cmd, args, timeoutMs, allowFailure = false, maxOutputBytes = 512 * 1024, context = {}, cwd = this.workspace, stdin = null, options = {}) {
|
|
597
|
+
return this.processExecutionService.run(cmd, args, timeoutMs, allowFailure, maxOutputBytes, context, cwd, stdin, options);
|
|
574
598
|
}
|
|
575
599
|
|
|
576
|
-
|
|
577
|
-
return
|
|
600
|
+
effectivePolicy(context = {}) {
|
|
601
|
+
return policyForContext(context, this.policy);
|
|
578
602
|
}
|
|
579
603
|
|
|
580
604
|
resolvePath(inputPath = ".") {
|
|
581
605
|
const raw = String(inputPath || ".");
|
|
582
|
-
if (raw.includes("\0")) throw new
|
|
606
|
+
if (raw.includes("\0")) throw new BridgeError("invalid_request", "path contains a NUL byte", { details: { reason: "nul_byte" } });
|
|
583
607
|
return isAbsolute(raw) ? resolve(raw) : resolve(this.workspaceInput, raw);
|
|
584
608
|
}
|
|
585
609
|
|
|
@@ -599,41 +623,41 @@ export class LocalRuntime {
|
|
|
599
623
|
return this.workspaceCanonicalPromise;
|
|
600
624
|
}
|
|
601
625
|
|
|
602
|
-
async resolveExistingPath(inputPath = ".") {
|
|
626
|
+
async resolveExistingPath(inputPath = ".", context = {}) {
|
|
603
627
|
const candidate = this.resolvePath(inputPath);
|
|
604
628
|
const [workspace, canonical] = await Promise.all([this.canonicalWorkspace(), realpath(candidate)]);
|
|
605
|
-
if (!this.
|
|
629
|
+
if (!this.effectivePolicy(context).unrestrictedPaths) assertContainedPath(workspace, canonical);
|
|
606
630
|
return canonical;
|
|
607
631
|
}
|
|
608
632
|
|
|
609
|
-
async resolveWritePath(inputPath = ".") {
|
|
633
|
+
async resolveWritePath(inputPath = ".", context = {}) {
|
|
610
634
|
const candidate = this.resolvePath(inputPath);
|
|
611
|
-
const candidateInfo = await
|
|
612
|
-
if (candidateInfo?.isSymbolicLink()) throw new
|
|
635
|
+
const candidateInfo = await pathEntryIfExists(candidate);
|
|
636
|
+
if (candidateInfo?.isSymbolicLink()) throw new BridgeError("conflict", "refusing to overwrite a symbolic link", { details: { reason: "symbolic_link" } });
|
|
613
637
|
let ancestor = candidate;
|
|
614
|
-
while (!(await
|
|
638
|
+
while (!(await pathEntryIfExists(ancestor))) {
|
|
615
639
|
const parent = dirname(ancestor);
|
|
616
640
|
if (parent === ancestor) break;
|
|
617
641
|
ancestor = parent;
|
|
618
642
|
}
|
|
619
643
|
const [workspace, canonicalAncestor] = await Promise.all([this.canonicalWorkspace(), realpath(ancestor)]);
|
|
620
|
-
if (!this.
|
|
644
|
+
if (!this.effectivePolicy(context).unrestrictedPaths) assertContainedPath(workspace, canonicalAncestor);
|
|
621
645
|
const suffix = relative(ancestor, candidate);
|
|
622
646
|
return suffix ? resolve(canonicalAncestor, suffix) : canonicalAncestor;
|
|
623
647
|
}
|
|
624
648
|
|
|
625
|
-
displayPath(fullPath) {
|
|
649
|
+
displayPath(fullPath, context = {}) {
|
|
626
650
|
const absolute = resolve(fullPath);
|
|
627
|
-
if (this.
|
|
651
|
+
if (this.effectivePolicy(context).exposeAbsolutePaths) return absolute;
|
|
628
652
|
const shown = relative(this.workspace, absolute);
|
|
629
653
|
const insideWorkspace = shown === "" || (!shown.startsWith(`..${sep}`) && shown !== ".." && !isAbsolute(shown));
|
|
630
654
|
if (insideWorkspace) return shown ? shown.split(sep).join("/") : ".";
|
|
631
655
|
return `<external-path:${sha256(absolute).slice(0, 12)}>`;
|
|
632
656
|
}
|
|
633
657
|
|
|
634
|
-
safeErrorMessage(error, toolArgs = {}) {
|
|
658
|
+
safeErrorMessage(error, toolArgs = {}, context = {}) {
|
|
635
659
|
const message = boundedErrorMessage(error);
|
|
636
|
-
if (this.
|
|
660
|
+
if (this.effectivePolicy(context).exposeAbsolutePaths) return message;
|
|
637
661
|
return redactRuntimeErrorMessage(message, {
|
|
638
662
|
error,
|
|
639
663
|
toolArgs,
|
|
@@ -641,23 +665,35 @@ export class LocalRuntime {
|
|
|
641
665
|
workspaceInput: this.workspaceInput,
|
|
642
666
|
runtimeDir: this.runtimeDir,
|
|
643
667
|
home: process.env.HOME || process.env.USERPROFILE || "",
|
|
644
|
-
displayPath: (value) => this.displayPath(value),
|
|
668
|
+
displayPath: (value) => this.displayPath(value, context),
|
|
645
669
|
});
|
|
646
670
|
}
|
|
647
671
|
|
|
648
672
|
throwIfCancelled(context = {}) {
|
|
649
673
|
this.callRegistry.throwIfCancelled(context);
|
|
650
674
|
}
|
|
675
|
+
}
|
|
651
676
|
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
677
|
+
function createAppAutomationManager(runtime, applicationAutomation, runProcess, readResourceText) {
|
|
678
|
+
const { backgroundVisualBackend, backgroundInputService } = applicationBackgroundInputConfiguration(
|
|
679
|
+
applicationAutomation, runProcess, runtime.runtimeDir,
|
|
680
|
+
);
|
|
681
|
+
return new AppAutomationManager({
|
|
682
|
+
...applicationAutomation,
|
|
683
|
+
backgroundVisualBackend,
|
|
684
|
+
backgroundInputService,
|
|
685
|
+
policy: runtime.policy,
|
|
686
|
+
authorizeTool: (tool) => runtime.policyGate.assert(tool),
|
|
687
|
+
displayPath: (value, context) => runtime.displayPath(value, context),
|
|
688
|
+
projectCapabilities: (capabilities, context) => projectRuntimeApplicationCapabilities(runtime, capabilities, context),
|
|
689
|
+
runProcess,
|
|
690
|
+
readResourceText,
|
|
691
|
+
throwIfCancelled: (context) => runtime.throwIfCancelled(context),
|
|
692
|
+
});
|
|
659
693
|
}
|
|
660
694
|
|
|
695
|
+
function projectRuntimeApplicationCapabilities(runtime, capabilities, context) { const available = new Set(runtime.effectiveToolNames(context)); return projectApplicationCapabilities(capabilities, (tool) => available.has(tool)); }
|
|
696
|
+
|
|
661
697
|
function shortCallId(value) {
|
|
662
698
|
return String(value || "").slice(0, 20);
|
|
663
699
|
}
|