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.
Files changed (473) hide show
  1. package/CHANGELOG.md +1142 -0
  2. package/CONTRIBUTING.md +23 -25
  3. package/GOVERNANCE.md +2 -2
  4. package/README.md +58 -20
  5. package/SECURITY.md +161 -120
  6. package/SUPPORT.md +1 -1
  7. package/browser-extension/broker-auth.js +83 -0
  8. package/browser-extension/broker-liveness.js +35 -0
  9. package/browser-extension/browser-error-boundary.js +96 -0
  10. package/browser-extension/browser-operations.js +1456 -101
  11. package/browser-extension/devtools-input.js +195 -34
  12. package/browser-extension/devtools-observation.js +429 -0
  13. package/browser-extension/devtools-session.js +48 -0
  14. package/browser-extension/manifest.json +4 -3
  15. package/browser-extension/page-automation.js +578 -118
  16. package/browser-extension/pairing-bootstrap.js +42 -0
  17. package/browser-extension/pairing.js +28 -12
  18. package/browser-extension/service-worker.js +126 -106
  19. package/docs/AGENT_CONTEXT.md +13 -10
  20. package/docs/ARCHITECTURE.md +159 -67
  21. package/docs/AUDIT.md +1302 -4
  22. package/docs/CLIENTS.md +19 -6
  23. package/docs/COMPUTER_USE.md +297 -0
  24. package/docs/ENGINEERING.md +72 -13
  25. package/docs/GETTING_STARTED.md +18 -20
  26. package/docs/LOCAL_AUTHORIZATION.md +115 -72
  27. package/docs/LOCAL_AUTOMATION.md +27 -21
  28. package/docs/LOGGING.md +40 -19
  29. package/docs/MANAGED_JOBS.md +37 -34
  30. package/docs/MULTI_ACCOUNT.md +98 -37
  31. package/docs/OPERATIONS.md +145 -51
  32. package/docs/OVERVIEW.md +14 -11
  33. package/docs/POLICY_REFERENCE.md +71 -3
  34. package/docs/PRIVACY.md +41 -2
  35. package/docs/PROJECT_STANDARDS.md +29 -6
  36. package/docs/RELEASING.md +238 -64
  37. package/docs/TESTING.md +150 -39
  38. package/docs/THREAT_MODEL.md +164 -67
  39. package/docs/TOOL_REFERENCE.md +653 -60
  40. package/docs/UPGRADING.md +78 -18
  41. package/native/macos/MachineBridgeBackgroundInput.swift +1051 -0
  42. package/native/macos/MachineBridgeBackgroundInputSmokeFixture.swift +295 -0
  43. package/native/macos/MachineBridgeTrustBroker.swift +233 -0
  44. package/package.json +94 -16
  45. package/scripts/accepted-candidate-tarball.mjs +77 -0
  46. package/scripts/candidate-runtime-store.mjs +93 -0
  47. package/scripts/check-plan.mjs +73 -3
  48. package/scripts/check-runner.mjs +129 -17
  49. package/scripts/commit-message-check.mjs +5 -2
  50. package/scripts/consumer-package-security.mjs +293 -0
  51. package/scripts/coverage-check.mjs +251 -15
  52. package/scripts/coverage-generation.mjs +41 -0
  53. package/scripts/coverage-range-merge.mjs +41 -0
  54. package/scripts/foreground-daemon-recovery.mjs +88 -0
  55. package/scripts/generate-policy-reference.mjs +28 -5
  56. package/scripts/generate-tool-reference.mjs +1 -1
  57. package/scripts/generate-worker-types.mjs +21 -11
  58. package/scripts/github-backlog.mjs +11 -10
  59. package/scripts/github-push.mjs +62 -16
  60. package/scripts/github-release-asset.mjs +58 -0
  61. package/scripts/github-release.mjs +241 -132
  62. package/scripts/global-package-installation.mjs +68 -0
  63. package/scripts/hardened-npm-session.mjs +42 -0
  64. package/scripts/install-published-prerelease.mjs +198 -0
  65. package/scripts/local-release-acceptance.mjs +103 -45
  66. package/scripts/macos-background-input-smoke.mjs +515 -0
  67. package/scripts/network-retry.mjs +8 -1
  68. package/scripts/npm-global-prefix.mjs +27 -0
  69. package/scripts/npm-publication-policy.mjs +17 -0
  70. package/scripts/official-mcp-conformance.mjs +267 -0
  71. package/scripts/persistent-activation-process.mjs +101 -0
  72. package/scripts/prepare-pinned-npm.mjs +12 -69
  73. package/scripts/prerelease-activation.mjs +160 -0
  74. package/scripts/privacy-check.mjs +14 -6
  75. package/scripts/promotion-digest.mjs +128 -0
  76. package/scripts/publish-npm.mjs +260 -0
  77. package/scripts/published-release.mjs +132 -0
  78. package/scripts/release-acceptance.mjs +62 -54
  79. package/scripts/release-browser-extension-store.mjs +172 -0
  80. package/scripts/release-candidate-manifest.mjs +52 -0
  81. package/scripts/release-channel.mjs +106 -0
  82. package/scripts/release-diagnostic.mjs +41 -0
  83. package/scripts/release-impact-check.mjs +12 -22
  84. package/scripts/release-oauth-canary-core.mjs +325 -0
  85. package/scripts/release-oauth-canary-evidence.mjs +100 -0
  86. package/scripts/release-oauth-canary.mjs +127 -0
  87. package/scripts/release-publication-guard.mjs +67 -0
  88. package/scripts/release-soak.mjs +284 -0
  89. package/scripts/release-state.mjs +1 -1
  90. package/scripts/run-checks.mjs +44 -7
  91. package/scripts/run-worker-dry-run.mjs +21 -0
  92. package/scripts/sarif-security-gate.mjs +2 -1
  93. package/scripts/sbom-check.mjs +106 -0
  94. package/scripts/start-release-candidate.mjs +267 -44
  95. package/scripts/syntax-check.mjs +36 -14
  96. package/scripts/verification-generation-guard.mjs +15 -0
  97. package/scripts/verification-idle-sleep-guard.mjs +37 -0
  98. package/scripts/verification-state.mjs +108 -0
  99. package/scripts/wrangler-command-lifecycle.mjs +115 -0
  100. package/src/local/account-access.mjs +13 -1
  101. package/src/local/account-admin-response.mjs +92 -0
  102. package/src/local/account-admin.mjs +52 -19
  103. package/src/local/agent-context-projection.mjs +26 -7
  104. package/src/local/agent-context.mjs +88 -49
  105. package/src/local/agent-skill-discovery.mjs +16 -5
  106. package/src/local/app-automation-macos-jxa.mjs +350 -0
  107. package/src/local/app-automation.mjs +873 -163
  108. package/src/local/application-capability-projection.mjs +24 -0
  109. package/src/local/authority-context.mjs +106 -0
  110. package/src/local/autostart-log-maintenance.mjs +36 -0
  111. package/src/local/browser-bridge-http.mjs +5 -3
  112. package/src/local/browser-bridge.mjs +109 -31
  113. package/src/local/browser-broker-auth-http.mjs +67 -0
  114. package/src/local/browser-broker-auth.mjs +98 -0
  115. package/src/local/browser-broker-routes.mjs +63 -20
  116. package/src/local/browser-broker-server.mjs +17 -7
  117. package/src/local/browser-command.mjs +79 -30
  118. package/src/local/browser-computer-observation-service.mjs +266 -0
  119. package/src/local/browser-extension-identity.mjs +50 -0
  120. package/src/local/browser-extension-path.mjs +22 -0
  121. package/src/local/browser-extension-protocol.mjs +50 -11
  122. package/src/local/browser-operation-service.mjs +147 -117
  123. package/src/local/browser-pairing-grant.mjs +109 -0
  124. package/src/local/browser-pairing-http.mjs +36 -0
  125. package/src/local/browser-pairing-launch.mjs +58 -0
  126. package/src/local/browser-pairing-store.mjs +85 -48
  127. package/src/local/browser-request-registry.mjs +40 -14
  128. package/src/local/browser-request-settlement.mjs +78 -0
  129. package/src/local/browser-resource-input.mjs +74 -0
  130. package/src/local/browser-trusted-input-health.mjs +63 -0
  131. package/src/local/call-authority.mjs +21 -0
  132. package/src/local/call-capacity.mjs +45 -0
  133. package/src/local/call-registry-drain.mjs +54 -0
  134. package/src/local/call-registry.mjs +30 -15
  135. package/src/local/capability-observer.mjs +5 -0
  136. package/src/local/capability-ranking.mjs +3 -2
  137. package/src/local/child-process-settlement.mjs +132 -0
  138. package/src/local/cli-account-admin.mjs +40 -6
  139. package/src/local/cli-activate.mjs +162 -0
  140. package/src/local/cli-local-admin.mjs +20 -45
  141. package/src/local/cli-options.mjs +12 -13
  142. package/src/local/cli-ready-output.mjs +52 -0
  143. package/src/local/cli-service.mjs +91 -11
  144. package/src/local/cli.mjs +232 -150
  145. package/src/local/computer-use-application-observation.mjs +224 -0
  146. package/src/local/computer-use-arguments.mjs +270 -0
  147. package/src/local/computer-use-deadline.mjs +50 -0
  148. package/src/local/computer-use-dispatch-settlement.mjs +40 -0
  149. package/src/local/computer-use-expectation.mjs +171 -0
  150. package/src/local/computer-use-observation.mjs +769 -0
  151. package/src/local/computer-use-recovery.mjs +82 -0
  152. package/src/local/computer-use-result-budget.mjs +145 -0
  153. package/src/local/computer-use-snapshot-store.mjs +67 -0
  154. package/src/local/computer-use.mjs +2255 -0
  155. package/src/local/daemon-http-relay-auth.mjs +26 -0
  156. package/src/local/daemon-http-relay-connection.mjs +298 -0
  157. package/src/local/daemon-http-relay-request.mjs +64 -0
  158. package/src/local/daemon-http-relay-sequence.mjs +49 -0
  159. package/src/local/daemon-process.mjs +40 -7
  160. package/src/local/delegated-process-sandbox.mjs +148 -0
  161. package/src/local/device-identity.mjs +156 -49
  162. package/src/local/device-root-provider.mjs +81 -0
  163. package/src/local/directory-metadata.mjs +47 -0
  164. package/src/local/doctor-reporting.mjs +23 -0
  165. package/src/local/durable-process-spec.mjs +80 -0
  166. package/src/local/errors.mjs +25 -15
  167. package/src/local/exclusive-file.mjs +74 -26
  168. package/src/local/execution-limits.mjs +9 -0
  169. package/src/local/execution-routing.mjs +276 -0
  170. package/src/local/execution-surface.mjs +23 -0
  171. package/src/local/file-mutation-coordinator.mjs +47 -0
  172. package/src/local/file-snapshot-preservation.mjs +24 -0
  173. package/src/local/filesystem-identity.mjs +54 -0
  174. package/src/local/fixed-process-environment.mjs +21 -0
  175. package/src/local/full-access-test.mjs +31 -13
  176. package/src/local/git-commit.mjs +69 -0
  177. package/src/local/git-config-safety.mjs +55 -0
  178. package/src/local/git-log-parser.mjs +41 -0
  179. package/src/local/git-metadata-boundary.mjs +77 -0
  180. package/src/local/git-metadata-tree-safety.mjs +59 -0
  181. package/src/local/git-operation-state.mjs +19 -0
  182. package/src/local/git-service.mjs +165 -30
  183. package/src/local/hardened-npm-download-timeout.mjs +46 -0
  184. package/src/local/hardened-npm-download.mjs +109 -0
  185. package/src/local/hardened-npm-extract.mjs +20 -0
  186. package/src/local/hardened-npm-verification.mjs +104 -0
  187. package/src/local/hardened-npm.mjs +199 -0
  188. package/src/local/job-runner.mjs +244 -89
  189. package/src/local/lifecycle.mjs +6 -0
  190. package/src/local/log.mjs +19 -45
  191. package/src/local/macos-background-input.mjs +398 -0
  192. package/src/local/macos-idle-sleep-assertion.mjs +65 -0
  193. package/src/local/macos-trust-broker.mjs +404 -0
  194. package/src/local/managed-job-cancellation.mjs +42 -0
  195. package/src/local/managed-job-capacity.mjs +16 -0
  196. package/src/local/managed-job-directory-generation.mjs +60 -0
  197. package/src/local/managed-job-directory.mjs +75 -0
  198. package/src/local/managed-job-durable-process.mjs +49 -0
  199. package/src/local/managed-job-lock.mjs +46 -14
  200. package/src/local/managed-job-plan.mjs +38 -14
  201. package/src/local/managed-job-projection.mjs +23 -15
  202. package/src/local/managed-job-retention.mjs +128 -0
  203. package/src/local/managed-job-runner-claim.mjs +70 -0
  204. package/src/local/managed-job-runner.mjs +35 -10
  205. package/src/local/managed-job-storage.mjs +22 -6
  206. package/src/local/managed-job-terminal-maintenance.mjs +40 -0
  207. package/src/local/managed-job-terminal.mjs +150 -0
  208. package/src/local/managed-jobs.mjs +424 -287
  209. package/src/local/npm-cli.mjs +42 -0
  210. package/src/local/npm-environment.mjs +37 -0
  211. package/src/local/operation-authorization.mjs +68 -324
  212. package/src/local/operation-risk.mjs +51 -4
  213. package/src/local/owner-state-lock.mjs +118 -0
  214. package/src/local/package-identity.mjs +9 -0
  215. package/src/local/patch.mjs +20 -18
  216. package/src/local/path-inspection.mjs +23 -0
  217. package/src/local/policy.mjs +19 -0
  218. package/src/local/private-toolchain-integrity.mjs +54 -0
  219. package/src/local/process-execution.mjs +87 -75
  220. package/src/local/process-foreground-timeout.mjs +50 -0
  221. package/src/local/process-identity.mjs +41 -7
  222. package/src/local/process-nonreplayable-settlement.mjs +50 -0
  223. package/src/local/process-result-projection.mjs +22 -0
  224. package/src/local/process-session-events.mjs +47 -0
  225. package/src/local/process-session-remote-activity.mjs +10 -0
  226. package/src/local/process-session-termination.mjs +73 -0
  227. package/src/local/process-sessions.mjs +144 -112
  228. package/src/local/process-tracker.mjs +140 -13
  229. package/src/local/process-tree-ownership-types.d.ts +37 -0
  230. package/src/local/process-tree-ownership.mjs +57 -0
  231. package/src/local/process-tree-signal.mjs +34 -0
  232. package/src/local/process-tree-snapshot.mjs +77 -0
  233. package/src/local/process-tree-supervisor.mjs +69 -0
  234. package/src/local/process-tree.mjs +11 -53
  235. package/src/local/project-metadata.mjs +19 -6
  236. package/src/local/relay-call-recovery.mjs +58 -38
  237. package/src/local/relay-connection-classification.mjs +131 -0
  238. package/src/local/relay-connection-support.mjs +91 -0
  239. package/src/local/relay-connection.mjs +179 -272
  240. package/src/local/relay-diagnostics.mjs +91 -0
  241. package/src/local/relay-heartbeat.mjs +119 -0
  242. package/src/local/relay-liveness.mjs +109 -0
  243. package/src/local/relay-peer-diagnostics.mjs +29 -0
  244. package/src/local/release-runtime-lock.mjs +18 -0
  245. package/src/local/remote-activity-idle-sleep-guard.mjs +77 -0
  246. package/src/local/remote-configuration.mjs +48 -0
  247. package/src/local/resilient-relay-connection.mjs +178 -0
  248. package/src/local/resource-admission-diagnostics.mjs +52 -0
  249. package/src/local/resource-admission-policy.mjs +115 -0
  250. package/src/local/resource-admission.mjs +339 -0
  251. package/src/local/resource-build-root.mjs +83 -0
  252. package/src/local/resource-cargo-concurrency.mjs +38 -0
  253. package/src/local/resource-cmake-concurrency.mjs +42 -0
  254. package/src/local/resource-command-concurrency.mjs +37 -0
  255. package/src/local/resource-command-profile.mjs +176 -0
  256. package/src/local/resource-coordinator-accounting.mjs +21 -0
  257. package/src/local/resource-cpu-window.mjs +20 -0
  258. package/src/local/resource-disk-headroom.mjs +13 -0
  259. package/src/local/resource-elastic-memory.mjs +19 -0
  260. package/src/local/resource-elastic-request.mjs +36 -0
  261. package/src/local/resource-foreground-wait.mjs +29 -0
  262. package/src/local/resource-go-concurrency.mjs +43 -0
  263. package/src/local/resource-gradle-concurrency.mjs +57 -0
  264. package/src/local/resource-host-cache.mjs +39 -0
  265. package/src/local/resource-host-darwin.mjs +54 -0
  266. package/src/local/resource-host-linux.mjs +35 -0
  267. package/src/local/resource-host-sample-file.mjs +23 -0
  268. package/src/local/resource-host-snapshot.mjs +99 -0
  269. package/src/local/resource-lease-accounting.mjs +119 -0
  270. package/src/local/resource-light-command.mjs +6 -0
  271. package/src/local/resource-make-concurrency.mjs +42 -0
  272. package/src/local/resource-maven-concurrency.mjs +38 -0
  273. package/src/local/resource-ninja-command-concurrency.mjs +20 -0
  274. package/src/local/resource-ninja-concurrency.mjs +28 -0
  275. package/src/local/resource-operations.mjs +26 -10
  276. package/src/local/resource-pressure.mjs +67 -0
  277. package/src/local/resource-probe-command.mjs +35 -0
  278. package/src/local/resource-process-admission.mjs +59 -0
  279. package/src/local/resource-process-ancestry-cache.mjs +43 -0
  280. package/src/local/resource-process-ancestry.mjs +32 -0
  281. package/src/local/resource-process-priority.mjs +15 -0
  282. package/src/local/resource-project-key.mjs +53 -0
  283. package/src/local/resource-pytest-concurrency.mjs +33 -0
  284. package/src/local/resource-release-control-classification.mjs +14 -0
  285. package/src/local/resource-release-control-executable.mjs +70 -0
  286. package/src/local/resource-release-control-workspace.mjs +41 -0
  287. package/src/local/resource-request-contract.mjs +30 -0
  288. package/src/local/resource-script-classification.mjs +44 -0
  289. package/src/local/resource-shell-analysis.mjs +58 -0
  290. package/src/local/resource-staging-recovery.mjs +97 -0
  291. package/src/local/resource-swift-concurrency.mjs +31 -0
  292. package/src/local/resource-transaction-lock.mjs +189 -0
  293. package/src/local/resource-wait.mjs +48 -0
  294. package/src/local/resource-waiters.mjs +139 -0
  295. package/src/local/resource-xcode-command.mjs +7 -0
  296. package/src/local/resource-xcode-concurrency.mjs +34 -0
  297. package/src/local/resource-xcode-non-build.mjs +19 -0
  298. package/src/local/runtime-activation.mjs +700 -0
  299. package/src/local/runtime-activity-projection.mjs +48 -0
  300. package/src/local/runtime-capabilities.mjs +48 -15
  301. package/src/local/runtime-diagnostic-state.mjs +14 -0
  302. package/src/local/runtime-diagnostics.mjs +40 -13
  303. package/src/local/runtime-info-projection.mjs +60 -0
  304. package/src/local/runtime-info-relay-projection.mjs +21 -0
  305. package/src/local/runtime-paths.mjs +2 -1
  306. package/src/local/runtime-process-routing.mjs +33 -0
  307. package/src/local/runtime-relay-connection-options.mjs +44 -0
  308. package/src/local/runtime-relay-control.mjs +98 -0
  309. package/src/local/runtime-relay.mjs +26 -50
  310. package/src/local/runtime-reporting.mjs +37 -21
  311. package/src/local/runtime-resource-service.mjs +77 -0
  312. package/src/local/runtime-tool-handlers.mjs +13 -10
  313. package/src/local/runtime.mjs +244 -208
  314. package/src/local/secure-file.mjs +73 -20
  315. package/src/local/security-audit-dispatch.mjs +35 -0
  316. package/src/local/security-audit-log.mjs +215 -0
  317. package/src/local/security-audit-state.mjs +139 -0
  318. package/src/local/security-audit-storage.mjs +135 -0
  319. package/src/local/security-audit-warning.mjs +31 -0
  320. package/src/local/security-audit-worker.mjs +87 -0
  321. package/src/local/service-convergence.mjs +42 -1
  322. package/src/local/service-definition.mjs +24 -0
  323. package/src/local/service-environment.mjs +18 -10
  324. package/src/local/service-owner.mjs +146 -0
  325. package/src/local/service-ownership.mjs +17 -0
  326. package/src/local/service-restart-handoff.mjs +64 -0
  327. package/src/local/service-restart-scheduler.mjs +49 -0
  328. package/src/local/service-runtime-convergence.mjs +52 -0
  329. package/src/local/service-runtime.mjs +105 -0
  330. package/src/local/service-status.mjs +60 -0
  331. package/src/local/service.mjs +385 -92
  332. package/src/local/shell.mjs +39 -19
  333. package/src/local/ssh-key.mjs +158 -42
  334. package/src/local/state-inventory.mjs +50 -24
  335. package/src/local/state-owner-lock-inventory.mjs +23 -0
  336. package/src/local/state-root-owned-namespaces.mjs +83 -0
  337. package/src/local/state-root-retirement.mjs +89 -0
  338. package/src/local/state.mjs +386 -96
  339. package/src/local/stdio.mjs +96 -66
  340. package/src/local/support-state-projection.mjs +30 -0
  341. package/src/local/system-network-route.mjs +76 -0
  342. package/src/local/systemd-removal.mjs +20 -0
  343. package/src/local/tool-executor.mjs +85 -20
  344. package/src/local/tool-result-boundary.mjs +51 -0
  345. package/src/local/toolchain-operation-lock.mjs +41 -0
  346. package/src/local/tools.mjs +7 -5
  347. package/src/local/trusted-executable.mjs +53 -0
  348. package/src/local/trusted-git-executable.mjs +34 -0
  349. package/src/local/trusted-github-cli.mjs +24 -0
  350. package/src/local/windows-service-convergence.mjs +49 -0
  351. package/src/local/windows-service.mjs +52 -45
  352. package/src/local/worker-deployment-fingerprint.mjs +102 -0
  353. package/src/local/worker-deployment.mjs +48 -60
  354. package/src/local/worker-health.mjs +12 -4
  355. package/src/local/worker-secret-file.mjs +37 -17
  356. package/src/local/workspace-file-service.mjs +156 -239
  357. package/src/local/workspace-file-transaction.mjs +189 -0
  358. package/src/local/workspace-search.mjs +55 -0
  359. package/src/local/wrangler-toolchain/package-lock.json +1505 -0
  360. package/src/local/wrangler-toolchain/package.json +23 -0
  361. package/src/local/wrangler-toolchain-verification.mjs +135 -0
  362. package/src/local/wrangler-toolchain.mjs +188 -0
  363. package/src/shared/access-contract.json +7 -1
  364. package/src/shared/activation-recovery.mjs +49 -0
  365. package/src/shared/admin-auth.d.mts +2 -1
  366. package/src/shared/admin-auth.mjs +3 -3
  367. package/src/shared/authority-revocation.d.mts +9 -0
  368. package/src/shared/authority-revocation.mjs +28 -0
  369. package/src/shared/daemon-auth.d.mts +11 -0
  370. package/src/shared/daemon-auth.mjs +17 -0
  371. package/src/shared/device-session-auth.d.mts +20 -0
  372. package/src/shared/device-session-auth.mjs +51 -0
  373. package/src/shared/foreground-timeout.d.mts +15 -0
  374. package/src/shared/foreground-timeout.mjs +70 -0
  375. package/src/shared/log-redaction.d.mts +9 -0
  376. package/src/shared/log-redaction.mjs +51 -0
  377. package/src/shared/mcp-protocol.d.mts +27 -0
  378. package/src/shared/mcp-protocol.mjs +275 -0
  379. package/src/shared/project-overview-projection.d.mts +4 -0
  380. package/src/shared/project-overview-projection.mjs +96 -0
  381. package/src/shared/relay-contract.json +28 -0
  382. package/src/shared/result-projection.d.mts +2 -1
  383. package/src/shared/result-projection.mjs +13 -2
  384. package/src/shared/server-metadata.json +15 -9
  385. package/src/shared/tool-argument-validation.d.mts +17 -0
  386. package/src/shared/tool-argument-validation.mjs +325 -0
  387. package/src/shared/tool-call-capacity.d.mts +41 -0
  388. package/src/shared/tool-call-capacity.mjs +59 -0
  389. package/src/shared/tool-catalog.json +626 -57
  390. package/src/worker/access.ts +12 -0
  391. package/src/worker/account-admin.ts +55 -33
  392. package/src/worker/authority-revocations.ts +174 -0
  393. package/src/worker/authority.ts +52 -6
  394. package/src/worker/daemon-auth.ts +49 -68
  395. package/src/worker/daemon-channel.ts +36 -0
  396. package/src/worker/daemon-http-auth.ts +63 -0
  397. package/src/worker/daemon-http-channel.ts +120 -0
  398. package/src/worker/daemon-http-controller.ts +163 -0
  399. package/src/worker/daemon-http-protocol.ts +62 -0
  400. package/src/worker/daemon-http-registry.ts +82 -0
  401. package/src/worker/daemon-last-observation.ts +30 -0
  402. package/src/worker/daemon-liveness.ts +8 -6
  403. package/src/worker/daemon-ready-dispatch.ts +17 -0
  404. package/src/worker/daemon-ready-messages.ts +73 -0
  405. package/src/worker/daemon-ready-waiters.ts +79 -0
  406. package/src/worker/daemon-recovery-budget.ts +13 -0
  407. package/src/worker/daemon-registry.ts +58 -0
  408. package/src/worker/daemon-relay-diagnostics.ts +127 -0
  409. package/src/worker/daemon-socket-attachment.ts +55 -0
  410. package/src/worker/daemon-sockets.ts +72 -62
  411. package/src/worker/daemon-status.ts +38 -0
  412. package/src/worker/device-session-verifier.ts +129 -0
  413. package/src/worker/dpop.ts +157 -0
  414. package/src/worker/durable-process-timeout.ts +29 -0
  415. package/src/worker/errors.ts +57 -0
  416. package/src/worker/http.ts +112 -26
  417. package/src/worker/index.ts +446 -440
  418. package/src/worker/mcp-access.ts +57 -0
  419. package/src/worker/mcp-controller.ts +188 -0
  420. package/src/worker/mcp-http-accept.ts +11 -0
  421. package/src/worker/mcp-http-contract.ts +322 -0
  422. package/src/worker/mcp-initialization-compat.ts +141 -0
  423. package/src/worker/mcp-jsonrpc.ts +11 -29
  424. package/src/worker/mcp-removed-protocol.ts +17 -0
  425. package/src/worker/mcp-response-proxy.ts +135 -0
  426. package/src/worker/mcp-response-stream.ts +65 -0
  427. package/src/worker/mcp-stale-schema-compat.ts +57 -0
  428. package/src/worker/mcp-stream-proxy-contract.ts +48 -0
  429. package/src/worker/mcp-tool-call-input.ts +23 -0
  430. package/src/worker/nonce-store.ts +33 -35
  431. package/src/worker/oauth-authorization-page.ts +21 -1
  432. package/src/worker/oauth-client-admin.ts +52 -0
  433. package/src/worker/oauth-client-contract.ts +38 -0
  434. package/src/worker/oauth-controller.ts +107 -47
  435. package/src/worker/oauth-field-contract.ts +31 -0
  436. package/src/worker/oauth-record-contract.ts +7 -0
  437. package/src/worker/oauth-refresh-authority.ts +27 -0
  438. package/src/worker/oauth-refresh-exchange.ts +162 -0
  439. package/src/worker/oauth-refresh-families.ts +130 -27
  440. package/src/worker/oauth-refresh-persistence.ts +116 -0
  441. package/src/worker/oauth-state.ts +33 -18
  442. package/src/worker/oauth-store-validation.ts +131 -0
  443. package/src/worker/oauth-token-derivation.ts +33 -0
  444. package/src/worker/oauth-token-issuance.ts +119 -0
  445. package/src/worker/oauth-tokens.ts +56 -190
  446. package/src/worker/observability.ts +38 -5
  447. package/src/worker/pending-admission.ts +15 -0
  448. package/src/worker/pending-call-capacity.ts +108 -0
  449. package/src/worker/pending-call-contract.ts +42 -5
  450. package/src/worker/pending-call-deadlines.ts +75 -0
  451. package/src/worker/pending-calls.ts +131 -125
  452. package/src/worker/runtime-alarm-storage.ts +37 -0
  453. package/src/worker/runtime-alarm.ts +136 -0
  454. package/src/worker/server-info-activity.ts +36 -0
  455. package/src/worker/server-info-tool-delivery.ts +15 -0
  456. package/src/worker/server-info.ts +168 -0
  457. package/src/worker/tool-catalog.ts +47 -1
  458. package/src/worker/tool-timeout.ts +75 -14
  459. package/src/worker/websocket-protocol.ts +26 -2
  460. package/src/worker/worker-edge-guard.ts +90 -0
  461. package/src/worker/worker-edge-log.ts +65 -0
  462. package/src/worker/worker-entry.ts +52 -0
  463. package/src/worker/worker-mcp-config.ts +23 -0
  464. package/src/worker/worker-metadata.ts +48 -0
  465. package/src/worker/worker-rate-limit-key.ts +30 -0
  466. package/src/worker/worker-runtime-config.ts +20 -0
  467. package/src/worker/worker-static-routes.ts +54 -0
  468. package/src/worker/worker-task-lifetime.ts +18 -0
  469. package/tsconfig.local.json +17 -1
  470. package/wrangler.jsonc +13 -0
  471. package/src/local/cli-approval.mjs +0 -117
  472. package/src/local/operation-state-lock.mjs +0 -92
  473. package/src/worker/mcp-session.ts +0 -72
