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,769 @@
1
+ import { createHash } from "node:crypto";
2
+
3
+ const MAX_DELTA_ENTRIES = 24;
4
+ const MAX_APPLICATION_POST_ELEMENTS = 24;
5
+ const BROWSER_IDENTITY_FIELDS = Object.freeze([
6
+ "tag", "type", "role", "name", "id", "field_name", "label", "placeholder", "href", "sensitive", "in_shadow_dom",
7
+ ]);
8
+ const BROWSER_COMPARABLE_FIELDS = Object.freeze([
9
+ ...BROWSER_IDENTITY_FIELDS, "visible", "enabled", "editable", "checked", "selected", "focused", "bounding_box",
10
+ ]);
11
+ const APPLICATION_COMPARABLE_FIELDS = Object.freeze([
12
+ "role", "subrole", "name", "title", "description", "identifier", "enabled", "focused", "checked", "selected", "expanded", "visible", "sensitive", "bounding_box", "_machine_owner_window_bounds",
13
+ ]);
14
+
15
+ export function extractBrowserPrivateBindings(captured) {
16
+ const frames = Array.isArray(captured?.semantic?.frames) ? captured.semantic.frames : [];
17
+ const semanticUrlCounts = browserSemanticUrlCounts(frames);
18
+ const cdpFrameUrls = browserCdpFrameUrls(captured);
19
+ const trustedBackends = browserTrustedBackends(captured, cdpFrameUrls);
20
+ const bindings = new Map();
21
+ for (const frame of frames) appendBrowserFrameBindings(bindings, frame, semanticUrlCounts, trustedBackends);
22
+ return {
23
+ browser_ref_bindings: bindings,
24
+ browser_history_entry_key: privateBrowserString(captured?._machine_history_entry_key, 512),
25
+ };
26
+ }
27
+
28
+ function browserSemanticUrlCounts(frames) {
29
+ const semanticUrlCounts = new Map();
30
+ for (const frame of frames) {
31
+ const url = privateBrowserString(frame?.document?.url, 8192);
32
+ if (url) semanticUrlCounts.set(url, (semanticUrlCounts.get(url) || 0) + 1);
33
+ }
34
+ return semanticUrlCounts;
35
+ }
36
+
37
+ function browserCdpFrameUrls(captured) {
38
+ const cdpFrameUrls = new Map();
39
+ for (const frame of Array.isArray(captured?.frame_tree) ? captured.frame_tree : []) {
40
+ const frameId = privateBrowserString(frame?.id, 32768);
41
+ const frameUrl = privateBrowserString(frame?.url, 8192);
42
+ if (!frameId || !frameUrl) continue;
43
+ if (cdpFrameUrls.has(frameId) && cdpFrameUrls.get(frameId) !== frameUrl) cdpFrameUrls.set(frameId, "");
44
+ else cdpFrameUrls.set(frameId, frameUrl);
45
+ }
46
+ return cdpFrameUrls;
47
+ }
48
+
49
+ function browserTrustedBackends(captured, cdpFrameUrls) {
50
+ const trustedBackends = new Map();
51
+ for (const node of Array.isArray(captured?.accessibility?.nodes) ? captured.accessibility.nodes : []) {
52
+ const ref = typeof node?.action_ref === "string" && node.action_ref && node.action_ref.length <= 100 && !node.action_ref.includes("\0")
53
+ ? node.action_ref : "";
54
+ const backendNodeId = node?.backend_dom_node_id;
55
+ const frameUrl = cdpFrameUrls.get(privateBrowserString(node?.frame_id, 32768)) || "";
56
+ if (node?.action_ref_confidence !== "high" || !ref || !frameUrl
57
+ || !Number.isSafeInteger(backendNodeId) || backendNodeId <= 0) continue;
58
+ const prior = trustedBackends.get(ref);
59
+ if (prior && (prior.backendNodeId !== backendNodeId || prior.frameUrl !== frameUrl)) trustedBackends.set(ref, null);
60
+ else if (!trustedBackends.has(ref)) trustedBackends.set(ref, { backendNodeId, frameUrl });
61
+ }
62
+ return trustedBackends;
63
+ }
64
+
65
+ function appendBrowserFrameBindings(bindings, frame, semanticUrlCounts, trustedBackends) {
66
+ const extensionFrameId = frame?.frame_id;
67
+ const extensionFrameEpoch = privateBrowserString(frame?.document?.epoch, 9000);
68
+ const extensionFrameUrl = privateBrowserString(frame?.document?.url, 8192);
69
+ if (!Number.isSafeInteger(extensionFrameId) || extensionFrameId < 0 || !extensionFrameEpoch || !extensionFrameUrl
70
+ || semanticUrlCounts.get(extensionFrameUrl) !== 1) return;
71
+ for (const element of Array.isArray(frame?.elements) ? frame.elements : []) {
72
+ const ref = typeof element?.ref === "string" ? element.ref : "";
73
+ const backendNodeId = element?._machine_backend_node_id;
74
+ const trusted = trustedBackends.get(ref);
75
+ if (!ref || ref.length > 100 || ref.includes("\0") || !Number.isSafeInteger(backendNodeId) || backendNodeId <= 0
76
+ || trusted?.backendNodeId !== backendNodeId || trusted?.frameUrl !== extensionFrameUrl) continue;
77
+ bindings.set(ref, {
78
+ backend_node_id: backendNodeId,
79
+ extension_frame_id: extensionFrameId,
80
+ extension_frame_epoch: extensionFrameEpoch,
81
+ extension_frame_url: extensionFrameUrl,
82
+ });
83
+ }
84
+ }
85
+
86
+ export function buildBrowserObservation(captured, args = {}) {
87
+ const inspected = record(captured?.semantic);
88
+ const accessibility = recordOrNull(captured?.accessibility);
89
+ const capture = browserCaptureMetadata(captured, args);
90
+ return {
91
+ snapshot_id: "",
92
+ surface: "browser",
93
+ captured_at: new Date().toISOString(),
94
+ document_epoch: privateBrowserString(captured?.document_epoch, 9000),
95
+ target: {
96
+ tab_id: browserObservationTabId(captured?.tab_id) ?? browserObservationTabId(inspected.tab_id),
97
+ url: privateBrowserString(captured?.url, 32768) || privateBrowserString(inspected.url, 32768),
98
+ title: privateBrowserText(captured?.title, 32768) || privateBrowserText(inspected.title, 32768),
99
+ },
100
+ capture,
101
+ capabilities: browserCapabilities(captured, accessibility, capture),
102
+ semantic: browserSemanticProjection(captured, inspected, accessibility),
103
+ };
104
+ }
105
+
106
+ export function observationDiff(before, after, beforePrivateState = null, afterPrivateState = null) {
107
+ const semanticDelta = before.surface === "browser"
108
+ ? browserSemanticDelta(before, after)
109
+ : applicationSemanticDelta(before, after, beforePrivateState, afterPrivateState);
110
+ const processChanged = before.surface === "application"
111
+ ? applicationProcessEpochChanged(beforePrivateState, afterPrivateState)
112
+ : null;
113
+ const semanticChanged = before.surface === "browser"
114
+ ? semanticFingerprint(before) !== semanticFingerprint(after)
115
+ : processChanged === true || semanticDelta.added_count > 0 || semanticDelta.removed_count > 0 || semanticDelta.changed_count > 0;
116
+ return {
117
+ target_changed: JSON.stringify(before.target) !== JSON.stringify(after.target) || processChanged === true,
118
+ process_changed: processChanged,
119
+ url_changed: before.surface === "browser" ? boundedStringChanged(before.target?.url, after.target?.url, 32768, false) : null,
120
+ title_changed: before.surface === "browser" ? boundedStringChanged(before.target?.title, after.target?.title, 32768, true) : null,
121
+ document_epoch_changed: before.surface === "browser" ? browserDocumentEpochChanged(before, after) : null,
122
+ frame_epoch_changed: before.surface === "browser" ? browserFrameEpochsChanged(before, after) : null,
123
+ history_entry_changed: before.surface === "browser" ? browserHistoryEntryChanged(beforePrivateState, afterPrivateState) : null,
124
+ screenshot_changed: screenshotChange(before, after),
125
+ semantic_changed: semanticChanged,
126
+ semantic_delta: semanticDelta,
127
+ };
128
+ }
129
+
130
+ export function buildContinuation(before, after, target, diff, beforePrivateState = null, afterPrivateState = null) {
131
+ if (!after) {
132
+ return {
133
+ available: false,
134
+ snapshot_id: null,
135
+ reobserve_recommended: true,
136
+ reason: "post_observation_unavailable",
137
+ };
138
+ }
139
+ if (after.surface === "application") {
140
+ const refs = (after.semantic?.elements || []).slice(0, MAX_APPLICATION_POST_ELEMENTS)
141
+ .map((element) => typeof element?.ref === "string" ? element.ref : "").filter(Boolean);
142
+ const targetMapping = mapApplicationTargetToPostSnapshot(before, after, target, beforePrivateState, afterPrivateState);
143
+ const salientRefs = targetMapping.mapped_post_target_ref && refs.includes(targetMapping.mapped_post_target_ref)
144
+ ? [targetMapping.mapped_post_target_ref, ...refs.filter((ref) => ref !== targetMapping.mapped_post_target_ref)]
145
+ : refs;
146
+ return {
147
+ available: true,
148
+ snapshot_id: after.snapshot_id,
149
+ surface: "application",
150
+ previous_refs_reusable: false,
151
+ previous_target_ref: targetMapping.previous_target_ref,
152
+ target_identity_continues: targetMapping.target_identity_continues,
153
+ mapped_post_target_ref: targetMapping.mapped_post_target_ref,
154
+ use_post_snapshot_ref: Boolean(targetMapping.mapped_post_target_ref),
155
+ target_identity_reason: targetMapping.reason,
156
+ post_snapshot_refs_available: refs.length > 0,
157
+ salient_post_refs: salientRefs.slice(0, 12),
158
+ reobserve_recommended: false,
159
+ reason: targetMapping.mapped_post_target_ref
160
+ ? "application_target_identity_mapped_to_post_snapshot"
161
+ : "application_refs_are_snapshot_scoped_use_post_observation_refs",
162
+ };
163
+ }
164
+ const delta = diff?.semantic_delta || emptyDelta();
165
+ const sameEpoch = diff?.document_epoch_changed === false;
166
+ const targetRef = target?.kind === "ref" && typeof target.ref === "string" ? target.ref : "";
167
+ const removedRefs = semanticRefs(delta.removed);
168
+ const addedRefs = semanticRefs(delta.added);
169
+ const changedRefs = semanticRefs(delta.changed.map((entry) => entry?.after));
170
+ const frameEpochChanged = diff?.frame_epoch_changed;
171
+ const targetFrameEpochSame = targetRef ? browserTargetFrameEpochSame(before, after, target) : null;
172
+ const postTarget = targetRef ? browserElementAt(after, target.frame_id, targetRef) : null;
173
+ const targetIdentityContinues = targetRef && targetFrameEpochSame === true && postTarget
174
+ ? browserElementIdentityMatches(target.element, postTarget)
175
+ : targetRef ? false : null;
176
+ const targetReusable = Boolean(
177
+ targetRef
178
+ && sameEpoch
179
+ && targetFrameEpochSame === true
180
+ && targetIdentityContinues === true
181
+ && !removedRefs.includes(targetRef),
182
+ );
183
+ const needsObserve = !sameEpoch || delta.truncated === true;
184
+ return {
185
+ available: true,
186
+ snapshot_id: after.snapshot_id,
187
+ surface: "browser",
188
+ document_epoch_same: sameEpoch,
189
+ frame_epoch_changed: typeof frameEpochChanged === "boolean" ? frameEpochChanged : null,
190
+ stable_ref_namespace: sameEpoch && frameEpochChanged === false,
191
+ previous_target_ref: targetRef || null,
192
+ previous_target_ref_reusable: targetReusable,
193
+ target_frame_epoch_same: targetFrameEpochSame,
194
+ target_identity_continues: targetIdentityContinues,
195
+ added_refs: addedRefs,
196
+ changed_refs: changedRefs,
197
+ removed_refs: removedRefs,
198
+ delta_truncated: delta.truncated === true,
199
+ reobserve_recommended: needsObserve,
200
+ reason: !sameEpoch
201
+ ? "document_epoch_changed"
202
+ : delta.truncated === true
203
+ ? "semantic_delta_truncated"
204
+ : targetRef && targetFrameEpochSame !== true
205
+ ? "target_frame_epoch_changed"
206
+ : targetRef && targetIdentityContinues !== true
207
+ ? "target_semantic_identity_changed"
208
+ : "post_snapshot_ready",
209
+ };
210
+ }
211
+
212
+ function mapApplicationTargetToPostSnapshot(before, after, target, beforePrivateState, afterPrivateState) {
213
+ const identity = applicationTargetIdentity(target, beforePrivateState);
214
+ if (!identity) {
215
+ return { previous_target_ref: null, target_identity_continues: null, mapped_post_target_ref: null, reason: "no_semantic_target" };
216
+ }
217
+ const processContinuity = applicationProcessContinuity(before, after, beforePrivateState, afterPrivateState);
218
+ if (processContinuity !== "same") {
219
+ return {
220
+ previous_target_ref: identity.ref,
221
+ target_identity_continues: false,
222
+ mapped_post_target_ref: null,
223
+ reason: processContinuity === "unknown" ? "application_process_identity_unavailable" : "application_process_changed",
224
+ };
225
+ }
226
+ const bindings = afterPrivateState?.application_ref_bindings;
227
+ if (!bindings?.entries) {
228
+ return { previous_target_ref: identity.ref, target_identity_continues: false, mapped_post_target_ref: null, reason: "post_identity_bindings_unavailable" };
229
+ }
230
+ const selectorKey = JSON.stringify(identity.selector || {});
231
+ for (const [ref, binding] of bindings.entries()) {
232
+ if (binding?.occurrence !== identity.occurrence || JSON.stringify(binding?.selector || {}) !== selectorKey) continue;
233
+ if (!applicationOwnerWindowContinues(identity.owner_window_bounds, boundedBox(binding?.owner_window_bounds))) {
234
+ return { previous_target_ref: identity.ref, target_identity_continues: false, mapped_post_target_ref: null, reason: "owner_window_changed" };
235
+ }
236
+ return {
237
+ previous_target_ref: identity.ref,
238
+ target_identity_continues: true,
239
+ mapped_post_target_ref: typeof ref === "string" ? ref : null,
240
+ reason: "selector_occurrence_and_owner_window_match",
241
+ };
242
+ }
243
+ return { previous_target_ref: identity.ref, target_identity_continues: false, mapped_post_target_ref: null, reason: "target_identity_missing_from_post_snapshot" };
244
+ }
245
+
246
+ function applicationTargetIdentity(target, privateState) {
247
+ const semantic = target?.kind === "ref" ? target : target?.kind === "point" ? target.semantic_delivery : null;
248
+ if (!semantic) return null;
249
+ const ref = typeof semantic.ref === "string" && semantic.ref ? semantic.ref : null;
250
+ const privateBinding = ref ? privateState?.application_ref_bindings?.get?.(ref) || null : null;
251
+ const selector = semantic.selector || privateBinding?.selector || null;
252
+ const occurrence = Number.isInteger(semantic.occurrence) ? semantic.occurrence : privateBinding?.occurrence;
253
+ if (!selector || !Number.isInteger(occurrence)) return null;
254
+ return {
255
+ ref,
256
+ selector,
257
+ occurrence,
258
+ owner_window_bounds: boundedBox(semantic.owner_window_bounds || privateBinding?.owner_window_bounds),
259
+ };
260
+ }
261
+
262
+ function applicationProcessContinuity(before, after, beforePrivateState, afterPrivateState) {
263
+ const beforeApplication = nativeBoundedString(before?.target?.application, 300, false);
264
+ const afterApplication = nativeBoundedString(after?.target?.application, 300, false);
265
+ if (!beforeApplication || !afterApplication) return "unknown";
266
+ if (beforeApplication !== afterApplication) return "changed";
267
+ const left = nativeBoundedString(before?.target?.process_name, 1000, true);
268
+ const right = nativeBoundedString(after?.target?.process_name, 1000, true);
269
+ if (left === null || right === null) return "unknown";
270
+ if (left && right && left !== right) return "changed";
271
+ const changed = applicationProcessEpochChanged(beforePrivateState, afterPrivateState);
272
+ return changed === null ? "unknown" : changed ? "changed" : "same";
273
+ }
274
+
275
+ function browserHistoryEntryChanged(beforePrivateState, afterPrivateState) {
276
+ const beforeKey = privateBrowserString(beforePrivateState?.browser_history_entry_key, 512);
277
+ const afterKey = privateBrowserString(afterPrivateState?.browser_history_entry_key, 512);
278
+ if (!beforeKey || !afterKey) return null;
279
+ return beforeKey !== afterKey;
280
+ }
281
+
282
+ function applicationProcessEpochChanged(beforePrivateState, afterPrivateState) {
283
+ const beforeId = beforePrivateState?.application_process_id;
284
+ const afterId = afterPrivateState?.application_process_id;
285
+ const beforeGeneration = beforePrivateState?.application_process_generation;
286
+ const afterGeneration = afterPrivateState?.application_process_generation;
287
+ if (!Number.isSafeInteger(beforeId) || beforeId < 1 || !Number.isSafeInteger(afterId) || afterId < 1
288
+ || typeof beforeGeneration !== "string" || !beforeGeneration || beforeGeneration.length > 2048 || /[\r\n\0]/.test(beforeGeneration)
289
+ || typeof afterGeneration !== "string" || !afterGeneration || afterGeneration.length > 2048 || /[\r\n\0]/.test(afterGeneration)) return null;
290
+ return beforeId !== afterId || beforeGeneration !== afterGeneration;
291
+ }
292
+
293
+ function nativeBoundedString(value, maxLength, allowEmpty) {
294
+ if (typeof value !== "string" || value.length > maxLength || value.includes("\0") || (!allowEmpty && !value)) return null;
295
+ return value;
296
+ }
297
+
298
+ function privateBrowserString(value, maxLength) {
299
+ return nativeBoundedString(value, maxLength, false) || "";
300
+ }
301
+
302
+ function privateBrowserText(value, maxLength) {
303
+ return nativeBoundedString(value, maxLength, true) ?? "";
304
+ }
305
+
306
+ function browserObservationTabId(value) {
307
+ return Number.isSafeInteger(value) && value > 0 ? value : null;
308
+ }
309
+
310
+ function boundedStringChanged(left, right, maxLength, allowEmpty) {
311
+ const a = nativeBoundedString(left, maxLength, allowEmpty);
312
+ const b = nativeBoundedString(right, maxLength, allowEmpty);
313
+ return a === null || b === null ? null : a !== b;
314
+ }
315
+
316
+ function browserObservationEpoch(observation) {
317
+ return privateBrowserString(observation?.capture?.semantic_epoch, 9000)
318
+ || privateBrowserString(observation?.document_epoch, 9000);
319
+ }
320
+
321
+ function browserDocumentEpochChanged(before, after) {
322
+ const left = browserObservationEpoch(before);
323
+ const right = browserObservationEpoch(after);
324
+ return left && right ? left !== right : null;
325
+ }
326
+
327
+ function applicationOwnerWindowContinues(beforeBounds, afterBounds) {
328
+ if (!beforeBounds && !afterBounds) return true;
329
+ if (!beforeBounds || !afterBounds) return false;
330
+ return ["x", "y", "width", "height"].every((key) => nearNumber(beforeBounds[key], afterBounds[key], 1));
331
+ }
332
+
333
+ export function projectPostObservation(observation, detail) {
334
+ if (detail === "full") return observation;
335
+ const base = compactObservationBase(observation);
336
+ if (observation.surface === "browser") return compactBrowserObservation(observation, base);
337
+ return compactApplicationObservation(observation, base);
338
+ }
339
+
340
+ function browserCaptureMetadata(captured, args) {
341
+ const source = record(captured?.capture);
342
+ return {
343
+ semantic: true,
344
+ screenshot: args.include_screenshot !== false,
345
+ atomic: source.atomic === true,
346
+ navigation_coherent: source.navigation_coherent === true,
347
+ frame_epochs_coherent: source.frame_epochs_coherent === true,
348
+ coherence: privateBrowserString(source.coherence, 128) || "unknown",
349
+ semantic_epoch: privateBrowserString(source.semantic_epoch, 9000),
350
+ cdp_epoch: privateBrowserString(source.cdp_epoch, 9000),
351
+ cdp: source.cdp === true,
352
+ cdp_components: publicRecordOrNull(source.cdp_components),
353
+ screenshot_source: privateBrowserString(source.screenshot_source, 64) || "none",
354
+ screenshot_format: source.screenshot_format === "png" || source.screenshot_format === "jpeg" ? source.screenshot_format : "",
355
+ screenshot_quality: validScreenshotQuality(source.screenshot_quality),
356
+ screenshot_sha256: validSha256(source.screenshot_sha256),
357
+ ...(privateBrowserText(source.fallback_reason, 500) ? { fallback_reason: privateBrowserText(source.fallback_reason, 500) } : {}),
358
+ ...(privateBrowserText(source.screenshot_fallback_reason, 500) ? { screenshot_fallback_reason: privateBrowserText(source.screenshot_fallback_reason, 500) } : {}),
359
+ };
360
+ }
361
+
362
+ function browserCapabilities(captured, accessibility, capture) {
363
+ const fusedActionRefs = Array.isArray(accessibility?.nodes)
364
+ ? accessibility.nodes.filter((node) => node?.action_ref_confidence === "high" && typeof node?.action_ref === "string").length
365
+ : 0;
366
+ return {
367
+ snapshot_bound_refs: true,
368
+ stable_backend_refs: true,
369
+ screenshot: true,
370
+ action_verification: true,
371
+ chromium_accessibility_tree: Boolean(accessibility && accessibility.available !== false),
372
+ fused_accessibility_action_refs: fusedActionRefs,
373
+ cdp_surface_screenshot: capture.screenshot_source === "cdp_surface",
374
+ document_epoch_preflight: Boolean(capture.semantic_epoch),
375
+ snapshot_bound_visual_points: capture.screenshot_source === "cdp_surface"
376
+ && capture.navigation_coherent === true
377
+ && Boolean(capture.screenshot_sha256)
378
+ && isPositiveViewport(captured?.viewport),
379
+ visual_grounding: false,
380
+ };
381
+ }
382
+
383
+ function browserSemanticProjection(captured, inspected, accessibility) {
384
+ return {
385
+ kind: accessibility?.available !== false && accessibility ? "browser-hybrid" : "browser-dom",
386
+ frames: sanitizeBrowserFrames(inspected.frames),
387
+ total_elements: nonNegativeSafeInteger(inspected.total_elements),
388
+ max_elements: nonNegativeSafeInteger(inspected.max_elements),
389
+ frames_truncated: inspected.frames_truncated === true,
390
+ selection: publicRecordOrNull(inspected.selection),
391
+ accessibility: sanitizeAccessibility(accessibility),
392
+ viewport: publicRecordOrNull(captured?.viewport),
393
+ frame_tree: Array.isArray(captured?.frame_tree) ? captured.frame_tree.map((frame) => publicRecord(frame)) : [],
394
+ };
395
+ }
396
+
397
+ function sanitizeAccessibility(accessibility) {
398
+ if (!accessibility) return null;
399
+ const publicAccessibility = publicRecord(accessibility);
400
+ delete publicAccessibility.nodes;
401
+ return {
402
+ ...publicAccessibility,
403
+ nodes: (Array.isArray(accessibility.nodes) ? accessibility.nodes : [])
404
+ .map((node) => publicRecord(node, new Set(["backend_dom_node_id", "backendDOMNodeId"]))),
405
+ };
406
+ }
407
+
408
+ function sanitizeBrowserFrames(frames) {
409
+ return (Array.isArray(frames) ? frames : []).map((frame) => {
410
+ const publicFrame = publicRecord(frame);
411
+ delete publicFrame.document;
412
+ delete publicFrame.elements;
413
+ return {
414
+ ...publicFrame,
415
+ document: publicRecord(frame?.document),
416
+ elements: (Array.isArray(frame?.elements) ? frame.elements : [])
417
+ .map((element) => publicRecord(element, new Set(["backend_dom_node_id", "backendDOMNodeId"]))),
418
+ };
419
+ });
420
+ }
421
+
422
+ function browserSemanticDelta(before, after) {
423
+ return mapSemanticDelta(
424
+ browserElementMap(before),
425
+ browserElementMap(after),
426
+ browserElementSummary,
427
+ BROWSER_COMPARABLE_FIELDS,
428
+ );
429
+ }
430
+
431
+ function browserElementMap(observation) {
432
+ const map = new Map();
433
+ const topEpoch = browserObservationEpoch(observation);
434
+ if (!topEpoch) return map;
435
+ for (const frame of observation.semantic?.frames || []) {
436
+ if (!Number.isSafeInteger(frame?.frame_id) || frame.frame_id < 0) continue;
437
+ const frameEpoch = privateBrowserString(frame?.document?.epoch, 9000) || topEpoch;
438
+ const frameUrl = privateBrowserString(frame?.document?.url, 32768);
439
+ if (!frameEpoch || !frameUrl) continue;
440
+ for (const element of frame?.elements || []) {
441
+ if (typeof element?.ref !== "string" || !element.ref) continue;
442
+ map.set(`${topEpoch}|${frame.frame_id}|${frameEpoch}|${frameUrl}|${element.ref}`, { ...element, frame_id: frame.frame_id });
443
+ }
444
+ }
445
+ return map;
446
+ }
447
+
448
+ function browserFrameEpochsChanged(before, after) {
449
+ if (before.semantic?.frames_truncated === true || after.semantic?.frames_truncated === true) return null;
450
+ const left = browserFrameEpochMap(before);
451
+ const right = browserFrameEpochMap(after);
452
+ if (!left || !right) return null;
453
+ if (left.size !== right.size) return true;
454
+ for (const [frameId, identity] of left) if (right.get(frameId) !== identity) return true;
455
+ return false;
456
+ }
457
+
458
+ function browserFrameEpochMap(observation) {
459
+ const map = new Map();
460
+ for (const frame of observation.semantic?.frames || []) {
461
+ if (!Number.isSafeInteger(frame?.frame_id) || frame.frame_id < 0) return null;
462
+ const epoch = privateBrowserString(frame?.document?.epoch, 9000);
463
+ const url = privateBrowserString(frame?.document?.url, 32768);
464
+ if (!epoch || !url) return null;
465
+ map.set(frame.frame_id, `${epoch}\u0000${url}`);
466
+ }
467
+ return map;
468
+ }
469
+
470
+ function browserTargetFrameEpochSame(before, after, target) {
471
+ if (!Number.isSafeInteger(target?.frame_id) || target.frame_id < 0) return false;
472
+ const beforeFrame = (before.semantic?.frames || []).find((frame) => frame?.frame_id === target.frame_id);
473
+ const afterFrame = (after.semantic?.frames || []).find((frame) => frame?.frame_id === target.frame_id);
474
+ if (!beforeFrame || !afterFrame) return false;
475
+ const beforeEpoch = privateBrowserString(beforeFrame.document?.epoch, 9000);
476
+ const afterEpoch = privateBrowserString(afterFrame.document?.epoch, 9000);
477
+ const beforeUrl = privateBrowserString(beforeFrame.document?.url, 32768);
478
+ const afterUrl = privateBrowserString(afterFrame.document?.url, 32768);
479
+ return Boolean(beforeEpoch && afterEpoch && beforeUrl && afterUrl)
480
+ && beforeEpoch === afterEpoch
481
+ && beforeUrl === afterUrl;
482
+ }
483
+
484
+ function browserElementAt(observation, frameId, ref) {
485
+ const frame = (observation.semantic?.frames || []).find((candidate) => candidate?.frame_id === frameId);
486
+ return (frame?.elements || []).find((element) => element?.ref === ref) || null;
487
+ }
488
+
489
+ function browserElementIdentityMatches(before, after) {
490
+ if (!before || !after) return false;
491
+ return BROWSER_IDENTITY_FIELDS.every((field) => !Object.hasOwn(before, field) || equivalentField(before[field], after[field], field));
492
+ }
493
+
494
+ function applicationSemanticDelta(before, after, beforePrivateState, afterPrivateState) {
495
+ return mapSemanticDelta(
496
+ applicationElementMap(before, beforePrivateState),
497
+ applicationElementMap(after, afterPrivateState),
498
+ applicationElementSummary,
499
+ APPLICATION_COMPARABLE_FIELDS,
500
+ );
501
+ }
502
+
503
+ function applicationElementMap(observation, privateState = null) {
504
+ const map = new Map();
505
+ const bindings = privateState?.application_ref_bindings;
506
+ const fallbackOccurrences = new Map();
507
+ for (const element of observation.semantic?.elements || []) {
508
+ const binding = bindings?.get?.(element?.ref);
509
+ let key = "";
510
+ if (binding?.selector && Number.isInteger(binding.occurrence)) {
511
+ key = `${JSON.stringify(binding.selector)}#${binding.occurrence}`;
512
+ } else {
513
+ const identity = JSON.stringify([
514
+ element.identifier || "", element.role || "", element.subrole || "", element.name || "",
515
+ element.title || "", element.description || "",
516
+ ]);
517
+ const occurrence = fallbackOccurrences.get(identity) || 0;
518
+ fallbackOccurrences.set(identity, occurrence + 1);
519
+ key = `${identity}#${occurrence}`;
520
+ }
521
+ map.set(key, {
522
+ ...element,
523
+ _machine_owner_window_bounds: binding?.owner_window_bounds || null,
524
+ });
525
+ }
526
+ return map;
527
+ }
528
+
529
+ function mapSemanticDelta(beforeMap, afterMap, summarize, comparableFields) {
530
+ const added = [];
531
+ const removed = [];
532
+ const changed = [];
533
+ let addedCount = 0;
534
+ let removedCount = 0;
535
+ let changedCount = 0;
536
+ for (const [key, value] of afterMap) {
537
+ if (!beforeMap.has(key)) {
538
+ addedCount += 1;
539
+ pushBounded(added, summarize(value));
540
+ continue;
541
+ }
542
+ const previous = beforeMap.get(key);
543
+ const fields = comparableFields
544
+ .filter((field) => !equivalentField(previous?.[field], value?.[field], field))
545
+ .map(publicChangedField);
546
+ if (!fields.length) continue;
547
+ changedCount += 1;
548
+ pushBounded(changed, {
549
+ before: summarize(previous),
550
+ after: summarize(value),
551
+ changed_fields: fields,
552
+ });
553
+ }
554
+ for (const [key, value] of beforeMap) {
555
+ if (afterMap.has(key)) continue;
556
+ removedCount += 1;
557
+ pushBounded(removed, summarize(value));
558
+ }
559
+ return {
560
+ before_count: beforeMap.size,
561
+ after_count: afterMap.size,
562
+ added_count: addedCount,
563
+ removed_count: removedCount,
564
+ changed_count: changedCount,
565
+ added,
566
+ removed,
567
+ changed,
568
+ truncated: addedCount > added.length || removedCount > removed.length || changedCount > changed.length,
569
+ };
570
+ }
571
+
572
+ function browserElementSummary(element) {
573
+ return {
574
+ ref: typeof element?.ref === "string" ? element.ref : "",
575
+ frame_id: Number.isInteger(element?.frame_id) ? element.frame_id : null,
576
+ role: boundedText(element?.role, 200),
577
+ name: boundedText(element?.name || element?.label || element?.placeholder, 500),
578
+ visible: element?.visible === true,
579
+ enabled: element?.enabled === true,
580
+ editable: element?.editable === true,
581
+ checked: element?.checked === true,
582
+ focused: element?.focused === true,
583
+ sensitive: element?.sensitive === true,
584
+ bounding_box: boundedBox(element?.bounding_box),
585
+ };
586
+ }
587
+
588
+ function applicationElementSummary(element) {
589
+ return {
590
+ ref: typeof element?.ref === "string" ? element.ref : "",
591
+ role: boundedText(element?.role, 200),
592
+ subrole: boundedText(element?.subrole, 200),
593
+ name: boundedText(element?.name || element?.title || element?.description, 500),
594
+ identifier: boundedText(element?.identifier, 500),
595
+ enabled: element?.enabled === true,
596
+ focused: element?.focused === true,
597
+ checked: typeof element?.checked === "boolean" ? element.checked : null,
598
+ selected: typeof element?.selected === "boolean" ? element.selected : null,
599
+ expanded: typeof element?.expanded === "boolean" ? element.expanded : null,
600
+ visible: element?.visible === true,
601
+ sensitive: element?.sensitive === true,
602
+ bounding_box: boundedBox(element?.bounding_box),
603
+ };
604
+ }
605
+
606
+ function equivalentField(left, right, field) {
607
+ if (field !== "bounding_box" && field !== "_machine_owner_window_bounds") return JSON.stringify(left ?? null) === JSON.stringify(right ?? null);
608
+ if (!left && !right) return true;
609
+ if (!left || !right) return false;
610
+ const tolerance = field === "_machine_owner_window_bounds" ? 1 : 2;
611
+ return ["x", "y", "width", "height"].every((key) => nearNumber(left[key], right[key], tolerance));
612
+ }
613
+
614
+ function publicChangedField(field) {
615
+ return field === "_machine_owner_window_bounds" ? "owner_window" : field;
616
+ }
617
+
618
+ function compactObservationBase(observation) {
619
+ return {
620
+ snapshot_id: observation.snapshot_id,
621
+ surface: observation.surface,
622
+ captured_at: observation.captured_at,
623
+ target: observation.target,
624
+ capture: observation.capture,
625
+ capabilities: observation.capabilities,
626
+ };
627
+ }
628
+
629
+ function compactBrowserObservation(observation, base) {
630
+ const accessibility = observation.semantic?.accessibility;
631
+ return {
632
+ ...base,
633
+ document_epoch: observation.document_epoch || "",
634
+ semantic: {
635
+ kind: observation.semantic?.kind || "",
636
+ total_elements: nonNegativeSafeInteger(observation.semantic?.total_elements),
637
+ max_elements: nonNegativeSafeInteger(observation.semantic?.max_elements),
638
+ frames_truncated: observation.semantic?.frames_truncated === true,
639
+ selection: observation.semantic?.selection || null,
640
+ viewport: observation.semantic?.viewport || null,
641
+ accessibility: accessibility ? {
642
+ available: accessibility.available !== false,
643
+ returned_nodes: nonNegativeSafeInteger(accessibility.returned_nodes),
644
+ observed_nodes: nonNegativeSafeInteger(accessibility.observed_nodes),
645
+ ignored_nodes: nonNegativeSafeInteger(accessibility.ignored_nodes),
646
+ truncated: accessibility.truncated === true,
647
+ query_matched: typeof accessibility.query_matched === "boolean" ? accessibility.query_matched : null,
648
+ query_match_count: optionalFiniteNumber(accessibility.query_match_count),
649
+ query_search_exhaustive: typeof accessibility.query_search_exhaustive === "boolean" ? accessibility.query_search_exhaustive : null,
650
+ top_query_score: optionalFiniteNumber(accessibility.top_query_score),
651
+ failed_frame_count: nonNegativeSafeInteger(accessibility.failed_frame_count),
652
+ } : null,
653
+ },
654
+ };
655
+ }
656
+
657
+ function compactApplicationObservation(observation, base) {
658
+ const elements = Array.isArray(observation.semantic?.elements) ? observation.semantic.elements : [];
659
+ const returned = elements.slice(0, MAX_APPLICATION_POST_ELEMENTS).map(applicationElementSummary);
660
+ return {
661
+ ...base,
662
+ semantic: {
663
+ kind: observation.semantic?.kind || "",
664
+ element_count: elements.length,
665
+ truncated: observation.semantic?.truncated === true,
666
+ menus_included: observation.semantic?.menus_included === true,
667
+ selection: observation.semantic?.selection || null,
668
+ elements: returned,
669
+ elements_truncated: elements.length > returned.length,
670
+ },
671
+ };
672
+ }
673
+
674
+ function semanticRefs(values) {
675
+ const refs = [];
676
+ for (const value of values || []) {
677
+ const ref = typeof value?.ref === "string" ? value.ref : "";
678
+ if (ref && !refs.includes(ref)) refs.push(ref);
679
+ }
680
+ return refs;
681
+ }
682
+
683
+ function emptyDelta() {
684
+ return { added: [], removed: [], changed: [], truncated: false };
685
+ }
686
+
687
+ function screenshotChange(before, after) {
688
+ const left = validSha256(before.capture?.screenshot_sha256);
689
+ const right = validSha256(after.capture?.screenshot_sha256);
690
+ return left && right ? left !== right : null;
691
+ }
692
+
693
+ function validScreenshotQuality(value) {
694
+ if (value === undefined || value === null) return null;
695
+ return Number.isInteger(value) && value >= 1 && value <= 100 ? value : null;
696
+ }
697
+
698
+ function validSha256(value) {
699
+ if (typeof value !== "string") return "";
700
+ const digest = value.toLowerCase();
701
+ return /^[a-f0-9]{64}$/.test(digest) ? digest : "";
702
+ }
703
+
704
+ function semanticFingerprint(observation) {
705
+ return createHash("sha256").update(JSON.stringify({ target: observation.target, semantic: observation.semantic })).digest("hex");
706
+ }
707
+
708
+ function isPositiveViewport(value) {
709
+ return Boolean(value
710
+ && typeof value.width === "number" && Number.isFinite(value.width) && value.width > 0
711
+ && typeof value.height === "number" && Number.isFinite(value.height) && value.height > 0
712
+ && typeof value.scale === "number" && Number.isFinite(value.scale) && value.scale > 0);
713
+ }
714
+
715
+ function record(value) {
716
+ return value && typeof value === "object" && !Array.isArray(value) ? value : {};
717
+ }
718
+
719
+ function publicRecord(value, excluded = null) {
720
+ if (!value || typeof value !== "object" || Array.isArray(value)) return {};
721
+ const output = {};
722
+ for (const [key, item] of Object.entries(value)) {
723
+ if (key.startsWith("_machine_") || excluded?.has(key)) continue;
724
+ output[key] = item;
725
+ }
726
+ return output;
727
+ }
728
+
729
+ function publicRecordOrNull(value) {
730
+ return value && typeof value === "object" && !Array.isArray(value) ? publicRecord(value) : null;
731
+ }
732
+
733
+ function nonNegativeSafeInteger(value) {
734
+ return Number.isSafeInteger(value) && value >= 0 ? value : 0;
735
+ }
736
+
737
+ function optionalFiniteNumber(value) {
738
+ return typeof value === "number" && Number.isFinite(value) ? value : null;
739
+ }
740
+
741
+
742
+ function recordOrNull(value) {
743
+ return value && typeof value === "object" && !Array.isArray(value) ? value : null;
744
+ }
745
+
746
+ function pushBounded(list, value) {
747
+ if (list.length < MAX_DELTA_ENTRIES) list.push(value);
748
+ }
749
+
750
+ function boundedBox(value) {
751
+ if (!value || typeof value !== "object" || Array.isArray(value)) return null;
752
+ const out = {};
753
+ for (const key of ["x", "y", "width", "height"]) {
754
+ const number = value[key];
755
+ if (typeof number !== "number" || !Number.isFinite(number)) return null;
756
+ out[key] = Math.round(number * 100) / 100;
757
+ }
758
+ return out;
759
+ }
760
+
761
+ function boundedText(value, max) {
762
+ return typeof value === "string" ? value.slice(0, max) : "";
763
+ }
764
+
765
+ function nearNumber(left, right, tolerance) {
766
+ return typeof left === "number" && Number.isFinite(left)
767
+ && typeof right === "number" && Number.isFinite(right)
768
+ && Math.abs(left - right) <= tolerance;
769
+ }