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,1051 @@
1
+ import AppKit
2
+ import CoreGraphics
3
+ import Darwin
4
+ import Foundation
5
+
6
+ private let skyLightPath = "/System/Library/PrivateFrameworks/SkyLight.framework/SkyLight"
7
+ private let hiServicesPath = "/System/Library/Frameworks/ApplicationServices.framework/Frameworks/HIServices.framework/HIServices"
8
+
9
+ private typealias PostToPidFn = @convention(c) (pid_t, UnsafeMutableRawPointer?) -> Void
10
+ private typealias SetWindowLocationFn = @convention(c) (UnsafeMutableRawPointer?, Double, Double) -> Void
11
+ private typealias SetIntegerFieldFn = @convention(c) (UnsafeMutableRawPointer?, UInt32, Int64) -> Void
12
+ private typealias PostEventRecordFn = @convention(c) (UnsafeRawPointer?, UnsafeRawPointer?) -> Int32
13
+ private typealias GetFrontProcessFn = @convention(c) (UnsafeMutableRawPointer?) -> Int32
14
+ private typealias GetProcessForPidFn = @convention(c) (pid_t, UnsafeMutableRawPointer?) -> Int32
15
+
16
+ private struct Request: Decodable {
17
+ let operation: String
18
+ let pid: Int32?
19
+ let process_generation: String?
20
+ let window_id: UInt32?
21
+ let screen_x: Double?
22
+ let screen_y: Double?
23
+ let local_x: Double?
24
+ let local_y: Double?
25
+ let destination_screen_x: Double?
26
+ let destination_screen_y: Double?
27
+ let destination_local_x: Double?
28
+ let destination_local_y: Double?
29
+ let delta_x: Double?
30
+ let delta_y: Double?
31
+ let click_count: Int?
32
+ let text: String?
33
+ let key: String?
34
+ let window_x: Double?
35
+ let window_y: Double?
36
+ let window_width: Double?
37
+ let window_height: Double?
38
+ }
39
+
40
+ private struct Response: Encodable {
41
+ let ok: Bool
42
+ let backend: String
43
+ let focus_without_raise: Bool?
44
+ let frontmost_restored: Bool?
45
+ let front_window_validated: Bool?
46
+ let cursor_preserved: Bool?
47
+ let dispatch_started: Bool?
48
+ let error: String?
49
+ let input_transport: String?
50
+
51
+ init(
52
+ ok: Bool,
53
+ backend: String,
54
+ focus_without_raise: Bool?,
55
+ frontmost_restored: Bool?,
56
+ front_window_validated: Bool?,
57
+ cursor_preserved: Bool?,
58
+ dispatch_started: Bool?,
59
+ error: String?,
60
+ input_transport: String? = nil
61
+ ) {
62
+ self.ok = ok
63
+ self.backend = backend
64
+ self.focus_without_raise = focus_without_raise
65
+ self.frontmost_restored = frontmost_restored
66
+ self.front_window_validated = front_window_validated
67
+ self.cursor_preserved = cursor_preserved
68
+ self.dispatch_started = dispatch_started
69
+ self.error = error
70
+ self.input_transport = input_transport
71
+ }
72
+ }
73
+
74
+ private final class SkyLightSymbols {
75
+ let sky: UnsafeMutableRawPointer
76
+ let hi: UnsafeMutableRawPointer
77
+ let postToPid: PostToPidFn
78
+ let setWindowLocation: SetWindowLocationFn
79
+ let setIntegerField: SetIntegerFieldFn
80
+ let postEventRecord: PostEventRecordFn
81
+ let getFrontProcess: GetFrontProcessFn
82
+ let getProcessForPid: GetProcessForPidFn
83
+
84
+ init?() {
85
+ guard let sky = dlopen(skyLightPath, RTLD_LAZY | RTLD_GLOBAL),
86
+ let hi = dlopen(hiServicesPath, RTLD_LAZY | RTLD_GLOBAL) else { return nil }
87
+ func load<T>(_ handle: UnsafeMutableRawPointer, _ name: String, _: T.Type) -> T? {
88
+ guard let pointer = dlsym(handle, name) else { return nil }
89
+ return unsafeBitCast(pointer, to: T.self)
90
+ }
91
+ guard let postToPid = load(sky, "SLEventPostToPid", PostToPidFn.self),
92
+ let setWindowLocation = load(sky, "CGEventSetWindowLocation", SetWindowLocationFn.self),
93
+ let setIntegerField = load(sky, "SLEventSetIntegerValueField", SetIntegerFieldFn.self),
94
+ let postEventRecord = load(sky, "SLPSPostEventRecordTo", PostEventRecordFn.self),
95
+ let getFrontProcess = load(sky, "_SLPSGetFrontProcess", GetFrontProcessFn.self),
96
+ let getProcessForPid = load(hi, "GetProcessForPID", GetProcessForPidFn.self) else { return nil }
97
+ self.sky = sky
98
+ self.hi = hi
99
+ self.postToPid = postToPid
100
+ self.setWindowLocation = setWindowLocation
101
+ self.setIntegerField = setIntegerField
102
+ self.postEventRecord = postEventRecord
103
+ self.getFrontProcess = getFrontProcess
104
+ self.getProcessForPid = getProcessForPid
105
+ }
106
+
107
+ deinit {
108
+ dlclose(hi)
109
+ dlclose(sky)
110
+ }
111
+ }
112
+
113
+ private func encode(_ response: Response) {
114
+ let encoder = JSONEncoder()
115
+ guard let data = try? encoder.encode(response), let text = String(data: data, encoding: .utf8) else {
116
+ print("{\"ok\":false,\"backend\":\"skylight-experimental\",\"error\":\"encoding_failed\"}")
117
+ return
118
+ }
119
+ print(text)
120
+ }
121
+
122
+ private struct FocusPreparationResult {
123
+ let ok: Bool
124
+ let dispatchStarted: Bool
125
+ }
126
+
127
+ private enum PointerTransport {
128
+ case skyLight
129
+ case publicCGEvent
130
+
131
+ var label: String {
132
+ switch self {
133
+ case .skyLight: "skylight-pid"
134
+ case .publicCGEvent: "public-cgevent-pid"
135
+ }
136
+ }
137
+ }
138
+
139
+ private func pointerTransport(application: NSRunningApplication) -> PointerTransport {
140
+ let bundleId = String(application.bundleIdentifier ?? "").lowercased()
141
+ let skyLightPrefixes = [
142
+ "com.google.chrome", "org.chromium.chromium", "com.microsoft.edgemac",
143
+ "company.thebrowser.browser", "com.brave.browser", "com.vivaldi.vivaldi",
144
+ ]
145
+ if skyLightPrefixes.contains(where: { bundleId.hasPrefix($0) }) { return .skyLight }
146
+ if let bundleURL = application.bundleURL,
147
+ let info = Bundle(url: bundleURL)?.infoDictionary {
148
+ let principal = String(info["NSPrincipalClass"] as? String ?? "")
149
+ if principal.contains("AtomApplication") || info["ElectronAsarIntegrity"] != nil { return .skyLight }
150
+ if info["UIApplicationSceneManifest"] != nil || info["UIDeviceFamily"] != nil { return .skyLight }
151
+ }
152
+ return .publicCGEvent
153
+ }
154
+
155
+ private func postPointerEvent(_ event: CGEvent, symbols: SkyLightSymbols, pid: pid_t, transport: PointerTransport) {
156
+ switch transport {
157
+ case .skyLight:
158
+ symbols.postToPid(pid, Unmanaged.passUnretained(event).toOpaque())
159
+ case .publicCGEvent:
160
+ event.postToPid(pid)
161
+ }
162
+ }
163
+
164
+ private func frontmostInstanceStillMatches(_ expected: NSRunningApplication?) -> Bool {
165
+ guard let expected else { return NSWorkspace.shared.frontmostApplication == nil }
166
+ guard !expected.isTerminated, let current = NSWorkspace.shared.frontmostApplication else { return false }
167
+ return current.isEqual(expected)
168
+ }
169
+
170
+ private func focusContinuationStillAuthorized(
171
+ priorFront: NSRunningApplication,
172
+ targetApplication: NSRunningApplication
173
+ ) -> Bool {
174
+ guard !priorFront.isTerminated, !targetApplication.isTerminated else { return false }
175
+ guard let current = NSWorkspace.shared.frontmostApplication else { return true }
176
+ return current.isEqual(priorFront) || current.isEqual(targetApplication)
177
+ }
178
+
179
+ private func skyLightInputStillAuthorized(
180
+ frameworkTransport: PointerTransport,
181
+ priorFront: NSRunningApplication?,
182
+ targetApplication: NSRunningApplication,
183
+ focusDispatched: Bool
184
+ ) -> Bool {
185
+ guard frameworkTransport == .skyLight else { return true }
186
+ guard !targetApplication.isTerminated, let current = NSWorkspace.shared.frontmostApplication else { return false }
187
+ if !focusDispatched { return current.isEqual(targetApplication) }
188
+ guard let priorFront, !priorFront.isTerminated else { return current.isEqual(targetApplication) }
189
+ return current.isEqual(priorFront) || current.isEqual(targetApplication)
190
+ }
191
+
192
+ private func inputBoundaryStillValid(
193
+ pid: pid_t,
194
+ application: NSRunningApplication,
195
+ windowId: UInt32,
196
+ expected: CGRect,
197
+ frameworkTransport: PointerTransport,
198
+ priorFront: NSRunningApplication?,
199
+ focusDispatched: Bool
200
+ ) -> Bool {
201
+ frontWindowStillMatches(pid: pid, application: application, windowId: windowId, expected: expected)
202
+ && skyLightInputStillAuthorized(
203
+ frameworkTransport: frameworkTransport, priorFront: priorFront,
204
+ targetApplication: application, focusDispatched: focusDispatched
205
+ )
206
+ }
207
+
208
+ private func prepareFocusIfNeeded(
209
+ _ symbols: SkyLightSymbols,
210
+ pid: pid_t,
211
+ windowId: UInt32,
212
+ frameworkTransport: PointerTransport,
213
+ priorFront: NSRunningApplication?,
214
+ targetApplication: NSRunningApplication
215
+ ) -> FocusPreparationResult {
216
+ guard frameworkTransport == .skyLight else { return FocusPreparationResult(ok: true, dispatchStarted: false) }
217
+ guard frontmostInstanceStillMatches(priorFront) else {
218
+ return FocusPreparationResult(ok: false, dispatchStarted: false)
219
+ }
220
+ if let priorFront, priorFront.isEqual(targetApplication) {
221
+ return FocusPreparationResult(ok: true, dispatchStarted: false)
222
+ }
223
+ guard let priorFront, !priorFront.isTerminated else {
224
+ return FocusPreparationResult(ok: false, dispatchStarted: false)
225
+ }
226
+ return focusWithoutRaise(
227
+ symbols, pid: pid, windowId: windowId, priorFront: priorFront, targetApplication: targetApplication
228
+ )
229
+ }
230
+
231
+ private func focusWithoutRaise(
232
+ _ symbols: SkyLightSymbols,
233
+ pid: pid_t,
234
+ windowId: UInt32,
235
+ priorFront: NSRunningApplication,
236
+ targetApplication: NSRunningApplication
237
+ ) -> FocusPreparationResult {
238
+ guard processInstanceStillMatches(pid: pid, application: targetApplication),
239
+ frontmostInstanceStillMatches(priorFront), !priorFront.isTerminated else {
240
+ return FocusPreparationResult(ok: false, dispatchStarted: false)
241
+ }
242
+ var previous = [UInt8](repeating: 0, count: 8)
243
+ var expectedPrevious = [UInt8](repeating: 0, count: 8)
244
+ var target = [UInt8](repeating: 0, count: 8)
245
+ let previousResolved = previous.withUnsafeMutableBytes { symbols.getFrontProcess($0.baseAddress) == 0 }
246
+ let expectedPreviousResolved = expectedPrevious.withUnsafeMutableBytes {
247
+ symbols.getProcessForPid(priorFront.processIdentifier, $0.baseAddress) == 0
248
+ }
249
+ let targetResolved = target.withUnsafeMutableBytes { symbols.getProcessForPid(pid, $0.baseAddress) == 0 }
250
+ guard previousResolved && expectedPreviousResolved && targetResolved,
251
+ previous == expectedPrevious,
252
+ processInstanceStillMatches(pid: pid, application: targetApplication),
253
+ frontmostInstanceStillMatches(priorFront), !priorFront.isTerminated else {
254
+ return FocusPreparationResult(ok: false, dispatchStarted: false)
255
+ }
256
+
257
+ var record = [UInt8](repeating: 0, count: 0xF8)
258
+ record[0x04] = 0xF8
259
+ record[0x08] = 0x0D
260
+ let littleEndian = windowId.littleEndian
261
+ withUnsafeBytes(of: littleEndian) { bytes in
262
+ for index in 0..<4 { record[0x3C + index] = bytes[index] }
263
+ }
264
+ var lastHopPrevious = [UInt8](repeating: 0, count: 8)
265
+ let lastHopPreviousResolved = lastHopPrevious.withUnsafeMutableBytes { symbols.getFrontProcess($0.baseAddress) == 0 }
266
+ guard lastHopPreviousResolved, lastHopPrevious == expectedPrevious,
267
+ processInstanceStillMatches(pid: pid, application: targetApplication),
268
+ frontmostInstanceStillMatches(priorFront), !priorFront.isTerminated else {
269
+ return FocusPreparationResult(ok: false, dispatchStarted: false)
270
+ }
271
+ record[0x8A] = 0x02
272
+ let defocused = lastHopPrevious.withUnsafeBytes { psn in
273
+ record.withUnsafeBytes { body in symbols.postEventRecord(psn.baseAddress, body.baseAddress) == 0 }
274
+ }
275
+ guard defocused else { return FocusPreparationResult(ok: false, dispatchStarted: true) }
276
+
277
+ var lastHopTarget = [UInt8](repeating: 0, count: 8)
278
+ let lastHopTargetResolved = lastHopTarget.withUnsafeMutableBytes { symbols.getProcessForPid(pid, $0.baseAddress) == 0 }
279
+ guard lastHopTargetResolved, lastHopTarget == target,
280
+ processInstanceStillMatches(pid: pid, application: targetApplication),
281
+ focusContinuationStillAuthorized(priorFront: priorFront, targetApplication: targetApplication) else {
282
+ return FocusPreparationResult(ok: false, dispatchStarted: true)
283
+ }
284
+ record[0x8A] = 0x01
285
+ let focused = lastHopTarget.withUnsafeBytes { psn in
286
+ record.withUnsafeBytes { body in symbols.postEventRecord(psn.baseAddress, body.baseAddress) == 0 }
287
+ }
288
+ return FocusPreparationResult(ok: focused, dispatchStarted: true)
289
+ }
290
+
291
+ private func stamp(
292
+ _ event: CGEvent,
293
+ symbols: SkyLightSymbols,
294
+ pid: pid_t,
295
+ windowId: UInt32,
296
+ localX: Double,
297
+ localY: Double,
298
+ clickState: Int64,
299
+ phase: Int64,
300
+ clickGroup: Int64,
301
+ subtype: Int64 = 3
302
+ ) {
303
+ let pointer = Unmanaged.passUnretained(event).toOpaque()
304
+ symbols.setIntegerField(pointer, 0, phase)
305
+ symbols.setIntegerField(pointer, 1, clickState)
306
+ symbols.setIntegerField(pointer, 3, 0)
307
+ symbols.setIntegerField(pointer, 7, subtype)
308
+ symbols.setIntegerField(pointer, 40, Int64(pid))
309
+ symbols.setIntegerField(pointer, 51, Int64(windowId))
310
+ symbols.setIntegerField(pointer, 91, Int64(windowId))
311
+ symbols.setIntegerField(pointer, 92, Int64(windowId))
312
+ symbols.setIntegerField(pointer, 58, clickGroup)
313
+ symbols.setWindowLocation(pointer, localX, localY)
314
+ }
315
+
316
+ private func sendMouseEvent(
317
+ _ type: CGEventType,
318
+ symbols: SkyLightSymbols,
319
+ source: CGEventSource,
320
+ pid: pid_t,
321
+ windowId: UInt32,
322
+ screenX: Double,
323
+ screenY: Double,
324
+ localX: Double,
325
+ localY: Double,
326
+ clickState: Int64,
327
+ phase: Int64,
328
+ clickGroup: Int64,
329
+ transport: PointerTransport,
330
+ subtype: Int64 = 3
331
+ ) throws {
332
+ guard let event = CGEvent(
333
+ mouseEventSource: source,
334
+ mouseType: type,
335
+ mouseCursorPosition: CGPoint(x: screenX, y: screenY),
336
+ mouseButton: .left
337
+ ) else { throw NSError(domain: "MachineBridgeBackgroundInput", code: 1) }
338
+ stamp(event, symbols: symbols, pid: pid, windowId: windowId, localX: localX, localY: localY,
339
+ clickState: clickState, phase: phase, clickGroup: clickGroup, subtype: subtype)
340
+ postPointerEvent(event, symbols: symbols, pid: pid, transport: transport)
341
+ }
342
+
343
+ private func sendScrollEvent(
344
+ symbols: SkyLightSymbols,
345
+ source: CGEventSource,
346
+ pid: pid_t,
347
+ windowId: UInt32,
348
+ screenX: Double,
349
+ screenY: Double,
350
+ localX: Double,
351
+ localY: Double,
352
+ deltaX: Int32,
353
+ deltaY: Int32,
354
+ transport: PointerTransport
355
+ ) throws {
356
+ guard let event = CGEvent(
357
+ scrollWheelEvent2Source: source,
358
+ units: .pixel,
359
+ wheelCount: 2,
360
+ wheel1: deltaY,
361
+ wheel2: deltaX,
362
+ wheel3: 0
363
+ ) else { throw NSError(domain: "MachineBridgeBackgroundInput", code: 6) }
364
+ event.location = CGPoint(x: screenX, y: screenY)
365
+ let pointer = Unmanaged.passUnretained(event).toOpaque()
366
+ symbols.setIntegerField(pointer, 40, Int64(pid))
367
+ symbols.setIntegerField(pointer, 51, Int64(windowId))
368
+ symbols.setIntegerField(pointer, 91, Int64(windowId))
369
+ symbols.setIntegerField(pointer, 92, Int64(windowId))
370
+ symbols.setWindowLocation(pointer, localX, localY)
371
+ postPointerEvent(event, symbols: symbols, pid: pid, transport: transport)
372
+ }
373
+
374
+ private func near(_ left: Double, _ right: Double, tolerance: Double = 1.0) -> Bool {
375
+ left.isFinite && right.isFinite && abs(left - right) <= tolerance
376
+ }
377
+
378
+ private func processStartSignature(pid: pid_t) -> String? {
379
+ var info = proc_bsdinfo()
380
+ let size = MemoryLayout<proc_bsdinfo>.size
381
+ let copied = withUnsafeMutablePointer(to: &info) { pointer in
382
+ proc_pidinfo(pid, PROC_PIDTBSDINFO, 0, pointer, Int32(size))
383
+ }
384
+ guard copied == size, info.pbi_pid == UInt32(pid) else { return nil }
385
+ var start = Data()
386
+ withUnsafeBytes(of: info.pbi_start_tvsec) { start.append(contentsOf: $0) }
387
+ withUnsafeBytes(of: info.pbi_start_tvusec) { start.append(contentsOf: $0) }
388
+ guard start.count == 16 else { return nil }
389
+ return start.base64EncodedString()
390
+ }
391
+
392
+ private func processGenerationToken(pid: pid_t) -> String? {
393
+ guard let signature = processStartSignature(pid: pid) else { return nil }
394
+ return "proc:\(signature)"
395
+ }
396
+
397
+ private func processInstanceStillMatches(pid: pid_t, application: NSRunningApplication) -> Bool {
398
+ guard !application.isTerminated,
399
+ let current = NSRunningApplication(processIdentifier: pid), !current.isTerminated else { return false }
400
+ return application.isEqual(current)
401
+ }
402
+
403
+ private func runningApplication(pid: pid_t, expectedGeneration: String) -> NSRunningApplication? {
404
+ guard !expectedGeneration.isEmpty, expectedGeneration.count <= 2048,
405
+ !expectedGeneration.contains("\n"), !expectedGeneration.contains("\r"), !expectedGeneration.contains("\0"),
406
+ let application = NSRunningApplication(processIdentifier: pid), !application.isTerminated,
407
+ processGenerationToken(pid: pid) == expectedGeneration,
408
+ processInstanceStillMatches(pid: pid, application: application) else { return nil }
409
+ return application
410
+ }
411
+
412
+ private func keyboardFailure(dispatchStarted: Bool, error: String) -> Response {
413
+ Response(ok: false, backend: "skylight-experimental", focus_without_raise: nil,
414
+ frontmost_restored: nil, front_window_validated: nil, cursor_preserved: nil,
415
+ dispatch_started: dispatchStarted,
416
+ error: dispatchStarted ? "dispatch_outcome_unknown" : error,
417
+ input_transport: "public-cgevent-pid")
418
+ }
419
+
420
+ private func unicodeKeystroke(_ request: Request) -> Response {
421
+ guard let rawPid = request.pid, rawPid > 0,
422
+ let processGeneration = request.process_generation,
423
+ let text = request.text, !text.isEmpty, !text.contains("\0") else {
424
+ return keyboardFailure(dispatchStarted: false, error: "invalid_request_before_dispatch")
425
+ }
426
+ let units = Array(text.utf16)
427
+ guard units.count <= 4_000 else {
428
+ return keyboardFailure(dispatchStarted: false, error: "invalid_request_before_dispatch")
429
+ }
430
+ let pid = pid_t(rawPid)
431
+ guard let application = runningApplication(pid: pid, expectedGeneration: processGeneration) else {
432
+ return keyboardFailure(dispatchStarted: false, error: "process_generation_changed_before_dispatch")
433
+ }
434
+
435
+ var start = 0
436
+ var dispatchStarted = false
437
+ while start < units.count {
438
+ var end = min(start + 20, units.count)
439
+ if end < units.count,
440
+ units[end - 1] >= 0xD800, units[end - 1] <= 0xDBFF,
441
+ units[end] >= 0xDC00, units[end] <= 0xDFFF {
442
+ end -= 1
443
+ }
444
+ guard end > start, processInstanceStillMatches(pid: pid, application: application),
445
+ let down = CGEvent(keyboardEventSource: nil, virtualKey: 0, keyDown: true),
446
+ let up = CGEvent(keyboardEventSource: nil, virtualKey: 0, keyDown: false) else {
447
+ return keyboardFailure(dispatchStarted: dispatchStarted, error: "input_unavailable_before_dispatch")
448
+ }
449
+ let chunk = Array(units[start..<end])
450
+ chunk.withUnsafeBufferPointer { buffer in
451
+ guard let base = buffer.baseAddress else { return }
452
+ down.keyboardSetUnicodeString(stringLength: buffer.count, unicodeString: base)
453
+ up.keyboardSetUnicodeString(stringLength: buffer.count, unicodeString: base)
454
+ }
455
+ down.postToPid(pid)
456
+ dispatchStarted = true
457
+ usleep(5_000)
458
+ guard processInstanceStillMatches(pid: pid, application: application) else {
459
+ return keyboardFailure(dispatchStarted: true, error: "dispatch_outcome_unknown")
460
+ }
461
+ up.postToPid(pid)
462
+ usleep(5_000)
463
+ start = end
464
+ }
465
+ return Response(ok: true, backend: "skylight-experimental", focus_without_raise: nil,
466
+ frontmost_restored: nil, front_window_validated: nil, cursor_preserved: nil,
467
+ dispatch_started: true, error: nil, input_transport: "public-cgevent-pid")
468
+ }
469
+
470
+ private func specialKeySpec(_ value: String) -> (keyCode: CGKeyCode, shifted: Bool)? {
471
+ let shifted = value.hasPrefix("Shift+")
472
+ let key = shifted ? String(value.dropFirst(6)) : value
473
+ let keyCodes: [String: CGKeyCode] = [
474
+ "Enter": 0x24, "Tab": 0x30, "Space": 0x31, "Backspace": 0x33, "Escape": 0x35,
475
+ "Home": 0x73, "PageUp": 0x74, "Delete": 0x75, "End": 0x77, "PageDown": 0x79,
476
+ "ArrowLeft": 0x7B, "ArrowRight": 0x7C, "ArrowDown": 0x7D, "ArrowUp": 0x7E,
477
+ ]
478
+ guard let keyCode = keyCodes[key] else { return nil }
479
+ return (keyCode, shifted)
480
+ }
481
+
482
+ private func specialKeyPress(_ request: Request) -> Response {
483
+ guard let rawPid = request.pid, rawPid > 0,
484
+ let processGeneration = request.process_generation,
485
+ let key = request.key, let spec = specialKeySpec(key) else {
486
+ return keyboardFailure(dispatchStarted: false, error: "invalid_request_before_dispatch")
487
+ }
488
+ let pid = pid_t(rawPid)
489
+ guard let application = runningApplication(pid: pid, expectedGeneration: processGeneration) else {
490
+ return keyboardFailure(dispatchStarted: false, error: "process_generation_changed_before_dispatch")
491
+ }
492
+ guard processInstanceStillMatches(pid: pid, application: application),
493
+ let down = CGEvent(keyboardEventSource: nil, virtualKey: spec.keyCode, keyDown: true),
494
+ let up = CGEvent(keyboardEventSource: nil, virtualKey: spec.keyCode, keyDown: false) else {
495
+ return keyboardFailure(dispatchStarted: false, error: "input_unavailable_before_dispatch")
496
+ }
497
+ if spec.shifted {
498
+ down.flags = .maskShift
499
+ up.flags = .maskShift
500
+ }
501
+ down.postToPid(pid)
502
+ usleep(5_000)
503
+ guard processInstanceStillMatches(pid: pid, application: application) else {
504
+ return keyboardFailure(dispatchStarted: true, error: "dispatch_outcome_unknown")
505
+ }
506
+ up.postToPid(pid)
507
+ usleep(5_000)
508
+ return Response(ok: true, backend: "skylight-experimental", focus_without_raise: nil,
509
+ frontmost_restored: nil, front_window_validated: nil, cursor_preserved: nil,
510
+ dispatch_started: true, error: nil, input_transport: "public-cgevent-pid")
511
+ }
512
+
513
+ private func frontWindowStillMatches(
514
+ pid: pid_t,
515
+ application: NSRunningApplication,
516
+ windowId: UInt32,
517
+ expected: CGRect
518
+ ) -> Bool {
519
+ guard processInstanceStillMatches(pid: pid, application: application),
520
+ let raw = CGWindowListCopyWindowInfo([.optionOnScreenOnly], kCGNullWindowID),
521
+ let windows = raw as? [[String: Any]] else { return false }
522
+ for info in windows {
523
+ let ownerPid = (info[kCGWindowOwnerPID as String] as? NSNumber)?.int32Value ?? 0
524
+ let layer = (info[kCGWindowLayer as String] as? NSNumber)?.intValue ?? -1
525
+ let alpha = (info[kCGWindowAlpha as String] as? NSNumber)?.doubleValue ?? 1
526
+ guard ownerPid == pid, layer == 0, alpha > 0 else { continue }
527
+ let candidateId = (info[kCGWindowNumber as String] as? NSNumber)?.uint32Value ?? 0
528
+ guard let boundsObject = info[kCGWindowBounds as String] as? NSDictionary,
529
+ let candidateBounds = CGRect(dictionaryRepresentation: boundsObject) else { return false }
530
+ return candidateId == windowId
531
+ && near(candidateBounds.origin.x, expected.origin.x)
532
+ && near(candidateBounds.origin.y, expected.origin.y)
533
+ && near(candidateBounds.size.width, expected.size.width)
534
+ && near(candidateBounds.size.height, expected.size.height)
535
+ }
536
+ return false
537
+ }
538
+
539
+ private func cursorLocation() -> CGPoint? {
540
+ NSEvent.mouseLocation
541
+ }
542
+
543
+ private func restoreFrontmostIfNeeded(
544
+ priorFront: NSRunningApplication?, targetApplication: NSRunningApplication, focusDispatched: Bool
545
+ ) -> Bool {
546
+ guard focusDispatched,
547
+ let priorFront, !priorFront.isEqual(targetApplication), !priorFront.isTerminated,
548
+ let current = NSWorkspace.shared.frontmostApplication, current.isEqual(targetApplication) else { return false }
549
+ return priorFront.activate(options: [])
550
+ }
551
+
552
+ private func click(_ request: Request, symbols: SkyLightSymbols) -> Response {
553
+ guard let rawPid = request.pid, rawPid > 0,
554
+ let processGeneration = request.process_generation,
555
+ let windowId = request.window_id, windowId > 0,
556
+ let screenX = request.screen_x, screenX.isFinite,
557
+ let screenY = request.screen_y, screenY.isFinite,
558
+ let localX = request.local_x, localX.isFinite,
559
+ let localY = request.local_y, localY.isFinite,
560
+ let windowX = request.window_x, windowX.isFinite,
561
+ let windowY = request.window_y, windowY.isFinite,
562
+ let windowWidth = request.window_width, windowWidth > 0, windowWidth.isFinite,
563
+ let windowHeight = request.window_height, windowHeight > 0, windowHeight.isFinite,
564
+ localX >= 0, localY >= 0, localX < windowWidth, localY < windowHeight,
565
+ (request.click_count ?? 1) >= 1, (request.click_count ?? 1) <= 2 else {
566
+ return Response(ok: false, backend: "skylight-experimental", focus_without_raise: nil,
567
+ frontmost_restored: nil, front_window_validated: nil, cursor_preserved: nil,
568
+ dispatch_started: false, error: "invalid_request_before_dispatch")
569
+ }
570
+ let pid = pid_t(rawPid)
571
+ guard let targetApplication = runningApplication(pid: pid, expectedGeneration: processGeneration) else {
572
+ return Response(ok: false, backend: "skylight-experimental", focus_without_raise: nil,
573
+ frontmost_restored: nil, front_window_validated: nil, cursor_preserved: nil,
574
+ dispatch_started: false, error: "process_generation_changed_before_dispatch")
575
+ }
576
+ let clickCount = request.click_count ?? 1
577
+ let transport = pointerTransport(application: targetApplication)
578
+ let frameworkTransport = transport
579
+ let clickSubtype: Int64 = switch transport {
580
+ case .skyLight: 3
581
+ case .publicCGEvent: 0
582
+ }
583
+ let expectedBounds = CGRect(x: windowX, y: windowY, width: windowWidth, height: windowHeight)
584
+ guard frontWindowStillMatches(pid: pid, application: targetApplication, windowId: windowId, expected: expectedBounds) else {
585
+ return Response(ok: false, backend: "skylight-experimental", focus_without_raise: nil,
586
+ frontmost_restored: nil, front_window_validated: false, cursor_preserved: nil,
587
+ dispatch_started: false, error: "front_window_changed_before_dispatch")
588
+ }
589
+
590
+ let cursorBefore = cursorLocation()
591
+ let priorFront = NSWorkspace.shared.frontmostApplication
592
+ let focusPreparation = prepareFocusIfNeeded(
593
+ symbols, pid: pid, windowId: windowId, frameworkTransport: transport,
594
+ priorFront: priorFront, targetApplication: targetApplication
595
+ )
596
+ guard focusPreparation.ok else {
597
+ let restored = restoreFrontmostIfNeeded(
598
+ priorFront: priorFront, targetApplication: targetApplication, focusDispatched: focusPreparation.dispatchStarted
599
+ )
600
+ return Response(ok: false, backend: "skylight-experimental", focus_without_raise: focusPreparation.dispatchStarted,
601
+ frontmost_restored: restored, front_window_validated: true, cursor_preserved: nil,
602
+ dispatch_started: focusPreparation.dispatchStarted,
603
+ error: focusPreparation.dispatchStarted ? "dispatch_outcome_unknown" : "focus_without_raise_unavailable_before_dispatch")
604
+ }
605
+ if focusPreparation.dispatchStarted { usleep(50_000) }
606
+ guard skyLightInputStillAuthorized(
607
+ frameworkTransport: transport, priorFront: priorFront,
608
+ targetApplication: targetApplication, focusDispatched: focusPreparation.dispatchStarted
609
+ ) else {
610
+ let restored = restoreFrontmostIfNeeded(
611
+ priorFront: priorFront, targetApplication: targetApplication, focusDispatched: focusPreparation.dispatchStarted
612
+ )
613
+ return Response(ok: false, backend: "skylight-experimental", focus_without_raise: focusPreparation.dispatchStarted,
614
+ frontmost_restored: restored, front_window_validated: true, cursor_preserved: nil,
615
+ dispatch_started: focusPreparation.dispatchStarted,
616
+ error: focusPreparation.dispatchStarted ? "dispatch_outcome_unknown" : "frontmost_changed_before_input")
617
+ }
618
+ guard let source = CGEventSource(stateID: .hidSystemState) else {
619
+ let restored = restoreFrontmostIfNeeded(
620
+ priorFront: priorFront, targetApplication: targetApplication, focusDispatched: focusPreparation.dispatchStarted
621
+ )
622
+ return Response(ok: false, backend: "skylight-experimental", focus_without_raise: focusPreparation.dispatchStarted,
623
+ frontmost_restored: restored, front_window_validated: true, cursor_preserved: nil,
624
+ dispatch_started: focusPreparation.dispatchStarted,
625
+ error: focusPreparation.dispatchStarted ? "dispatch_outcome_unknown" : "event_source_unavailable_before_dispatch")
626
+ }
627
+
628
+ let clickGroup = Int64(UInt32.random(in: 1...UInt32.max))
629
+ var pointerDispatchStarted = false
630
+ var downSent = false
631
+ var upSent = true
632
+ var activeClickState: Int64 = 0
633
+ do {
634
+ guard inputBoundaryStillValid(
635
+ pid: pid, application: targetApplication, windowId: windowId, expected: expectedBounds,
636
+ frameworkTransport: frameworkTransport, priorFront: priorFront,
637
+ focusDispatched: focusPreparation.dispatchStarted
638
+ ) else {
639
+ throw NSError(domain: "MachineBridgeBackgroundInput", code: 11)
640
+ }
641
+ try sendMouseEvent(.mouseMoved, symbols: symbols, source: source, pid: pid, windowId: windowId,
642
+ screenX: screenX, screenY: screenY, localX: localX, localY: localY,
643
+ clickState: 0, phase: 2, clickGroup: clickGroup, transport: transport, subtype: clickSubtype)
644
+ pointerDispatchStarted = true
645
+ usleep(15_000)
646
+ for clickState in 1...clickCount {
647
+ activeClickState = Int64(clickState)
648
+ guard inputBoundaryStillValid(
649
+ pid: pid, application: targetApplication, windowId: windowId, expected: expectedBounds,
650
+ frameworkTransport: frameworkTransport, priorFront: priorFront,
651
+ focusDispatched: focusPreparation.dispatchStarted
652
+ ) else {
653
+ throw NSError(domain: "MachineBridgeBackgroundInput", code: 12)
654
+ }
655
+ try sendMouseEvent(.leftMouseDown, symbols: symbols, source: source, pid: pid, windowId: windowId,
656
+ screenX: screenX, screenY: screenY, localX: localX, localY: localY,
657
+ clickState: activeClickState, phase: 3, clickGroup: clickGroup, transport: transport, subtype: clickSubtype)
658
+ pointerDispatchStarted = true
659
+ downSent = true
660
+ upSent = false
661
+ usleep(28_000)
662
+ guard inputBoundaryStillValid(
663
+ pid: pid, application: targetApplication, windowId: windowId, expected: expectedBounds,
664
+ frameworkTransport: frameworkTransport, priorFront: priorFront,
665
+ focusDispatched: focusPreparation.dispatchStarted
666
+ ) else {
667
+ throw NSError(domain: "MachineBridgeBackgroundInput", code: 13)
668
+ }
669
+ try sendMouseEvent(.leftMouseUp, symbols: symbols, source: source, pid: pid, windowId: windowId,
670
+ screenX: screenX, screenY: screenY, localX: localX, localY: localY,
671
+ clickState: activeClickState, phase: 3, clickGroup: clickGroup, transport: transport, subtype: clickSubtype)
672
+ pointerDispatchStarted = true
673
+ upSent = true
674
+ downSent = false
675
+ if clickState < clickCount { usleep(55_000) }
676
+ }
677
+ } catch {
678
+ if downSent && !upSent && processInstanceStillMatches(pid: pid, application: targetApplication) {
679
+ try? sendMouseEvent(.leftMouseUp, symbols: symbols, source: source, pid: pid, windowId: windowId,
680
+ screenX: screenX, screenY: screenY, localX: localX, localY: localY,
681
+ clickState: activeClickState, phase: 3, clickGroup: clickGroup, transport: transport, subtype: clickSubtype)
682
+ }
683
+ let dispatchStarted = focusPreparation.dispatchStarted || pointerDispatchStarted
684
+ let restored = restoreFrontmostIfNeeded(priorFront: priorFront, targetApplication: targetApplication, focusDispatched: focusPreparation.dispatchStarted)
685
+ return Response(ok: false, backend: "skylight-experimental", focus_without_raise: focusPreparation.dispatchStarted,
686
+ frontmost_restored: restored, front_window_validated: true, cursor_preserved: nil,
687
+ dispatch_started: dispatchStarted,
688
+ error: dispatchStarted ? "dispatch_outcome_unknown" : "input_unavailable_before_dispatch")
689
+ }
690
+
691
+ usleep(50_000)
692
+ let restored = restoreFrontmostIfNeeded(priorFront: priorFront, targetApplication: targetApplication, focusDispatched: focusPreparation.dispatchStarted)
693
+ let cursorAfter = cursorLocation()
694
+ let cursorPreserved: Bool? = {
695
+ guard let cursorBefore, let cursorAfter else { return nil }
696
+ return hypot(cursorBefore.x - cursorAfter.x, cursorBefore.y - cursorAfter.y) <= 0.5
697
+ }()
698
+ return Response(ok: true, backend: "skylight-experimental", focus_without_raise: focusPreparation.dispatchStarted,
699
+ frontmost_restored: restored, front_window_validated: true, cursor_preserved: cursorPreserved,
700
+ dispatch_started: true, error: nil, input_transport: transport.label)
701
+ }
702
+
703
+ private func drag(_ request: Request, symbols: SkyLightSymbols) -> Response {
704
+ guard let rawPid = request.pid, rawPid > 0,
705
+ let processGeneration = request.process_generation,
706
+ let windowId = request.window_id, windowId > 0,
707
+ let screenX = request.screen_x, screenX.isFinite,
708
+ let screenY = request.screen_y, screenY.isFinite,
709
+ let localX = request.local_x, localX.isFinite,
710
+ let localY = request.local_y, localY.isFinite,
711
+ let destinationScreenX = request.destination_screen_x, destinationScreenX.isFinite,
712
+ let destinationScreenY = request.destination_screen_y, destinationScreenY.isFinite,
713
+ let destinationLocalX = request.destination_local_x, destinationLocalX.isFinite,
714
+ let destinationLocalY = request.destination_local_y, destinationLocalY.isFinite,
715
+ let windowX = request.window_x, windowX.isFinite,
716
+ let windowY = request.window_y, windowY.isFinite,
717
+ let windowWidth = request.window_width, windowWidth > 0, windowWidth.isFinite,
718
+ let windowHeight = request.window_height, windowHeight > 0, windowHeight.isFinite,
719
+ localX >= 0, localY >= 0, destinationLocalX >= 0, destinationLocalY >= 0,
720
+ localX < windowWidth, localY < windowHeight,
721
+ destinationLocalX < windowWidth, destinationLocalY < windowHeight else {
722
+ return Response(ok: false, backend: "skylight-experimental", focus_without_raise: nil,
723
+ frontmost_restored: nil, front_window_validated: nil, cursor_preserved: nil,
724
+ dispatch_started: false, error: "invalid_request_before_dispatch")
725
+ }
726
+ let pid = pid_t(rawPid)
727
+ guard let targetApplication = runningApplication(pid: pid, expectedGeneration: processGeneration) else {
728
+ return Response(ok: false, backend: "skylight-experimental", focus_without_raise: nil,
729
+ frontmost_restored: nil, front_window_validated: nil, cursor_preserved: nil,
730
+ dispatch_started: false, error: "process_generation_changed_before_dispatch")
731
+ }
732
+ let transport = pointerTransport(application: targetApplication)
733
+ let frameworkTransport = transport
734
+ let expectedBounds = CGRect(x: windowX, y: windowY, width: windowWidth, height: windowHeight)
735
+ guard frontWindowStillMatches(pid: pid, application: targetApplication, windowId: windowId, expected: expectedBounds) else {
736
+ return Response(ok: false, backend: "skylight-experimental", focus_without_raise: nil,
737
+ frontmost_restored: nil, front_window_validated: false, cursor_preserved: nil,
738
+ dispatch_started: false, error: "front_window_changed_before_dispatch")
739
+ }
740
+
741
+ let cursorBefore = cursorLocation()
742
+ let priorFront = NSWorkspace.shared.frontmostApplication
743
+ let focusPreparation = prepareFocusIfNeeded(
744
+ symbols, pid: pid, windowId: windowId, frameworkTransport: transport,
745
+ priorFront: priorFront, targetApplication: targetApplication
746
+ )
747
+ guard focusPreparation.ok else {
748
+ let restored = restoreFrontmostIfNeeded(
749
+ priorFront: priorFront, targetApplication: targetApplication, focusDispatched: focusPreparation.dispatchStarted
750
+ )
751
+ return Response(ok: false, backend: "skylight-experimental", focus_without_raise: focusPreparation.dispatchStarted,
752
+ frontmost_restored: restored, front_window_validated: true, cursor_preserved: nil,
753
+ dispatch_started: focusPreparation.dispatchStarted,
754
+ error: focusPreparation.dispatchStarted ? "dispatch_outcome_unknown" : "focus_without_raise_unavailable_before_dispatch")
755
+ }
756
+ if focusPreparation.dispatchStarted { usleep(50_000) }
757
+ guard skyLightInputStillAuthorized(
758
+ frameworkTransport: transport, priorFront: priorFront,
759
+ targetApplication: targetApplication, focusDispatched: focusPreparation.dispatchStarted
760
+ ) else {
761
+ let restored = restoreFrontmostIfNeeded(
762
+ priorFront: priorFront, targetApplication: targetApplication, focusDispatched: focusPreparation.dispatchStarted
763
+ )
764
+ return Response(ok: false, backend: "skylight-experimental", focus_without_raise: focusPreparation.dispatchStarted,
765
+ frontmost_restored: restored, front_window_validated: true, cursor_preserved: nil,
766
+ dispatch_started: focusPreparation.dispatchStarted,
767
+ error: focusPreparation.dispatchStarted ? "dispatch_outcome_unknown" : "frontmost_changed_before_input")
768
+ }
769
+ guard let source = CGEventSource(stateID: .hidSystemState) else {
770
+ let restored = restoreFrontmostIfNeeded(
771
+ priorFront: priorFront, targetApplication: targetApplication, focusDispatched: focusPreparation.dispatchStarted
772
+ )
773
+ return Response(ok: false, backend: "skylight-experimental", focus_without_raise: focusPreparation.dispatchStarted,
774
+ frontmost_restored: restored, front_window_validated: true, cursor_preserved: nil,
775
+ dispatch_started: focusPreparation.dispatchStarted,
776
+ error: focusPreparation.dispatchStarted ? "dispatch_outcome_unknown" : "event_source_unavailable_before_dispatch")
777
+ }
778
+
779
+ let clickGroup = Int64(UInt32.random(in: 1...UInt32.max))
780
+ var pointerDispatchStarted = false
781
+ var downSent = false
782
+ var upSent = false
783
+ var lastScreenX = screenX
784
+ var lastScreenY = screenY
785
+ var lastLocalX = localX
786
+ var lastLocalY = localY
787
+ do {
788
+ guard inputBoundaryStillValid(
789
+ pid: pid, application: targetApplication, windowId: windowId, expected: expectedBounds,
790
+ frameworkTransport: frameworkTransport, priorFront: priorFront,
791
+ focusDispatched: focusPreparation.dispatchStarted
792
+ ) else {
793
+ throw NSError(domain: "MachineBridgeBackgroundInput", code: 2)
794
+ }
795
+ try sendMouseEvent(.mouseMoved, symbols: symbols, source: source, pid: pid, windowId: windowId,
796
+ screenX: screenX, screenY: screenY, localX: localX, localY: localY,
797
+ clickState: 0, phase: 2, clickGroup: clickGroup, transport: transport, subtype: 0)
798
+ pointerDispatchStarted = true
799
+ usleep(15_000)
800
+ guard inputBoundaryStillValid(
801
+ pid: pid, application: targetApplication, windowId: windowId, expected: expectedBounds,
802
+ frameworkTransport: frameworkTransport, priorFront: priorFront,
803
+ focusDispatched: focusPreparation.dispatchStarted
804
+ ) else {
805
+ throw NSError(domain: "MachineBridgeBackgroundInput", code: 3)
806
+ }
807
+ try sendMouseEvent(.leftMouseDown, symbols: symbols, source: source, pid: pid, windowId: windowId,
808
+ screenX: screenX, screenY: screenY, localX: localX, localY: localY,
809
+ clickState: 1, phase: 3, clickGroup: clickGroup, transport: transport, subtype: 0)
810
+ pointerDispatchStarted = true
811
+ downSent = true
812
+ usleep(16_000)
813
+
814
+ let steps = 8
815
+ for step in 1...steps {
816
+ guard inputBoundaryStillValid(
817
+ pid: pid, application: targetApplication, windowId: windowId, expected: expectedBounds,
818
+ frameworkTransport: frameworkTransport, priorFront: priorFront,
819
+ focusDispatched: focusPreparation.dispatchStarted
820
+ ) else {
821
+ throw NSError(domain: "MachineBridgeBackgroundInput", code: 4)
822
+ }
823
+ let ratio = Double(step) / Double(steps)
824
+ lastScreenX = screenX + (destinationScreenX - screenX) * ratio
825
+ lastScreenY = screenY + (destinationScreenY - screenY) * ratio
826
+ lastLocalX = localX + (destinationLocalX - localX) * ratio
827
+ lastLocalY = localY + (destinationLocalY - localY) * ratio
828
+ try sendMouseEvent(.leftMouseDragged, symbols: symbols, source: source, pid: pid, windowId: windowId,
829
+ screenX: lastScreenX, screenY: lastScreenY, localX: lastLocalX, localY: lastLocalY,
830
+ clickState: 1, phase: 3, clickGroup: clickGroup, transport: transport, subtype: 0)
831
+ pointerDispatchStarted = true
832
+ usleep(16_000)
833
+ }
834
+ guard inputBoundaryStillValid(
835
+ pid: pid, application: targetApplication, windowId: windowId, expected: expectedBounds,
836
+ frameworkTransport: frameworkTransport, priorFront: priorFront,
837
+ focusDispatched: focusPreparation.dispatchStarted
838
+ ) else {
839
+ throw NSError(domain: "MachineBridgeBackgroundInput", code: 5)
840
+ }
841
+ usleep(30_000)
842
+ try sendMouseEvent(.leftMouseUp, symbols: symbols, source: source, pid: pid, windowId: windowId,
843
+ screenX: destinationScreenX, screenY: destinationScreenY,
844
+ localX: destinationLocalX, localY: destinationLocalY,
845
+ clickState: 1, phase: 3, clickGroup: clickGroup, transport: transport, subtype: 0)
846
+ pointerDispatchStarted = true
847
+ upSent = true
848
+ } catch {
849
+ if downSent && !upSent && processInstanceStillMatches(pid: pid, application: targetApplication) {
850
+ try? sendMouseEvent(.leftMouseUp, symbols: symbols, source: source, pid: pid, windowId: windowId,
851
+ screenX: lastScreenX, screenY: lastScreenY, localX: lastLocalX, localY: lastLocalY,
852
+ clickState: 1, phase: 3, clickGroup: clickGroup, transport: transport, subtype: 0)
853
+ }
854
+ let dispatchStarted = focusPreparation.dispatchStarted || pointerDispatchStarted
855
+ let restored = restoreFrontmostIfNeeded(priorFront: priorFront, targetApplication: targetApplication, focusDispatched: focusPreparation.dispatchStarted)
856
+ return Response(ok: false, backend: "skylight-experimental", focus_without_raise: focusPreparation.dispatchStarted,
857
+ frontmost_restored: restored, front_window_validated: true, cursor_preserved: nil,
858
+ dispatch_started: dispatchStarted,
859
+ error: dispatchStarted ? "dispatch_outcome_unknown" : "input_unavailable_before_dispatch")
860
+ }
861
+
862
+ usleep(50_000)
863
+ let restored = restoreFrontmostIfNeeded(priorFront: priorFront, targetApplication: targetApplication, focusDispatched: focusPreparation.dispatchStarted)
864
+ let cursorAfter = cursorLocation()
865
+ let cursorPreserved: Bool? = {
866
+ guard let cursorBefore, let cursorAfter else { return nil }
867
+ return hypot(cursorBefore.x - cursorAfter.x, cursorBefore.y - cursorAfter.y) <= 0.5
868
+ }()
869
+ return Response(ok: true, backend: "skylight-experimental", focus_without_raise: focusPreparation.dispatchStarted,
870
+ frontmost_restored: restored, front_window_validated: true, cursor_preserved: cursorPreserved,
871
+ dispatch_started: true, error: nil, input_transport: transport.label)
872
+ }
873
+
874
+ private func scroll(_ request: Request, symbols: SkyLightSymbols) -> Response {
875
+ guard let rawPid = request.pid, rawPid > 0,
876
+ let processGeneration = request.process_generation,
877
+ let windowId = request.window_id, windowId > 0,
878
+ let screenX = request.screen_x, screenX.isFinite,
879
+ let screenY = request.screen_y, screenY.isFinite,
880
+ let localX = request.local_x, localX.isFinite,
881
+ let localY = request.local_y, localY.isFinite,
882
+ let requestedDeltaX = request.delta_x, requestedDeltaX.isFinite, abs(requestedDeltaX) <= 10_000,
883
+ let requestedDeltaY = request.delta_y, requestedDeltaY.isFinite, abs(requestedDeltaY) <= 10_000,
884
+ let windowX = request.window_x, windowX.isFinite,
885
+ let windowY = request.window_y, windowY.isFinite,
886
+ let windowWidth = request.window_width, windowWidth > 0, windowWidth.isFinite,
887
+ let windowHeight = request.window_height, windowHeight > 0, windowHeight.isFinite,
888
+ localX >= 0, localY >= 0, localX < windowWidth, localY < windowHeight else {
889
+ return Response(ok: false, backend: "skylight-experimental", focus_without_raise: nil,
890
+ frontmost_restored: nil, front_window_validated: nil, cursor_preserved: nil,
891
+ dispatch_started: false, error: "invalid_request_before_dispatch")
892
+ }
893
+ let wheelX = Int32((-requestedDeltaX).rounded())
894
+ let wheelY = Int32((-requestedDeltaY).rounded())
895
+ guard wheelX != 0 || wheelY != 0 else {
896
+ return Response(ok: false, backend: "skylight-experimental", focus_without_raise: nil,
897
+ frontmost_restored: nil, front_window_validated: nil, cursor_preserved: nil,
898
+ dispatch_started: false, error: "invalid_request_before_dispatch")
899
+ }
900
+ let pid = pid_t(rawPid)
901
+ guard let targetApplication = runningApplication(pid: pid, expectedGeneration: processGeneration) else {
902
+ return Response(ok: false, backend: "skylight-experimental", focus_without_raise: nil,
903
+ frontmost_restored: nil, front_window_validated: nil, cursor_preserved: nil,
904
+ dispatch_started: false, error: "process_generation_changed_before_dispatch")
905
+ }
906
+ let frameworkTransport = pointerTransport(application: targetApplication)
907
+ let transport: PointerTransport = .skyLight
908
+ let expectedBounds = CGRect(x: windowX, y: windowY, width: windowWidth, height: windowHeight)
909
+ guard frontWindowStillMatches(pid: pid, application: targetApplication, windowId: windowId, expected: expectedBounds) else {
910
+ return Response(ok: false, backend: "skylight-experimental", focus_without_raise: nil,
911
+ frontmost_restored: nil, front_window_validated: false, cursor_preserved: nil,
912
+ dispatch_started: false, error: "front_window_changed_before_dispatch")
913
+ }
914
+
915
+ let cursorBefore = cursorLocation()
916
+ let priorFront = NSWorkspace.shared.frontmostApplication
917
+ let focusPreparation = prepareFocusIfNeeded(
918
+ symbols, pid: pid, windowId: windowId, frameworkTransport: frameworkTransport,
919
+ priorFront: priorFront, targetApplication: targetApplication
920
+ )
921
+ guard focusPreparation.ok else {
922
+ let restored = restoreFrontmostIfNeeded(
923
+ priorFront: priorFront, targetApplication: targetApplication, focusDispatched: focusPreparation.dispatchStarted
924
+ )
925
+ return Response(ok: false, backend: "skylight-experimental", focus_without_raise: focusPreparation.dispatchStarted,
926
+ frontmost_restored: restored, front_window_validated: true, cursor_preserved: nil,
927
+ dispatch_started: focusPreparation.dispatchStarted,
928
+ error: focusPreparation.dispatchStarted ? "dispatch_outcome_unknown" : "focus_without_raise_unavailable_before_dispatch")
929
+ }
930
+ if focusPreparation.dispatchStarted { usleep(50_000) }
931
+ guard skyLightInputStillAuthorized(
932
+ frameworkTransport: frameworkTransport, priorFront: priorFront,
933
+ targetApplication: targetApplication, focusDispatched: focusPreparation.dispatchStarted
934
+ ) else {
935
+ let restored = restoreFrontmostIfNeeded(
936
+ priorFront: priorFront, targetApplication: targetApplication, focusDispatched: focusPreparation.dispatchStarted
937
+ )
938
+ return Response(ok: false, backend: "skylight-experimental", focus_without_raise: focusPreparation.dispatchStarted,
939
+ frontmost_restored: restored, front_window_validated: true, cursor_preserved: nil,
940
+ dispatch_started: focusPreparation.dispatchStarted,
941
+ error: focusPreparation.dispatchStarted ? "dispatch_outcome_unknown" : "frontmost_changed_before_input")
942
+ }
943
+ guard let source = CGEventSource(stateID: .hidSystemState) else {
944
+ let restored = restoreFrontmostIfNeeded(
945
+ priorFront: priorFront, targetApplication: targetApplication, focusDispatched: focusPreparation.dispatchStarted
946
+ )
947
+ return Response(ok: false, backend: "skylight-experimental", focus_without_raise: focusPreparation.dispatchStarted,
948
+ frontmost_restored: restored, front_window_validated: true, cursor_preserved: nil,
949
+ dispatch_started: focusPreparation.dispatchStarted,
950
+ error: focusPreparation.dispatchStarted ? "dispatch_outcome_unknown" : "event_source_unavailable_before_dispatch")
951
+ }
952
+
953
+ var pointerDispatchStarted = false
954
+ do {
955
+ let clickGroup = Int64(UInt32.random(in: 1...UInt32.max))
956
+ guard inputBoundaryStillValid(
957
+ pid: pid, application: targetApplication, windowId: windowId, expected: expectedBounds,
958
+ frameworkTransport: frameworkTransport, priorFront: priorFront,
959
+ focusDispatched: focusPreparation.dispatchStarted
960
+ ) else {
961
+ throw NSError(domain: "MachineBridgeBackgroundInput", code: 7)
962
+ }
963
+ try sendMouseEvent(.mouseMoved, symbols: symbols, source: source, pid: pid, windowId: windowId,
964
+ screenX: screenX, screenY: screenY, localX: localX, localY: localY,
965
+ clickState: 0, phase: 2, clickGroup: clickGroup, transport: transport, subtype: 0)
966
+ pointerDispatchStarted = true
967
+ usleep(12_000)
968
+ guard inputBoundaryStillValid(
969
+ pid: pid, application: targetApplication, windowId: windowId, expected: expectedBounds,
970
+ frameworkTransport: frameworkTransport, priorFront: priorFront,
971
+ focusDispatched: focusPreparation.dispatchStarted
972
+ ) else {
973
+ throw NSError(domain: "MachineBridgeBackgroundInput", code: 8)
974
+ }
975
+ try sendScrollEvent(symbols: symbols, source: source, pid: pid, windowId: windowId,
976
+ screenX: screenX, screenY: screenY, localX: localX, localY: localY,
977
+ deltaX: wheelX, deltaY: wheelY, transport: transport)
978
+ pointerDispatchStarted = true
979
+ } catch {
980
+ let dispatchStarted = focusPreparation.dispatchStarted || pointerDispatchStarted
981
+ let restored = restoreFrontmostIfNeeded(priorFront: priorFront, targetApplication: targetApplication, focusDispatched: focusPreparation.dispatchStarted)
982
+ return Response(ok: false, backend: "skylight-experimental", focus_without_raise: focusPreparation.dispatchStarted,
983
+ frontmost_restored: restored, front_window_validated: true, cursor_preserved: nil,
984
+ dispatch_started: dispatchStarted,
985
+ error: dispatchStarted ? "dispatch_outcome_unknown" : "input_unavailable_before_dispatch")
986
+ }
987
+
988
+ usleep(50_000)
989
+ let restored = restoreFrontmostIfNeeded(priorFront: priorFront, targetApplication: targetApplication, focusDispatched: focusPreparation.dispatchStarted)
990
+ let cursorAfter = cursorLocation()
991
+ let cursorPreserved: Bool? = {
992
+ guard let cursorBefore, let cursorAfter else { return nil }
993
+ return hypot(cursorBefore.x - cursorAfter.x, cursorBefore.y - cursorAfter.y) <= 0.5
994
+ }()
995
+ return Response(ok: true, backend: "skylight-experimental", focus_without_raise: focusPreparation.dispatchStarted,
996
+ frontmost_restored: restored, front_window_validated: true, cursor_preserved: cursorPreserved,
997
+ dispatch_started: true, error: nil, input_transport: transport.label)
998
+ }
999
+
1000
+ guard let line = readLine(), let data = line.data(using: .utf8), let request = try? JSONDecoder().decode(Request.self, from: data) else {
1001
+ encode(Response(ok: false, backend: "skylight-experimental", focus_without_raise: nil,
1002
+ frontmost_restored: nil, front_window_validated: nil, cursor_preserved: nil,
1003
+ dispatch_started: false, error: "invalid_json_before_dispatch"))
1004
+ exit(2)
1005
+ }
1006
+
1007
+ switch request.operation {
1008
+ case "unicode_keystroke":
1009
+ let response = unicodeKeystroke(request)
1010
+ encode(response)
1011
+ exit(response.ok ? 0 : 4)
1012
+ case "key_press":
1013
+ let response = specialKeyPress(request)
1014
+ encode(response)
1015
+ exit(response.ok ? 0 : 4)
1016
+ case "probe", "click", "drag", "scroll":
1017
+ guard let symbols = SkyLightSymbols() else {
1018
+ encode(Response(ok: false, backend: "skylight-experimental", focus_without_raise: nil,
1019
+ frontmost_restored: nil, front_window_validated: nil, cursor_preserved: nil,
1020
+ dispatch_started: false, error: "private_symbols_unavailable_before_dispatch"))
1021
+ exit(3)
1022
+ }
1023
+ switch request.operation {
1024
+ case "probe":
1025
+ encode(Response(ok: true, backend: "skylight-experimental", focus_without_raise: nil,
1026
+ frontmost_restored: nil, front_window_validated: nil, cursor_preserved: nil,
1027
+ dispatch_started: false, error: nil))
1028
+ case "click":
1029
+ let response = click(request, symbols: symbols)
1030
+ encode(response)
1031
+ exit(response.ok ? 0 : 4)
1032
+ case "drag":
1033
+ let response = drag(request, symbols: symbols)
1034
+ encode(response)
1035
+ exit(response.ok ? 0 : 4)
1036
+ case "scroll":
1037
+ let response = scroll(request, symbols: symbols)
1038
+ encode(response)
1039
+ exit(response.ok ? 0 : 4)
1040
+ default:
1041
+ encode(Response(ok: false, backend: "skylight-experimental", focus_without_raise: nil,
1042
+ frontmost_restored: nil, front_window_validated: nil, cursor_preserved: nil,
1043
+ dispatch_started: false, error: "unsupported_operation_before_dispatch"))
1044
+ exit(2)
1045
+ }
1046
+ default:
1047
+ encode(Response(ok: false, backend: "skylight-experimental", focus_without_raise: nil,
1048
+ frontmost_restored: nil, front_window_validated: nil, cursor_preserved: nil,
1049
+ dispatch_started: false, error: "unsupported_operation_before_dispatch"))
1050
+ exit(2)
1051
+ }