@@ -0,0 +1,404 @@
1
+ import { createHash, randomBytes } from "node:crypto";
2
+ import { lstatSync, realpathSync, unlinkSync } from "node:fs";
3
+ import path from "node:path";
4
+ import { spawnSync } from "node:child_process";
5
+ import { deviceKeyId } from "./device-identity.mjs";
6
+ import { ensureOwnerOnlyDirectorySync, readBoundedRegularFileSync } from "./secure-file.mjs";
7
+ import { replaceFileAtomicallySync } from "./exclusive-file.mjs";
8
+ import { packageRoot } from "./package-identity.mjs";
9
+
10
+ const PROVIDER = "macos-secure-enclave-v1";
11
+ const BROKER_PROTOCOL = 1;
12
+ const BROKER_ENVIRONMENT_VARIABLE = "MBM_MACOS_TRUST_BROKER";
13
+ const SOURCE_RELATIVE = "native/macos/MachineBridgeTrustBroker.swift";
14
+ const MAX_OUTPUT_BYTES = 256 * 1024;
15
+ const MAX_TRANSCRIPT_BYTES = 64 * 1024;
16
+ const MAX_DEVELOPMENT_BROKER_BYTES = 16 * 1024 * 1024;
17
+ const IDENTIFIER_PATTERN = /^[A-Za-z0-9][A-Za-z0-9.-]{2,199}$/;
18
+ const TEAM_IDENTIFIER_PATTERN = /^[A-Z0-9]{10}$/;
19
+
20
+ export class MacosTrustBrokerUnavailableError extends Error {
21
+ constructor(message, options = {}) {
22
+ super(message, options);
23
+ this.name = "MacosTrustBrokerUnavailableError";
24
+ this.code = "MBM_MACOS_TRUST_BROKER_UNAVAILABLE";
25
+ }
26
+ }
27
+
28
+ export function configuredMacosTrustBrokerPath(env = process.env) {
29
+ const value = String(env?.[BROKER_ENVIRONMENT_VARIABLE] || "").trim();
30
+ if (!value) return null;
31
+ if (!path.isAbsolute(value)) throw new MacosTrustBrokerUnavailableError(`${BROKER_ENVIRONMENT_VARIABLE} must be an absolute path`);
32
+ return value;
33
+ }
34
+
35
+ export function isMacosSecureDeviceRoot(value) {
36
+ return Boolean(
37
+ value
38
+ && typeof value === "object"
39
+ && !Array.isArray(value)
40
+ && value.provider === PROVIDER
41
+ && value.brokerProtocol === BROKER_PROTOCOL
42
+ && path.isAbsolute(String(value.brokerPath || ""))
43
+ && IDENTIFIER_PATTERN.test(String(value.brokerIdentifier || ""))
44
+ && TEAM_IDENTIFIER_PATTERN.test(String(value.brokerTeamIdentifier || ""))
45
+ && /^com\.machine-bridge-mcp\.device\.[A-Za-z0-9._-]{8,160}$/.test(String(value.keyTag || ""))
46
+ && value.publicJwk?.kty === "EC"
47
+ && value.publicJwk?.crv === "P-256"
48
+ && typeof value.publicJwk?.x === "string"
49
+ && typeof value.publicJwk?.y === "string"
50
+ && value.keyId === deviceKeyId(value.publicJwk)
51
+ && Number.isFinite(Date.parse(String(value.createdAt || "")))
52
+ );
53
+ }
54
+
55
+ export function ensureMacosSecureDeviceRoot({ workspaceHash, existing = null, rotate = false, brokerPath = null, options = {} } = {}) {
56
+ if (process.platform !== "darwin" && !options.allowNonDarwin) {
57
+ throw new MacosTrustBrokerUnavailableError("macOS Secure Enclave provider is unavailable on this platform");
58
+ }
59
+ const selectedPath = brokerPath || existing?.brokerPath || configuredMacosTrustBrokerPath(options.env);
60
+ if (!selectedPath) {
61
+ throw new MacosTrustBrokerUnavailableError(
62
+ `Secure Enclave enrollment requires a provisioned app-like broker configured through ${BROKER_ENVIRONMENT_VARIABLE}`,
63
+ );
64
+ }
65
+ const broker = inspectProvisionedMacosTrustBroker(selectedPath, options);
66
+ if (!rotate && isMacosSecureDeviceRoot(existing)) {
67
+ assertBrokerBinding(existing, broker);
68
+ const result = runBroker(broker.path, ["public", "--tag", existing.keyTag], { timeoutMs: 30_000 }, options);
69
+ assertBrokerKeyResult(result, existing.keyTag);
70
+ if (deviceKeyId(result.publicJwk) !== existing.keyId) throw new Error("provisioned macOS trust broker returned a different device root");
71
+ return existing;
72
+ }
73
+
74
+ probeProvisionedMacosTrustBroker(broker, options);
75
+ const tagSuffix = randomBytes(18).toString("base64url").replaceAll("_", "-");
76
+ const tag = `com.machine-bridge-mcp.device.${String(workspaceHash || "workspace").slice(0, 24)}.${tagSuffix}`;
77
+ let created = false;
78
+ try {
79
+ const result = runBroker(broker.path, ["ensure", "--tag", tag], { timeoutMs: 30_000 }, options);
80
+ created = true;
81
+ assertBrokerKeyResult(result, tag);
82
+ const identity = {
83
+ scheme: "device-signature-v1",
84
+ provider: PROVIDER,
85
+ brokerProtocol: BROKER_PROTOCOL,
86
+ brokerPath: broker.path,
87
+ brokerIdentifier: broker.identifier,
88
+ brokerTeamIdentifier: broker.teamIdentifier,
89
+ keyTag: tag,
90
+ publicJwk: result.publicJwk,
91
+ keyId: deviceKeyId(result.publicJwk),
92
+ createdAt: new Date().toISOString(),
93
+ };
94
+ if (!isMacosSecureDeviceRoot(identity)) throw new Error("Secure Enclave device root failed local validation");
95
+ return identity;
96
+ } catch (error) {
97
+ let cleanupError = null;
98
+ if (created) {
99
+ try { runBroker(broker.path, ["delete", "--tag", tag], { timeoutMs: 30_000 }, options); }
100
+ catch (failure) { cleanupError = failure; }
101
+ }
102
+ if (cleanupError) {
103
+ throw new AggregateError(
104
+ [error, cleanupError],
105
+ "Secure Enclave enrollment failed and the newly created key could not be removed; inspect the provisioned trust broker before retrying",
106
+ );
107
+ }
108
+ throw error;
109
+ }
110
+ }
111
+
112
+ export function signWithMacosSecureDeviceRoot(identity, transcript, { reason = "Authorize Machine Bridge startup", options = {} } = {}) {
113
+ if (!isMacosSecureDeviceRoot(identity)) throw new Error("Secure Enclave device root is invalid");
114
+ const input = Buffer.from(String(transcript), "utf8");
115
+ if (!input.length || input.length > MAX_TRANSCRIPT_BYTES) throw new Error("device root signing transcript is empty or too large");
116
+ const broker = inspectProvisionedMacosTrustBroker(identity.brokerPath, options);
117
+ assertBrokerBinding(identity, broker);
118
+ const result = runBroker(broker.path, ["sign", "--tag", identity.keyTag, "--reason", sanitizeReason(reason)], {
119
+ input,
120
+ timeoutMs: 120_000,
121
+ }, options);
122
+ if (!result.ok || result.provider !== PROVIDER || result.keyTag !== identity.keyTag || !/^[A-Za-z0-9_-]{86}$/.test(String(result.signature || ""))) {
123
+ throw new Error("Secure Enclave broker returned an invalid signature result");
124
+ }
125
+ if (result.publicJwk && deviceKeyId(result.publicJwk) !== identity.keyId) {
126
+ throw new Error("Secure Enclave broker key identity changed before signing");
127
+ }
128
+ return result.signature;
129
+ }
130
+
131
+ export function inspectProvisionedMacosTrustBroker(binaryPath, options = {}) {
132
+ const raw = String(binaryPath || "");
133
+ if (!path.isAbsolute(raw)) throw new MacosTrustBrokerUnavailableError("macOS trust broker path must be absolute");
134
+ let info;
135
+ let resolved;
136
+ try {
137
+ const direct = lstatSync(raw);
138
+ if (direct.isSymbolicLink()) throw new MacosTrustBrokerUnavailableError("macOS trust broker path must not be a symbolic link");
139
+ resolved = realpathSync(raw);
140
+ info = lstatSync(resolved);
141
+ } catch (error) {
142
+ if (error instanceof MacosTrustBrokerUnavailableError) throw error;
143
+ throw new MacosTrustBrokerUnavailableError(`macOS trust broker is unavailable: ${boundedDiagnostic(error?.message)}`, { cause: error });
144
+ }
145
+ if (!info.isFile()) throw new MacosTrustBrokerUnavailableError("macOS trust broker is not a regular file");
146
+ if ((info.mode & 0o022) !== 0) throw new MacosTrustBrokerUnavailableError("macOS trust broker is writable by group or other users");
147
+ if ((info.mode & 0o111) === 0) throw new MacosTrustBrokerUnavailableError("macOS trust broker is not executable");
148
+ const currentUid = typeof process.getuid === "function" ? process.getuid() : null;
149
+ if (currentUid !== null && info.uid !== currentUid && info.uid !== 0) {
150
+ throw new MacosTrustBrokerUnavailableError("macOS trust broker must be owned by the current user or root");
151
+ }
152
+
153
+ const spawn = options.spawnSync || spawnSync;
154
+ const verify = spawn("/usr/bin/codesign", ["--verify", "--strict", "--verbose=2", resolved], codesignOptions());
155
+ if (verify.status !== 0 || verify.error) {
156
+ throw new MacosTrustBrokerUnavailableError(`macOS trust broker code signature is invalid (${boundedDiagnostic(verify.stderr || verify.error?.message)})`);
157
+ }
158
+ const describe = spawn("/usr/bin/codesign", ["-dvvv", resolved], codesignOptions());
159
+ if (describe.status !== 0 || describe.error) {
160
+ throw new MacosTrustBrokerUnavailableError(`macOS trust broker signature metadata is unavailable (${boundedDiagnostic(describe.stderr || describe.error?.message)})`);
161
+ }
162
+ const metadata = parseCodesignMetadata(describe.stderr || describe.stdout);
163
+ if (!TEAM_IDENTIFIER_PATTERN.test(metadata.teamIdentifier) || metadata.signature.toLowerCase() === "adhoc") {
164
+ throw new MacosTrustBrokerUnavailableError(
165
+ "macOS trust broker must be signed by an Apple development or distribution identity and validated by a provisioning profile; ad-hoc signing cannot access the data-protection Keychain",
166
+ );
167
+ }
168
+ if (!IDENTIFIER_PATTERN.test(metadata.identifier)) throw new MacosTrustBrokerUnavailableError("macOS trust broker has no stable code-signing identifier");
169
+ return { path: resolved, identifier: metadata.identifier, teamIdentifier: metadata.teamIdentifier };
170
+ }
171
+
172
+ export function probeProvisionedMacosTrustBroker(brokerOrPath, options = {}) {
173
+ const broker = typeof brokerOrPath === "string" ? inspectProvisionedMacosTrustBroker(brokerOrPath, options) : brokerOrPath;
174
+ const tag = `com.machine-bridge-mcp.device.probe.${randomBytes(18).toString("base64url").replaceAll("_", "-")}`;
175
+ let created = false;
176
+ let probeError = null;
177
+ try {
178
+ const result = runBroker(broker.path, ["ensure", "--tag", tag], { timeoutMs: 30_000 }, options);
179
+ created = true;
180
+ assertBrokerKeyResult(result, tag);
181
+ } catch (error) {
182
+ probeError = error instanceof MacosTrustBrokerUnavailableError
183
+ ? error
184
+ : new MacosTrustBrokerUnavailableError(
185
+ `macOS trust broker failed its Secure Enclave capability probe (${boundedDiagnostic(error?.message)})`,
186
+ { cause: error },
187
+ );
188
+ }
189
+ if (created) {
190
+ const deleted = runBroker(broker.path, ["delete", "--tag", tag], { timeoutMs: 30_000 }, options);
191
+ if (!deleted.ok || deleted.provider !== PROVIDER || deleted.keyTag !== tag) {
192
+ throw new MacosTrustBrokerUnavailableError("macOS trust broker could not remove its capability-probe key");
193
+ }
194
+ }
195
+ if (probeError) throw probeError;
196
+ return broker;
197
+ }
198
+
199
+ export function buildDevelopmentTrustBrokerBinary(profileDir, options = {}) {
200
+ if (process.platform !== "darwin") throw new Error("macOS trust broker build is unavailable on this platform");
201
+ const source = path.resolve(options.packageRoot || packageRoot, SOURCE_RELATIVE);
202
+ const sourceBytes = readBoundedRegularFileSync(source, 2 * 1024 * 1024, "macOS trust broker source", {
203
+ verifyPathIdentity: true,
204
+ rejectMultipleLinks: true,
205
+ });
206
+ const sourceDigest = createHash("sha256").update(sourceBytes).digest("hex");
207
+ const directory = path.resolve(profileDir, "native", "macos");
208
+ ensureOwnerOnlyDirectorySync(directory);
209
+ const binary = path.join(directory, "machine-bridge-trust-broker-development");
210
+ const marker = path.join(directory, "machine-bridge-trust-broker-development.sha256");
211
+ const currentMarker = readDevelopmentBrokerMarker(marker);
212
+ const existingBinary = inspectDevelopmentBrokerBinary(binary);
213
+ if (existingBinary && currentMarker?.sourceSha256 === sourceDigest) {
214
+ const binaryBytes = readBoundedRegularFileSync(binary, MAX_DEVELOPMENT_BROKER_BYTES, "macOS development trust broker", {
215
+ verifyPathIdentity: true,
216
+ rejectMultipleLinks: true,
217
+ });
218
+ const binaryDigest = createHash("sha256").update(binaryBytes).digest("hex");
219
+ if (binaryDigest === currentMarker.binarySha256) return binary;
220
+ }
221
+
222
+ const temporary = path.join(directory, `.machine-bridge-trust-broker.${process.pid}.${randomBytes(6).toString("hex")}`);
223
+ const compiler = options.swiftc || "/usr/bin/swiftc";
224
+ let compiledBytes;
225
+ let primaryError = null;
226
+ try {
227
+ const compile = (options.spawnSync || spawnSync)(compiler, [
228
+ "-parse-as-library", "-O", "-framework", "Security", "-framework", "LocalAuthentication", source, "-o", temporary,
229
+ ], {
230
+ encoding: "utf8",
231
+ timeout: 120_000,
232
+ killSignal: "SIGKILL",
233
+ maxBuffer: MAX_OUTPUT_BYTES,
234
+ env: minimalEnvironment(),
235
+ });
236
+ if (compile.status !== 0 || compile.error) {
237
+ throw new Error(`could not build macOS trust broker (${boundedDiagnostic(compile.stderr || compile.error?.message)})`);
238
+ }
239
+ const sign = (options.spawnSync || spawnSync)("/usr/bin/codesign", ["--force", "--sign", "-", temporary], {
240
+ encoding: "utf8",
241
+ timeout: 30_000,
242
+ killSignal: "SIGKILL",
243
+ maxBuffer: MAX_OUTPUT_BYTES,
244
+ env: minimalEnvironment(),
245
+ });
246
+ if (sign.status !== 0 || sign.error) {
247
+ throw new Error(`could not ad-hoc sign development macOS trust broker (${boundedDiagnostic(sign.stderr || sign.error?.message)})`);
248
+ }
249
+ compiledBytes = readBoundedRegularFileSync(temporary, MAX_DEVELOPMENT_BROKER_BYTES, "compiled macOS development trust broker", {
250
+ verifyPathIdentity: true,
251
+ rejectMultipleLinks: true,
252
+ });
253
+ } catch (error) {
254
+ primaryError = error;
255
+ }
256
+ let cleanupError = null;
257
+ try { (options.unlinkSync || unlinkSync)(temporary); }
258
+ catch (error) {
259
+ if (error?.code !== "ENOENT") cleanupError = error;
260
+ }
261
+ if (primaryError && cleanupError) {
262
+ throw new AggregateError([primaryError, cleanupError], "macOS development trust broker build failed and temporary cleanup was incomplete");
263
+ }
264
+ if (primaryError) throw primaryError;
265
+ if (cleanupError) throw new Error("macOS development trust broker temporary cleanup failed", { cause: cleanupError });
266
+
267
+ const binaryDigest = createHash("sha256").update(compiledBytes).digest("hex");
268
+ replaceFileAtomicallySync(binary, compiledBytes, { mode: 0o700 });
269
+ replaceFileAtomicallySync(marker, `${JSON.stringify({
270
+ schema: 1,
271
+ source_sha256: sourceDigest,
272
+ binary_sha256: binaryDigest,
273
+ })}
274
+ `, { mode: 0o600 });
275
+ return binary;
276
+ }
277
+
278
+ function readDevelopmentBrokerMarker(marker) {
279
+ let bytes;
280
+ try {
281
+ bytes = readBoundedRegularFileSync(marker, 512, "macOS development trust broker digest", {
282
+ verifyPathIdentity: true,
283
+ rejectMultipleLinks: true,
284
+ });
285
+ } catch (error) {
286
+ if (error?.code === "ENOENT") return null;
287
+ throw error;
288
+ }
289
+ let value;
290
+ try {
291
+ value = JSON.parse(new TextDecoder("utf-8", { fatal: true }).decode(bytes));
292
+ } catch {
293
+ return null;
294
+ }
295
+ if (!value || typeof value !== "object" || Array.isArray(value)
296
+ || value.schema !== 1
297
+ || !/^[0-9a-f]{64}$/.test(String(value.source_sha256 || ""))
298
+ || !/^[0-9a-f]{64}$/.test(String(value.binary_sha256 || ""))) return null;
299
+ return { sourceSha256: value.source_sha256, binarySha256: value.binary_sha256 };
300
+ }
301
+
302
+ function inspectDevelopmentBrokerBinary(binary) {
303
+ let info;
304
+ try { info = lstatSync(binary); }
305
+ catch (error) {
306
+ if (error?.code === "ENOENT") return null;
307
+ throw error;
308
+ }
309
+ if (info.isSymbolicLink() || !info.isFile()) {
310
+ throw new Error("macOS development trust broker must be a regular file and not a symbolic link");
311
+ }
312
+ if (Number(info.nlink) > 1) throw new Error("macOS development trust broker must not have multiple hard links");
313
+ if (process.platform !== "win32" && ((info.mode & 0o077) !== 0 || (info.mode & 0o700) !== 0o700)) {
314
+ throw new Error("macOS development trust broker must remain owner-only and owner-executable");
315
+ }
316
+ return info;
317
+ }
318
+
319
+ function assertBrokerBinding(identity, broker) {
320
+ if (identity.brokerPath !== broker.path
321
+ || identity.brokerIdentifier !== broker.identifier
322
+ || identity.brokerTeamIdentifier !== broker.teamIdentifier) {
323
+ throw new Error("macOS trust broker signing identity no longer matches the enrolled device root");
324
+ }
325
+ }
326
+
327
+ function assertBrokerKeyResult(result, tag) {
328
+ if (!result?.ok || result.provider !== PROVIDER || result.keyTag !== tag || result.secureEnclave !== true || !result.publicJwk) {
329
+ throw new Error("Secure Enclave broker returned an invalid key result");
330
+ }
331
+ deviceKeyId(result.publicJwk);
332
+ }
333
+
334
+ function runBroker(binary, args, { input, timeoutMs }, options = {}) {
335
+ const result = (options.spawnSync || spawnSync)(binary, args, {
336
+ input,
337
+ encoding: "utf8",
338
+ timeout: timeoutMs,
339
+ killSignal: "SIGKILL",
340
+ maxBuffer: MAX_OUTPUT_BYTES,
341
+ env: minimalEnvironment(),
342
+ windowsHide: true,
343
+ });
344
+ if (result.status !== 0 || result.error) {
345
+ const diagnostic = boundedDiagnostic(result.stderr || result.error?.message || result.signal || `exit ${result.status}`);
346
+ if (result.error?.code === "ETIMEDOUT") {
347
+ throw new MacosTrustBrokerUnavailableError("macOS trust broker timed out");
348
+ }
349
+ if (/-34018|missing entitlement|required entitlement/i.test(diagnostic)) {
350
+ throw new MacosTrustBrokerUnavailableError(
351
+ "macOS trust broker lacks a provisioning-profile-validated data-protection Keychain entitlement",
352
+ );
353
+ }
354
+ if (result.signal === "SIGKILL" || result.status === 137) {
355
+ throw new MacosTrustBrokerUnavailableError("macOS rejected the trust broker code signature or entitlements");
356
+ }
357
+ throw new Error(`macOS trust broker failed (${diagnostic})`);
358
+ }
359
+ let parsed;
360
+ try { parsed = JSON.parse(result.stdout); } catch { throw new Error("macOS trust broker returned invalid JSON"); }
361
+ if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) throw new Error("macOS trust broker returned an invalid result");
362
+ return parsed;
363
+ }
364
+
365
+ function parseCodesignMetadata(value) {
366
+ const metadata = { identifier: "", teamIdentifier: "", signature: "" };
367
+ for (const line of String(value || "").split(/\r?\n/)) {
368
+ const index = line.indexOf("=");
369
+ if (index <= 0) continue;
370
+ const key = line.slice(0, index).trim();
371
+ const entry = line.slice(index + 1).trim();
372
+ if (key === "Identifier") metadata.identifier = entry;
373
+ else if (key === "TeamIdentifier") metadata.teamIdentifier = entry;
374
+ else if (key === "Signature") metadata.signature = entry;
375
+ }
376
+ return metadata;
377
+ }
378
+
379
+ function codesignOptions() {
380
+ return {
381
+ encoding: "utf8",
382
+ timeout: 30_000,
383
+ killSignal: "SIGKILL",
384
+ maxBuffer: MAX_OUTPUT_BYTES,
385
+ env: minimalEnvironment(),
386
+ };
387
+ }
388
+
389
+ function minimalEnvironment() {
390
+ return {
391
+ PATH: "/usr/bin:/bin:/usr/sbin:/sbin",
392
+ HOME: process.env.HOME || "",
393
+ TMPDIR: process.env.TMPDIR || "/tmp",
394
+ LANG: process.env.LANG || "en_US.UTF-8",
395
+ };
396
+ }
397
+
398
+ function sanitizeReason(value) {
399
+ return String(value || "Authorize Machine Bridge startup").replace(/[\r\n\t\u0000-\u001f\u007f]/g, " ").trim().slice(0, 160) || "Authorize Machine Bridge startup";
400
+ }
401
+
402
+ function boundedDiagnostic(value) {
403
+ return String(value || "unknown error").replace(/[\r\n\t]+/g, " ").trim().slice(0, 600);
404
+ }
@@ -0,0 +1,42 @@
1
+ import { replaceFileAtomicallySync } from "./exclusive-file.mjs";
2
+ import { inspectPathIfPresentSync, readBoundedRegularFileSync } from "./secure-file.mjs";
3
+
4
+ const MAX_CANCELLATION_BYTES = 128;
5
+ const ISO_TIMESTAMP = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3}Z$/;
6
+
7
+ export function writeManagedJobCancellation(file, now = new Date(), options = {}) {
8
+ const timestamp = now instanceof Date ? now.toISOString() : String(now || "");
9
+ if (!validTimestamp(timestamp)) throw new Error("managed job cancellation timestamp is invalid");
10
+ const replace = options.replaceFile || replaceFileAtomicallySync;
11
+ replace(file, `${timestamp}\n`, { mode: 0o600 });
12
+ }
13
+
14
+ export function managedJobCancellationRequested(file, options = {}) {
15
+ const inspect = options.inspectPath || ((target) => inspectPathIfPresentSync(
16
+ target,
17
+ "managed job cancellation marker",
18
+ options.inspectOptions || {},
19
+ ));
20
+ const info = inspect(file);
21
+ if (!info) return false;
22
+ if (info.isSymbolicLink?.() || !info.isFile?.()) {
23
+ throw new Error("managed job cancellation marker must be a regular file and not a symbolic link");
24
+ }
25
+ if (Number(info.nlink) > 1) throw new Error("managed job cancellation marker must not have multiple hard links");
26
+ const read = options.readFile || ((target) => readBoundedRegularFileSync(
27
+ target,
28
+ MAX_CANCELLATION_BYTES,
29
+ "managed job cancellation marker",
30
+ { verifyPathIdentity: true, rejectMultipleLinks: true },
31
+ ));
32
+ const text = new TextDecoder("utf-8", { fatal: true }).decode(read(file));
33
+ if (!text.endsWith("\n") || text.indexOf("\n") !== text.length - 1 || !validTimestamp(text.slice(0, -1))) {
34
+ throw new Error("managed job cancellation marker is invalid");
35
+ }
36
+ return true;
37
+ }
38
+
39
+ function validTimestamp(value) {
40
+ if (!ISO_TIMESTAMP.test(value) || !Number.isFinite(Date.parse(value))) return false;
41
+ return new Date(Date.parse(value)).toISOString() === value;
42
+ }
@@ -0,0 +1,16 @@
1
+ import { MANAGED_JOB_ID } from "./managed-job-directory.mjs";
2
+ import { retiredManagedJobDirectories } from "./managed-job-directory-generation.mjs";
3
+ import { safeReadDir } from "./managed-job-storage.mjs";
4
+
5
+ export const MAX_JOBS = 50;
6
+
7
+ export function managedJobCapacitySnapshot(jobRoot) {
8
+ const retired = retiredManagedJobDirectories(jobRoot);
9
+ const reservedJobs = safeReadDir(jobRoot).filter((entry) => MANAGED_JOB_ID.test(entry.name));
10
+ return {
11
+ retained_state: reservedJobs.length + retired.length,
12
+ job_state_unreadable: reservedJobs.filter((entry) => !entry.isDirectory()).length,
13
+ retired_state: retired.length,
14
+ retired_unreadable: retired.filter((entry) => !entry.reclaimable).length,
15
+ };
16
+ }
@@ -0,0 +1,60 @@
1
+ import { randomBytes } from "node:crypto";
2
+ import { lstatSync, readdirSync, renameSync, rmSync } from "node:fs";
3
+ import { dirname, join } from "node:path";
4
+ import { filesystemIdentity, filesystemTimeMs, sameFilesystemIdentity } from "./filesystem-identity.mjs";
5
+ import { withPinnedManagedJobDirectory } from "./managed-job-directory.mjs";
6
+ const RETIRED_JOB_DIRECTORY = /^retired_job_([A-Za-z0-9_-]{24})_d([0-9]+)_i([0-9]+)$/;
7
+ export function inspectManagedJobDirectoryGeneration(dir, label = "managed job directory") {
8
+ const info = inspectDirectory(dir, label);
9
+ return { identity: filesystemIdentity(info, label), mtimeMs: filesystemTimeMs(info.mtimeMs, `${label} modification time`) };
10
+ }
11
+ export function retiredManagedJobDirectories(jobRoot) {
12
+ let entries; try { entries = readdirSync(jobRoot, { withFileTypes: true }); }
13
+ catch (error) { if (error?.code === "ENOENT") return []; throw error; }
14
+ const retired = [];
15
+ for (const entry of entries) {
16
+ if (!entry.name.startsWith("retired_job_")) continue;
17
+ const match = RETIRED_JOB_DIRECTORY.exec(entry.name); const dir = join(jobRoot, entry.name);
18
+ if (!match || !entry.isDirectory()) { retired.push({ name: entry.name, dir, identity: null, reclaimable: false, error_class: "integrity_error" }); continue; }
19
+ try {
20
+ const identity = filesystemIdentity(inspectDirectory(dir, "retired managed job directory"), "retired managed job directory");
21
+ const reclaimable = identity.dev === BigInt(match[2]) && identity.ino === BigInt(match[3]);
22
+ retired.push({ name: entry.name, dir, identity, reclaimable, error_class: reclaimable ? null : "integrity_error" });
23
+ } catch (error) {
24
+ if (error?.code !== "ENOENT") retired.push({ name: entry.name, dir, identity: null, reclaimable: false, error_class: "resource_unavailable" });
25
+ }
26
+ }
27
+ return retired;
28
+ }
29
+ export function removeManagedJobDirectoryIfCurrent(dir, expectedIdentity, label = "managed job directory", options = {}) {
30
+ const rename = typeof options.renameSync === "function" ? options.renameSync : renameSync;
31
+ const result = withPinnedManagedJobDirectory(dir, label, options, true, (pinned) => {
32
+ const pinnedIdentity = filesystemIdentity(pinned, label);
33
+ if (!sameFilesystemIdentity(expectedIdentity, pinnedIdentity)) return false;
34
+ const quarantine = join(dirname(dir), `retired_job_${randomBytes(18).toString("base64url")}_d${pinnedIdentity.dev}_i${pinnedIdentity.ino}`);
35
+ try { rename(dir, quarantine); }
36
+ catch (error) { if (error?.code === "ENOENT") return false; throw error; }
37
+ const moved = filesystemIdentity(inspectDirectory(quarantine, label), label);
38
+ if (moved.dev !== pinnedIdentity.dev || moved.ino !== pinnedIdentity.ino) return false;
39
+ rmSync(quarantine, { recursive: true, force: false });
40
+ return true;
41
+ });
42
+ return result === true;
43
+ }
44
+ export function pruneRetiredManagedJobDirectories(jobRoot, logger = console) {
45
+ for (const retired of retiredManagedJobDirectories(jobRoot)) {
46
+ if (!retired.reclaimable) { logger.warn?.("retired managed-job directory generation is inconsistent; retaining it for inspection", { error_class: retired.error_class }); continue; }
47
+ try {
48
+ if (!removeManagedJobDirectoryIfCurrent(retired.dir, retired.identity, "retired managed job directory")) {
49
+ logger.warn?.("retired managed-job directory changed during reclamation; retaining it for inspection", { error_class: "integrity_error" });
50
+ }
51
+ } catch (error) {
52
+ if (error?.code !== "ENOENT") logger.warn?.("retired managed-job directory could not be reclaimed", { error_class: "resource_unavailable" });
53
+ }
54
+ }
55
+ }
56
+ function inspectDirectory(path, label) {
57
+ const info = lstatSync(path, { bigint: true });
58
+ if (info.isSymbolicLink() || !info.isDirectory()) throw new Error(`${label} must be a real directory`);
59
+ return info;
60
+ }
@@ -0,0 +1,75 @@
1
+ import { closeSync, constants as fsConstants, fstatSync, lstatSync, openSync, realpathSync } from "node:fs";
2
+ import { isAbsolute, join, relative, resolve, sep } from "node:path";
3
+ import { filesystemIdentity } from "./filesystem-identity.mjs";
4
+
5
+ export const MANAGED_JOB_ID = /^job_[A-Za-z0-9_-]{24,}$/;
6
+
7
+ export function resolveManagedJobDirectory(jobRoot, value, options = {}) {
8
+ const id = String(value || "");
9
+ if (!MANAGED_JOB_ID.test(id)) throw new Error("invalid job id");
10
+ const root = resolveManagedJobRootIfPresent(jobRoot, options);
11
+ if (!root) throw new Error("job not found or expired");
12
+ const candidate = join(root, id);
13
+ return withPinnedManagedJobDirectory(candidate, "managed job directory", options, false, (pinned, verify) => {
14
+ const canonical = (options.realpathSync || realpathSync)(candidate);
15
+ requireContained(root, canonical);
16
+ if (!sameDirectory(pinned, verify(candidate)) || !sameDirectory(pinned, verify(canonical))) {
17
+ throw new Error("managed job directory identity changed during inspection");
18
+ }
19
+ return canonical;
20
+ });
21
+ }
22
+
23
+ export function resolveManagedJobRootIfPresent(jobRoot, options = {}) {
24
+ const target = resolve(String(jobRoot || ""));
25
+ return withPinnedManagedJobDirectory(target, "managed job root", options, true, (pinned, verify) => {
26
+ const canonical = (options.realpathSync || realpathSync)(target);
27
+ if (!sameDirectory(pinned, verify(target))) throw new Error("managed job root identity changed during inspection");
28
+ if (!sameDirectory(pinned, verify(canonical))) {
29
+ throw new Error("managed job root canonical target does not match the inspected directory");
30
+ }
31
+ return canonical;
32
+ });
33
+ }
34
+
35
+ export function withPinnedManagedJobDirectory(target, label, options, missingAllowed, callback) {
36
+ const verify = options.lstatSync || ((value) => lstatSync(value, { bigint: true }));
37
+ const platform = String(options.platform || process.platform);
38
+ if (platform === "win32") {
39
+ let info;
40
+ try { info = verify(target); } catch (error) {
41
+ if (missingAllowed && error?.code === "ENOENT") return null;
42
+ throw error;
43
+ }
44
+ if (info.isSymbolicLink?.() || !info.isDirectory?.()) throw new Error(`${label} must be a real directory and not a symbolic link`);
45
+ return callback(info, verify);
46
+ }
47
+ const open = options.openSync || openSync;
48
+ let fd;
49
+ try { fd = open(target, fsConstants.O_RDONLY | fsConstants.O_NOFOLLOW | fsConstants.O_DIRECTORY, 0o700); }
50
+ catch (error) {
51
+ if (missingAllowed && error?.code === "ENOENT") return null;
52
+ if (["ELOOP", "ENOTDIR"].includes(error?.code)) throw new Error(`${label} must be a real directory and not a symbolic link`, { cause: error });
53
+ if (error?.code === "ENOENT") throw new Error("job not found or expired", { cause: error });
54
+ throw error;
55
+ }
56
+ try {
57
+ const info = (options.fstatSync || ((value) => fstatSync(value, { bigint: true })))(fd);
58
+ if (!info.isDirectory?.()) throw new Error(`${label} must be a real directory and not a symbolic link`);
59
+ return callback(info, verify);
60
+ } finally { (options.closeSync || closeSync)(fd); }
61
+ }
62
+
63
+ function sameDirectory(left, right) {
64
+ try {
65
+ if (right.isSymbolicLink?.() || !right.isDirectory?.()) return false;
66
+ const a = filesystemIdentity(left, "managed job directory");
67
+ const b = filesystemIdentity(right, "managed job directory");
68
+ return a.dev === b.dev && a.ino === b.ino;
69
+ } catch { return false; }
70
+ }
71
+
72
+ function requireContained(root, candidate) {
73
+ const value = relative(root, candidate);
74
+ if (!value || value === ".." || value.startsWith(`..${sep}`) || isAbsolute(value)) throw new Error("managed job directory escapes the managed job root");
75
+ }
@@ -0,0 +1,49 @@
1
+ import { BridgeError } from "./errors.mjs";
2
+ import { REMOTE_DURABLE_PROCESS_MAXIMUM_TIMEOUT_SECONDS } from "../shared/foreground-timeout.mjs";
3
+
4
+ const DURABLE_PROCESS_SOURCE_TOOLS = new Set(["exec_command", "run_process", "run_local_command"]);
5
+
6
+ export function startDurableProcessJob(manager, args = {}, context = {}) {
7
+ const sourceTool = String(args.sourceTool || "");
8
+ if (!DURABLE_PROCESS_SOURCE_TOOLS.has(sourceTool)) {
9
+ throw new BridgeError("invalid_request", "durable process execution requires a supported process source tool");
10
+ }
11
+ manager.authorizeTool(sourceTool);
12
+ manager.assertMaintenanceAvailable();
13
+ const timeoutSeconds = args.timeoutSeconds;
14
+ if (!Number.isSafeInteger(timeoutSeconds) || timeoutSeconds < 1 || timeoutSeconds > REMOTE_DURABLE_PROCESS_MAXIMUM_TIMEOUT_SECONDS) {
15
+ throw new BridgeError("invalid_request", `durable process execution timeout must be an integer from 1 to ${REMOTE_DURABLE_PROCESS_MAXIMUM_TIMEOUT_SECONDS} seconds`);
16
+ }
17
+ const accepted = manager.createJob({
18
+ name: String(args.name || `durable ${sourceTool}`).slice(0, 128),
19
+ ...(args.idempotencyKey === undefined ? {} : { idempotency_key: args.idempotencyKey }),
20
+ steps: [{
21
+ name: sourceTool,
22
+ argv: args.argv,
23
+ cwd: args.cwd,
24
+ timeout_seconds: timeoutSeconds,
25
+ capture_output: "redacted",
26
+ }],
27
+ }, {
28
+ launch: true,
29
+ executionPriority: "interactive",
30
+ delegatedProcess: args.delegatedProcess === true,
31
+ }, context);
32
+ return {
33
+ ...accepted,
34
+ execution_mode: "durable_job",
35
+ source_tool: sourceTool,
36
+ execution_timeout_seconds: timeoutSeconds,
37
+ progress: { status: accepted.status, current_phase: null, current_step: null },
38
+ recovery: {
39
+ tool: "read_job",
40
+ job_id: accepted.job_id,
41
+ fallback_tool: "list_jobs",
42
+ survives_mcp_disconnect: true,
43
+ survives_daemon_restart: true,
44
+ },
45
+ retry_safety: args.idempotencyKey === undefined
46
+ ? "retain job_id and inspect list_jobs before resubmitting after an ambiguous acceptance failure"
47
+ : "retry the same tool arguments with the same idempotency_key to recover the same durable job",
48
+ };
49
+ }