@mirasim/computer-use 0.0.0-stage → 0.1.0-rc.3

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 (341) hide show
  1. package/LICENSE +202 -0
  2. package/NOTICE +16 -0
  3. package/README.md +154 -2
  4. package/THIRD_PARTY_NOTICES +488 -0
  5. package/bin/mirasim-cu.mjs +30 -0
  6. package/dist/entries/cli.d.ts +2 -0
  7. package/dist/entries/cli.js +32 -0
  8. package/dist/entries/commands/approvals.d.ts +1 -0
  9. package/dist/entries/commands/approvals.js +17 -0
  10. package/dist/entries/commands/bridge-host.d.ts +1 -0
  11. package/dist/entries/commands/bridge-host.js +7 -0
  12. package/dist/entries/commands/bridge.d.ts +1 -0
  13. package/dist/entries/commands/bridge.js +16 -0
  14. package/dist/entries/commands/browser-state.d.ts +1 -0
  15. package/dist/entries/commands/browser-state.js +8 -0
  16. package/dist/entries/commands/capture-server.d.ts +1 -0
  17. package/dist/entries/commands/capture-server.js +5 -0
  18. package/dist/entries/commands/help.d.ts +2 -0
  19. package/dist/entries/commands/help.js +1 -0
  20. package/dist/entries/commands/native-host-options.d.ts +32 -0
  21. package/dist/entries/commands/native-host-options.js +7 -0
  22. package/dist/entries/commands/setup-macos.d.ts +1 -0
  23. package/dist/entries/commands/setup-macos.js +4 -0
  24. package/dist/entries/commands/setup.d.ts +1 -0
  25. package/dist/entries/commands/setup.js +15 -0
  26. package/dist/entries/mcp.d.ts +1 -0
  27. package/dist/entries/mcp.js +6 -0
  28. package/dist/entries/version.d.ts +1 -0
  29. package/dist/entries/version.js +1 -0
  30. package/dist/index.d.ts +11 -0
  31. package/dist/index.js +1 -0
  32. package/dist/platform/browser/acquire.d.ts +15 -0
  33. package/dist/platform/browser/acquire.js +1 -0
  34. package/dist/platform/browser/bridge/acquire-bridge.d.ts +7 -0
  35. package/dist/platform/browser/bridge/acquire-bridge.js +3 -0
  36. package/dist/platform/browser/bridge/client.d.ts +69 -0
  37. package/dist/platform/browser/bridge/client.js +1 -0
  38. package/dist/platform/browser/bridge/extension-channel.d.ts +12 -0
  39. package/dist/platform/browser/bridge/extension-channel.js +1 -0
  40. package/dist/platform/browser/bridge/extension-id.d.ts +8 -0
  41. package/dist/platform/browser/bridge/extension-id.js +1 -0
  42. package/dist/platform/browser/bridge/extension-updates.d.ts +37 -0
  43. package/dist/platform/browser/bridge/extension-updates.js +1 -0
  44. package/dist/platform/browser/bridge/model-commands.d.ts +20 -0
  45. package/dist/platform/browser/bridge/model-commands.js +1 -0
  46. package/dist/platform/browser/bridge/model-core.d.ts +59 -0
  47. package/dist/platform/browser/bridge/model-core.js +1 -0
  48. package/dist/platform/browser/bridge/model.d.ts +4 -0
  49. package/dist/platform/browser/bridge/model.js +1 -0
  50. package/dist/platform/browser/bridge/native-frames.d.ts +9 -0
  51. package/dist/platform/browser/bridge/native-frames.js +1 -0
  52. package/dist/platform/browser/bridge/native-host.d.ts +24 -0
  53. package/dist/platform/browser/bridge/native-host.js +5 -0
  54. package/dist/platform/browser/bridge/runtime-contexts.d.ts +12 -0
  55. package/dist/platform/browser/bridge/runtime-contexts.js +1 -0
  56. package/dist/platform/browser/bridge/server-core.d.ts +66 -0
  57. package/dist/platform/browser/bridge/server-core.js +1 -0
  58. package/dist/platform/browser/bridge/server.d.ts +13 -0
  59. package/dist/platform/browser/bridge/server.js +1 -0
  60. package/dist/platform/browser/bridge-tabs.d.ts +22 -0
  61. package/dist/platform/browser/bridge-tabs.js +1 -0
  62. package/dist/platform/browser/cdp-connection.d.ts +3 -0
  63. package/dist/platform/browser/cdp-connection.js +1 -0
  64. package/dist/platform/browser/chrome-binary.d.ts +6 -0
  65. package/dist/platform/browser/chrome-binary.js +1 -0
  66. package/dist/platform/browser/config.d.ts +29 -0
  67. package/dist/platform/browser/config.js +1 -0
  68. package/dist/platform/browser/devtools-port.d.ts +3 -0
  69. package/dist/platform/browser/devtools-port.js +2 -0
  70. package/dist/platform/browser/downloads.d.ts +22 -0
  71. package/dist/platform/browser/downloads.js +1 -0
  72. package/dist/platform/browser/driver-connect.d.ts +13 -0
  73. package/dist/platform/browser/driver-connect.js +1 -0
  74. package/dist/platform/browser/driver-core.d.ts +50 -0
  75. package/dist/platform/browser/driver-core.js +1 -0
  76. package/dist/platform/browser/driver-tabs.d.ts +16 -0
  77. package/dist/platform/browser/driver-tabs.js +1 -0
  78. package/dist/platform/browser/driver-verbs.d.ts +13 -0
  79. package/dist/platform/browser/driver-verbs.js +2 -0
  80. package/dist/platform/browser/driver.d.ts +38 -0
  81. package/dist/platform/browser/driver.js +3 -0
  82. package/dist/platform/browser/focus-guard.d.ts +2 -0
  83. package/dist/platform/browser/focus-guard.js +1 -0
  84. package/dist/platform/browser/journal.d.ts +21 -0
  85. package/dist/platform/browser/journal.js +2 -0
  86. package/dist/platform/browser/keep-in-tab.d.ts +1 -0
  87. package/dist/platform/browser/keep-in-tab.js +1 -0
  88. package/dist/platform/browser/messages.d.ts +25 -0
  89. package/dist/platform/browser/messages.js +8 -0
  90. package/dist/platform/browser/navigate.d.ts +4 -0
  91. package/dist/platform/browser/navigate.js +2 -0
  92. package/dist/platform/browser/occupancy.d.ts +2 -0
  93. package/dist/platform/browser/occupancy.js +2 -0
  94. package/dist/platform/browser/overlay-guard.d.ts +3 -0
  95. package/dist/platform/browser/overlay-guard.js +1 -0
  96. package/dist/platform/browser/save-picker.d.ts +2 -0
  97. package/dist/platform/browser/save-picker.js +1 -0
  98. package/dist/platform/browser/session-files.d.ts +11 -0
  99. package/dist/platform/browser/session-files.js +1 -0
  100. package/dist/platform/browser/state.d.ts +25 -0
  101. package/dist/platform/browser/state.js +2 -0
  102. package/dist/platform/browser/tabs.d.ts +15 -0
  103. package/dist/platform/browser/tabs.js +2 -0
  104. package/dist/platform/browser/window-placement.d.ts +8 -0
  105. package/dist/platform/browser/window-placement.js +1 -0
  106. package/dist/platform/chromium/actions-value.d.ts +11 -0
  107. package/dist/platform/chromium/actions-value.js +5 -0
  108. package/dist/platform/chromium/actions.d.ts +20 -0
  109. package/dist/platform/chromium/actions.js +2 -0
  110. package/dist/platform/chromium/checkable-target.d.ts +1 -0
  111. package/dist/platform/chromium/checkable-target.js +1 -0
  112. package/dist/platform/chromium/collect-viewport.d.ts +1 -0
  113. package/dist/platform/chromium/collect-viewport.js +1 -0
  114. package/dist/platform/chromium/collect.d.ts +11 -0
  115. package/dist/platform/chromium/collect.js +1 -0
  116. package/dist/platform/chromium/coverer-label.d.ts +8 -0
  117. package/dist/platform/chromium/coverer-label.js +1 -0
  118. package/dist/platform/chromium/frames.d.ts +2 -0
  119. package/dist/platform/chromium/frames.js +1 -0
  120. package/dist/platform/chromium/headings.d.ts +1 -0
  121. package/dist/platform/chromium/headings.js +1 -0
  122. package/dist/platform/chromium/locate.d.ts +2 -0
  123. package/dist/platform/chromium/locate.js +1 -0
  124. package/dist/platform/chromium/page-acts.d.ts +9 -0
  125. package/dist/platform/chromium/page-acts.js +1 -0
  126. package/dist/platform/chromium/page-base.d.ts +33 -0
  127. package/dist/platform/chromium/page-base.js +1 -0
  128. package/dist/platform/chromium/page-driver.d.ts +18 -0
  129. package/dist/platform/chromium/page-driver.js +2 -0
  130. package/dist/platform/chromium/page-refs.d.ts +4 -0
  131. package/dist/platform/chromium/page-refs.js +1 -0
  132. package/dist/platform/chromium/page-text.d.ts +15 -0
  133. package/dist/platform/chromium/page-text.js +1 -0
  134. package/dist/platform/chromium/page-waits.d.ts +7 -0
  135. package/dist/platform/chromium/page-waits.js +1 -0
  136. package/dist/platform/chromium/preview-stream.d.ts +37 -0
  137. package/dist/platform/chromium/preview-stream.js +1 -0
  138. package/dist/platform/chromium/preview.d.ts +3 -0
  139. package/dist/platform/chromium/preview.js +1 -0
  140. package/dist/platform/chromium/read-page-script.d.ts +1 -0
  141. package/dist/platform/chromium/read-page-script.js +1 -0
  142. package/dist/platform/chromium/read-page.d.ts +11 -0
  143. package/dist/platform/chromium/read-page.js +6 -0
  144. package/dist/platform/chromium/run-js.d.ts +4 -0
  145. package/dist/platform/chromium/run-js.js +2 -0
  146. package/dist/platform/chromium/scroll-regions.d.ts +1 -0
  147. package/dist/platform/chromium/scroll-regions.js +1 -0
  148. package/dist/platform/chromium/scroll-scripts.d.ts +3 -0
  149. package/dist/platform/chromium/scroll-scripts.js +1 -0
  150. package/dist/platform/chromium/scroll.d.ts +18 -0
  151. package/dist/platform/chromium/scroll.js +5 -0
  152. package/dist/platform/chromium/select-text.d.ts +4 -0
  153. package/dist/platform/chromium/select-text.js +2 -0
  154. package/dist/platform/chromium/shot.d.ts +10 -0
  155. package/dist/platform/chromium/shot.js +2 -0
  156. package/dist/platform/chromium/unreached.d.ts +8 -0
  157. package/dist/platform/chromium/unreached.js +1 -0
  158. package/dist/platform/cli-command.d.ts +1 -0
  159. package/dist/platform/cli-command.js +1 -0
  160. package/dist/platform/driver-base.d.ts +83 -0
  161. package/dist/platform/driver-base.js +1 -0
  162. package/dist/platform/driver-diagnostics.d.ts +30 -0
  163. package/dist/platform/driver-diagnostics.js +4 -0
  164. package/dist/platform/driver-lines.d.ts +15 -0
  165. package/dist/platform/driver-lines.js +2 -0
  166. package/dist/platform/driver-narrate.d.ts +26 -0
  167. package/dist/platform/driver-narrate.js +3 -0
  168. package/dist/platform/driver-refs.d.ts +16 -0
  169. package/dist/platform/driver-refs.js +1 -0
  170. package/dist/platform/driver-render.d.ts +26 -0
  171. package/dist/platform/driver-render.js +4 -0
  172. package/dist/platform/driver-select.d.ts +31 -0
  173. package/dist/platform/driver-select.js +2 -0
  174. package/dist/platform/driver-settle.d.ts +22 -0
  175. package/dist/platform/driver-settle.js +4 -0
  176. package/dist/platform/driver-verdict.d.ts +11 -0
  177. package/dist/platform/driver-verdict.js +5 -0
  178. package/dist/platform/driver-wait.d.ts +9 -0
  179. package/dist/platform/driver-wait.js +1 -0
  180. package/dist/platform/driver-waits.d.ts +10 -0
  181. package/dist/platform/driver-waits.js +1 -0
  182. package/dist/platform/driver.d.ts +39 -0
  183. package/dist/platform/driver.js +15 -0
  184. package/dist/platform/electron/driver.d.ts +30 -0
  185. package/dist/platform/electron/driver.js +7 -0
  186. package/dist/platform/electron/preflight.d.ts +9 -0
  187. package/dist/platform/electron/preflight.js +1 -0
  188. package/dist/platform/electron/verbs.d.ts +3 -0
  189. package/dist/platform/electron/verbs.js +1 -0
  190. package/dist/platform/home.d.ts +2 -0
  191. package/dist/platform/home.js +1 -0
  192. package/dist/platform/macos/act-element.d.ts +27 -0
  193. package/dist/platform/macos/act-element.js +1 -0
  194. package/dist/platform/macos/app-names.d.ts +2 -0
  195. package/dist/platform/macos/app-names.js +2 -0
  196. package/dist/platform/macos/app-notes.d.ts +2 -0
  197. package/dist/platform/macos/app-notes.js +86 -0
  198. package/dist/platform/macos/approvals.d.ts +10 -0
  199. package/dist/platform/macos/approvals.js +2 -0
  200. package/dist/platform/macos/ax-client.d.ts +53 -0
  201. package/dist/platform/macos/ax-client.js +3 -0
  202. package/dist/platform/macos/ax-errors.d.ts +16 -0
  203. package/dist/platform/macos/ax-errors.js +1 -0
  204. package/dist/platform/macos/ax-shapes.d.ts +53 -0
  205. package/dist/platform/macos/ax-shapes.js +1 -0
  206. package/dist/platform/macos/capture-client.d.ts +11 -0
  207. package/dist/platform/macos/capture-client.js +2 -0
  208. package/dist/platform/macos/click-verb.d.ts +4 -0
  209. package/dist/platform/macos/click-verb.js +1 -0
  210. package/dist/platform/macos/driver-apps.d.ts +59 -0
  211. package/dist/platform/macos/driver-apps.js +2 -0
  212. package/dist/platform/macos/driver-read.d.ts +47 -0
  213. package/dist/platform/macos/driver-read.js +1 -0
  214. package/dist/platform/macos/driver-targets.d.ts +9 -0
  215. package/dist/platform/macos/driver-targets.js +1 -0
  216. package/dist/platform/macos/driver.d.ts +65 -0
  217. package/dist/platform/macos/driver.js +2 -0
  218. package/dist/platform/macos/element-lines.d.ts +12 -0
  219. package/dist/platform/macos/element-lines.js +1 -0
  220. package/dist/platform/macos/element-shapes.d.ts +54 -0
  221. package/dist/platform/macos/element-shapes.js +0 -0
  222. package/dist/platform/macos/element-text.d.ts +3 -0
  223. package/dist/platform/macos/element-text.js +2 -0
  224. package/dist/platform/macos/elements.d.ts +26 -0
  225. package/dist/platform/macos/elements.js +1 -0
  226. package/dist/platform/macos/extra-verbs.d.ts +2 -0
  227. package/dist/platform/macos/extra-verbs.js +1 -0
  228. package/dist/platform/macos/interaction-notes.d.ts +2 -0
  229. package/dist/platform/macos/interaction-notes.js +1 -0
  230. package/dist/platform/macos/interaction-policy.d.ts +5 -0
  231. package/dist/platform/macos/interaction-policy.js +1 -0
  232. package/dist/platform/macos/menu-commands.d.ts +22 -0
  233. package/dist/platform/macos/menu-commands.js +5 -0
  234. package/dist/platform/macos/mouse.d.ts +23 -0
  235. package/dist/platform/macos/mouse.js +1 -0
  236. package/dist/platform/macos/narrate.d.ts +20 -0
  237. package/dist/platform/macos/narrate.js +1 -0
  238. package/dist/platform/macos/permissions.d.ts +5 -0
  239. package/dist/platform/macos/permissions.js +1 -0
  240. package/dist/platform/macos/press-rungs.d.ts +49 -0
  241. package/dist/platform/macos/press-rungs.js +5 -0
  242. package/dist/platform/macos/preview-stream.d.ts +15 -0
  243. package/dist/platform/macos/preview-stream.js +1 -0
  244. package/dist/platform/macos/prompt-fragment.d.ts +1 -0
  245. package/dist/platform/macos/prompt-fragment.js +1 -0
  246. package/dist/platform/macos/scroll-pages.d.ts +1 -0
  247. package/dist/platform/macos/scroll-pages.js +1 -0
  248. package/dist/platform/macos/scroll-verb.d.ts +5 -0
  249. package/dist/platform/macos/scroll-verb.js +1 -0
  250. package/dist/platform/macos/select-text-verb.d.ts +8 -0
  251. package/dist/platform/macos/select-text-verb.js +1 -0
  252. package/dist/platform/macos/type-verb.d.ts +5 -0
  253. package/dist/platform/macos/type-verb.js +1 -0
  254. package/dist/platform/ownership.d.ts +20 -0
  255. package/dist/platform/ownership.js +1 -0
  256. package/dist/platform/platform-package.d.ts +1 -0
  257. package/dist/platform/platform-package.js +1 -0
  258. package/dist/platform/preview.d.ts +39 -0
  259. package/dist/platform/preview.js +1 -0
  260. package/dist/platform/profile.d.ts +20 -0
  261. package/dist/platform/profile.js +1 -0
  262. package/dist/platform/registry.d.ts +12 -0
  263. package/dist/platform/registry.js +1 -0
  264. package/dist/platform/tools/api-contract.d.ts +33 -0
  265. package/dist/platform/tools/api-contract.js +3 -0
  266. package/dist/platform/tools/api-expect.d.ts +3 -0
  267. package/dist/platform/tools/api-expect.js +1 -0
  268. package/dist/platform/tools/api-run.d.ts +6 -0
  269. package/dist/platform/tools/api-run.js +1 -0
  270. package/dist/platform/tools/api-target.d.ts +22 -0
  271. package/dist/platform/tools/api-target.js +1 -0
  272. package/dist/platform/tools/api-wait.d.ts +3 -0
  273. package/dist/platform/tools/api-wait.js +1 -0
  274. package/dist/platform/tools/api.d.ts +7 -0
  275. package/dist/platform/tools/api.js +1 -0
  276. package/dist/platform/tools/find-target.d.ts +54 -0
  277. package/dist/platform/tools/find-target.js +1 -0
  278. package/dist/platform/tools/index.d.ts +8 -0
  279. package/dist/platform/tools/index.js +1 -0
  280. package/dist/platform/tools/normalize.d.ts +2 -0
  281. package/dist/platform/tools/normalize.js +1 -0
  282. package/dist/platform/tools/repl-budget.d.ts +8 -0
  283. package/dist/platform/tools/repl-budget.js +4 -0
  284. package/dist/platform/tools/repl-code.d.ts +1 -0
  285. package/dist/platform/tools/repl-code.js +4 -0
  286. package/dist/platform/tools/repl-docs.d.ts +5 -0
  287. package/dist/platform/tools/repl-docs.js +4 -0
  288. package/dist/platform/tools/repl-state.d.ts +21 -0
  289. package/dist/platform/tools/repl-state.js +0 -0
  290. package/dist/platform/tools/repl.d.ts +8 -0
  291. package/dist/platform/tools/repl.js +19 -0
  292. package/dist/platform/tools/shot-file.d.ts +7 -0
  293. package/dist/platform/tools/shot-file.js +1 -0
  294. package/dist/platform/tools/validate.d.ts +2 -0
  295. package/dist/platform/tools/validate.js +1 -0
  296. package/dist/platform/types.d.ts +220 -0
  297. package/dist/platform/types.js +1 -0
  298. package/dist/platform/windows/app-gate.d.ts +24 -0
  299. package/dist/platform/windows/app-gate.js +2 -0
  300. package/dist/platform/windows/background-verb.d.ts +13 -0
  301. package/dist/platform/windows/background-verb.js +1 -0
  302. package/dist/platform/windows/dates.d.ts +2 -0
  303. package/dist/platform/windows/dates.js +1 -0
  304. package/dist/platform/windows/driver-apps.d.ts +9 -0
  305. package/dist/platform/windows/driver-apps.js +1 -0
  306. package/dist/platform/windows/driver-read.d.ts +12 -0
  307. package/dist/platform/windows/driver-read.js +3 -0
  308. package/dist/platform/windows/driver-targets.d.ts +58 -0
  309. package/dist/platform/windows/driver-targets.js +1 -0
  310. package/dist/platform/windows/driver-yield.d.ts +10 -0
  311. package/dist/platform/windows/driver-yield.js +1 -0
  312. package/dist/platform/windows/driver.d.ts +39 -0
  313. package/dist/platform/windows/driver.js +2 -0
  314. package/dist/platform/windows/elements.d.ts +66 -0
  315. package/dist/platform/windows/elements.js +2 -0
  316. package/dist/platform/windows/launch.d.ts +23 -0
  317. package/dist/platform/windows/launch.js +1 -0
  318. package/dist/platform/windows/menu-verb.d.ts +7 -0
  319. package/dist/platform/windows/menu-verb.js +6 -0
  320. package/dist/platform/windows/prompt-fragment.d.ts +2 -0
  321. package/dist/platform/windows/prompt-fragment.js +1 -0
  322. package/dist/platform/windows/text-verbs.d.ts +10 -0
  323. package/dist/platform/windows/text-verbs.js +5 -0
  324. package/dist/platform/windows/uia-client.d.ts +32 -0
  325. package/dist/platform/windows/uia-client.js +3 -0
  326. package/dist/platform/windows/verbs.d.ts +2 -0
  327. package/dist/platform/windows/verbs.js +1 -0
  328. package/extension/background.js +280 -0
  329. package/extension/connect.html +27 -0
  330. package/extension/connect.js +28 -0
  331. package/extension/group.js +283 -0
  332. package/extension/icons/icon-128.png +0 -0
  333. package/extension/icons/icon-16.png +0 -0
  334. package/extension/icons/icon-32.png +0 -0
  335. package/extension/icons/icon-48.png +0 -0
  336. package/extension/manifest.json +36 -0
  337. package/extension/relay.js +361 -0
  338. package/extension/runtime-info.js +9 -0
  339. package/extension/transport.js +81 -0
  340. package/package.json +76 -4
  341. package/scripts/extension.mjs +111 -0
@@ -0,0 +1,39 @@
1
+ import type { ShotScope, TargetInfo, ToolResult } from "./types.ts";
2
+ import { ComputerUseDriverWaits } from "./driver-waits.ts";
3
+ import type { PreviewTarget } from "./types.ts";
4
+ export { STATE_CHANGING_ACTIONS } from "./driver-settle.ts";
5
+ export declare abstract class ComputerUseDriver extends ComputerUseDriverWaits {
6
+ surfaceIdPrefix: string;
7
+ onPreview?: (target: PreviewTarget, at: number) => void;
8
+ protected previewTarget(): Promise<PreviewTarget | null>;
9
+ publishPreview(kind?: string, args?: Record<string, unknown>): void;
10
+ consentPurpose: string | null;
11
+ permissionRefusal: string | null;
12
+ turnEnded(_info: {
13
+ sessionId: string;
14
+ turnId: string;
15
+ hookEventName: string;
16
+ keepBrowserTabs?: boolean;
17
+ }): Promise<void>;
18
+ ensureSettleBaseline(kind: string): Promise<void>;
19
+ observeElements(opts?: {
20
+ prefix?: string;
21
+ forceImage?: boolean;
22
+ afterAction?: string;
23
+ }): Promise<ToolResult>;
24
+ private geometryChanges;
25
+ protected frozenExtra(): string | null;
26
+ explainMiss(_query: string): string | null;
27
+ unlistedTarget(_query: string): Promise<TargetInfo | null>;
28
+ waitedOnUserMs: number;
29
+ endCall(): void;
30
+ protected treeBlind(): boolean;
31
+ private takeActionsInRound;
32
+ private frozenFacts;
33
+ observeImage(opts?: {
34
+ prefix?: string;
35
+ scope?: ShotScope;
36
+ modelInitiated?: boolean;
37
+ }): Promise<ToolResult>;
38
+ observeFullText(): Promise<ToolResult>;
39
+ }
@@ -0,0 +1,15 @@
1
+ import{SurfaceGoneError as k,SurfaceUnreadableError as C,text as m}from"./types.js";import"./driver-narrate.js";import{OBSERVE_FROZEN_NOTE as z}from"./driver-lines.js";import{disclosureClosed as L,effectAlreadyShown as F,elementSignature as N,onlyRefsLost as B,settleAfterStateAction as G,STATE_CHANGING_ACTIONS as I,substantiveElementSignature as v}from"./driver-settle.js";import{ComputerUseDriverWaits as U}from"./driver-waits.js";import{STATE_CHANGING_ACTIONS as J}from"./driver-settle.js";const Y=new Set(["textbox","searchbox"]);class W extends U{surfaceIdPrefix="";onPreview;previewTarget(){return Promise.resolve(null)}publishPreview(t,r={}){if(!this.onPreview||this.permissionRefusal)return;const c=Date.now(),e=typeof r.ref=="string"?this.lastRects?.get(r.ref):void 0,o=typeof r.x=="number"?r.x:e?e.x+e.w/2:void 0,i=typeof r.y=="number"?r.y:e?e.y+e.h/2:void 0;this.previewTarget().then(n=>{n&&!this.permissionRefusal&&this.onPreview?.({...n,...t&&o!==void 0&&i!==void 0?{pointer:{x:o,y:i,kind:t,ts:c}}:{}},c)}).catch(()=>{})}consentPurpose=null;permissionRefusal=null;async turnEnded(t){}async ensureSettleBaseline(t){if(!(!I.has(t)||this.prevElSigSubstantive!==null))try{const{snapshot:r}=await this.bounded("observe",this.captureSnapshot());this.prevElSigSubstantive=v(r.elements)}catch{}}async observeElements(t={}){let r;try{r=await this.bounded("observe",this.captureSnapshot())}catch(s){if(this.prevSig=null,this.takeSurfaceChange(),this.forgetDeltaBase(),this.noteObserveFailure(s.message),s instanceof k||s instanceof C)throw s;const h=`(observe failed: ${s.message})`,f=this.takePendingNote(),g=[t.prefix,f?`NOTE: ${f}.`:"",h].filter(Boolean).join(`
2
+ `),u=g.split(`
3
+ `).length;return m(g,{verdict:"unknown",actionLines:u,headLines:u})}const c=t.afterAction==="click"&&this.lastActionRef!==null?r.snapshot.elements.find(s=>s.ref===this.lastActionRef):void 0;if(I.has(t.afterAction??"")&&!(c&&Y.has(c.role))){const s=this.lastRects?new Set(this.lastRects.keys()):null,h=this.prevElSig,f=this.lastScrollY,g=t.afterAction??"";r=await G({capture:r,previous:this.prevElSigSubstantive,signature:u=>v(u.snapshot.elements),unsettled:(u,p)=>{const d=p.snapshot.elements,$=f!==null&&Math.abs(p.snapshot.meta.scrollY-f)>=3;return u===v(d)?!F({action:g,target:d.find(b=>b.ref===this.lastActionRef)??d.find(b=>b.state.startsWith("focused")),scrolled:$,focusMoved:h!==null&&h!==N(d),geometryMoved:this.geometryChanges(p.snapshot)!==null}):$||s===null||!B(s,d)?!1:this.geometryChanges(p.snapshot)===null||L(h,d)},recapture:()=>this.bounded("observe",this.captureSnapshot())})}const e=r.snapshot;this.publishPreview();const o=this.signature(e),i=this.takeSurfaceChange(),n=i?"changed":this.prevSig===null?null:this.prevSig===o?"frozen":"changed";this.prevSig=o;const l=N(e.elements),S=this.prevElSig!==null&&this.prevElSig===l;this.prevElSig=l,this.prevElSigSubstantive=v(e.elements),this.lastGeomChange=this.geometryChanges(e),this.lastRects=new Map(e.elements.map(s=>[s.ref,s.rect])),this.lastScrollY=e.meta.scrollY,this.rememberRefs(e),n==="frozen"&&this.journalVerdict?.("frozen");const M=this.takeActionsInRound(),y=!t.afterAction&&this.takeContentRead();let a=t.prefix??"";const w=this.takePendingNote();if(w&&(a+=(a?`
4
+ `:"")+`NOTE: ${w}.`),n==="frozen"&&!y){a+=(a?`
5
+ `:"")+(t.afterAction?this.frozenNote(t.afterAction,this.frozenFacts(M)):z);const s=this.frozenExtra();s&&(a+=`
6
+ ${s}`)}const x=this.diag?.takeNote(e.url);x&&(a+=(a?`
7
+ `:"")+x),!t.afterAction&&!y&&!i&&++this.observesSinceAction>=3&&(n!=="changed"||S)&&(a+=(a?`
8
+ `:"")+`NOTE: ${this.observesSinceAction} observations in a row without acting, and the actionable elements are not changing \u2014 more looking will not reveal more. Act now (click / set_text / drag / scroll), or if the target truly is not on this screen, scroll or switch target.`);const A=await this.listTargets().catch(()=>[]),O=this.surfaceIdPrefix?A.map(s=>({...s,id:`${this.surfaceIdPrefix}${s.id}`})):A,{body:E,obsKind:P,headLines:_,effectNote:R}=this.renderObservation(e,O,n,{...t,surfaceChanged:i}),T=m(a?`${a}
9
+ ${E}`:E,{url:e.url,verdict:n,elementCount:e.elements.length,obsKind:P,headLines:(a?a.split(`
10
+ `).length:0)+_,actionLines:a?a.split(`
11
+ `).length:0,keep:[...this.contextKeep,...this.trimSurvivors(),...R?[R]:[]],coverage:this.observationCoverage(e),...e.target?{target:e.target}:{},viewport:this.viewportPosition(e.meta),...e.meta.offscreen||e.meta.capped?{notListed:{offscreen:e.meta.offscreen??0,capped:e.meta.capped??0}}:{}});if(t.forceImage){const s=r.image??await this.screenshot().then(h=>({bytes:h,mimeType:this.screenshotMimeType})).catch(()=>null);s&&T.content.push({type:"image",data:s.bytes.toString("base64"),mimeType:s.mimeType})}return T}geometryChanges(t){const r=this.lastRects;if(!r)return null;const c=[];let e=0;const o=i=>Math.round(i);for(const i of t.elements){const n=r.get(i.ref);if(!n)continue;const l=Math.abs(i.rect.w-n.w)>=3||Math.abs(i.rect.h-n.h)>=3;if(!(!(Math.abs(i.rect.x-n.x)>=3||Math.abs(i.rect.y-n.y)>=3)&&!l)){if(c.length>=2){e++;continue}c.push(l?`${i.ref} resized ${o(n.w)}\xD7${o(n.h)} \u2192 ${o(i.rect.w)}\xD7${o(i.rect.h)}`:`${i.ref} moved (${o(n.x)},${o(n.y)}) \u2192 (${o(i.rect.x)},${o(i.rect.y)})`)}}return c.length===0?null:c.join(", ")+(e?` (+${e} more)`:"")}frozenExtra(){return null}explainMiss(t){return null}async unlistedTarget(t){return null}waitedOnUserMs=0;endCall(){}treeBlind(){return!1}takeActionsInRound(){const t=this.actionsInRound;return this.actionsInRound=0,t}frozenFacts(t){return{scrollMoved:this.lastScrollMoved,writeRound:this.writeRound,geomChange:this.lastGeomChange,repeated:this.lastActionSig!==null&&this.lastActionSig===this.prevActionSig,actionsInRound:t,treeBlind:this.treeBlind()}}async observeImage(t={}){const r=t.modelInitiated&&!this.takeContentRead()&&++this.observesSinceAction>=3?`
12
+ NOTE: ${this.observesSinceAction} observations in a row without acting \u2014 more looking will not reveal more; act (click / set_text / drag / scroll) before looking again.`:"";if(t.scope){let n;try{n=await this.bounded("screenshot",this.screenshotScoped(t.scope))}catch(l){if(l instanceof k||l instanceof C)throw l;return m(`(screenshot failed: ${l.message})`,{error:"shot_failed"})}return{content:[{type:"text",text:`Screenshot captured (${n.note}). Scoped shots are for looking \u2014 point coordinates for actions live in FULL screenshots; use the returned mapping when provided, or act by ref.`+r},{type:"image",data:n.bytes.toString("base64"),mimeType:n.mimeType}],details:{scoped:!0,bytes:n.bytes.length,...n.capture?{capture:n.capture}:{}}}}const c=await this.bounded("screenshot",this.screenshot());this.takeSurfaceChange(),this.takeActionsInRound();let e=t.prefix??"";const o=this.takePendingNote();o&&(e+=(e?`
13
+ `:"")+`NOTE: ${o}.`);const i=this.diag?.takeNote(await this.currentUrl().catch(()=>""));return i&&(e+=(e?`
14
+ `:"")+i),{content:[{type:"text",text:`${e?`${e}
15
+ `:""}Screenshot captured. Anything without a ref can be acted on by x/y coordinates from this image.${r}`},{type:"image",data:c.toString("base64"),mimeType:this.screenshotMimeType}],details:{verdict:null,bytes:c.length}}}async observeFullText(){const t=await this.bounded("read text",this.readText());return m(t||"(no readable text \u2014 the page may still be rendering; wait, then observe again)",{chars:t.length})}}export{W as ComputerUseDriver,J as STATE_CHANGING_ACTIONS};
@@ -0,0 +1,30 @@
1
+ import { type Page } from "playwright-core";
2
+ import { ChromiumPageDriver } from "../chromium/page-driver.ts";
3
+ import { type ActResult, type Snapshot, type TargetInfo, type VerbSpec } from "../types.ts";
4
+ export declare class ElectronDriver extends ChromiumPageDriver {
5
+ protected previewTarget(): Promise<import("../types.ts").PreviewTarget | null>;
6
+ readonly platform = "electron";
7
+ private browser;
8
+ private context;
9
+ private active;
10
+ private windowIds;
11
+ private nextWindowId;
12
+ private readonly cdpUrl;
13
+ constructor(opts?: {
14
+ cdpUrl?: string;
15
+ env?: NodeJS.ProcessEnv;
16
+ });
17
+ protected snapshot(): Promise<Snapshot>;
18
+ extraVerbs(): VerbSpec[];
19
+ protected staleRefCause(): string;
20
+ promptFragment(): string;
21
+ protected ensure(): Promise<void>;
22
+ private surfaces;
23
+ private goneMessage;
24
+ protected page(): Page;
25
+ listTargets(): Promise<TargetInfo[]>;
26
+ focusTarget(id: string): Promise<ActResult>;
27
+ private windowId;
28
+ perform(kind: string, a: Record<string, unknown>): Promise<ActResult>;
29
+ close(): Promise<void>;
30
+ }
@@ -0,0 +1,7 @@
1
+ import{chromium as d}from"playwright-core";import{ChromiumPageDriver as u}from"../chromium/page-driver.js";import{previewPage as p}from"../chromium/preview.js";import{DRAG_VERB as w,fileInputFor as f,performUploadToRef as g,refuseMissingFiles as m}from"../chromium/actions.js";import{PASTE_VERB as v,SELECT_OPTION_VERB as b}from"../chromium/actions-value.js";import{SELECT_TEXT_VERB as E}from"../chromium/select-text.js";import{performRunJs as T}from"../chromium/run-js.js";import{ensureRefSelector as y}from"../chromium/page-refs.js";import{SurfaceGoneError as h}from"../types.js";import{closeWedgedAuxTargets as U,isAuxUrl as _,listTargets as C}from"./preflight.js";const R="http://127.0.0.1:9333";function S(i){const t=i.url();return!i.isClosed()&&!!t&&t!=="about:blank"&&!_(t)&&!t.includes("#/aux/computer-use")}const O=15e3;function l(i,t){return`mirasim-cu: no Electron app is listening on ${i}.
2
+ (${t})
3
+ This driver attaches to a running app and never starts one, and it needs that app's renderer debugging port \u2014 a DEV-ONLY port. Start the app's dev build with that port open (\`--remote-debugging-port=9333\`, or whatever its dev script uses), or point COMPUTER_USE_ELECTRON_CDP_URL at the port yours uses.
4
+ An INSTALLED app opens no such port and cannot be driven here: the port is unauthenticated, so shipping one would hand every local process the app. To operate an installed app, use its own authenticated route (a CLI or API it ships).`}import{RUN_JS_VERB as x,UPLOAD_TO_REF_VERB as I}from"./verbs.js";class j extends u{previewTarget(){return!this.active||this.active.isClosed()?Promise.resolve(null):p(this.active,this.cdpUrl,"electron")}platform="electron";browser=null;context=null;active=null;windowIds=new WeakMap;nextWindowId=1;cdpUrl;constructor(t={}){super();const e=t.env??process.env;this.cdpUrl=t.cdpUrl?.trim()||e.COMPUTER_USE_ELECTRON_CDP_URL?.trim()||R}async snapshot(){const t=await super.snapshot(),e=await this.page().evaluate(()=>{const n=/\(KHTML, like Gecko\) (.+?)\/(\S+) Chrome\/.* Electron\//.exec(navigator.userAgent);return n?{name:n[1],version:n[2]}:void 0}).catch(()=>{});return t.target={transport:"cdp",endpoint:this.cdpUrl,windowId:this.windowId(this.page()),...e?{application:e}:{}},t}extraVerbs(){return[w,v,b,E,I,x]}staleRefCause(){return"it predates a navigation, a reload or a window switch"}promptFragment(){return"You are operating a DESKTOP APPLICATION, not a web page: there is no address bar, no back button and no reload \u2014 reach everything through the app's own UI. computer.surfaces() lists WINDOWS, not tabs. run_js is the app's DevTools console \u2014 a DEBUG channel for inspecting state; operating the product goes through the interaction verbs. Grounding: observations are text lists of interactive elements with refs, for the CURRENT viewport only. Act by ref from the latest observation. When what you want is NOT in the list: if you can name it, w.find('<name>') searches EVERY control in the window and hands back a handle \u2014 act on it directly, the click scrolls it into view, so do not scroll first. Scroll only to discover what you cannot name. Observations may show only changes since the previous one; refs stay valid across observations. Use text() to read the full window text."}async ensure(){if(this.browser?.isConnected()&&this.active&&!this.active.isClosed())return;if(this.browser?.isConnected()){if(!this.surfaces().length)throw new h(this.goneMessage());this.resetObservationState();return}this.browser=null,this.context=null,this.active=null;const t=await C(this.cdpUrl);if(t===null)throw new Error(l(this.cdpUrl,"nothing answers at /json/list"));const e=t?await U(this.cdpUrl,t):[];let n;try{n=await d.connectOverCDP(this.cdpUrl,{timeout:O}),await y(n)}catch(r){const a=r instanceof Error?r.message.split(`
5
+ `)[0]??"":String(r);throw t?new Error(`mirasim-cu: ${this.cdpUrl} answers \u2014 ${t.length} target(s): ${t.map(c=>c.url).join(", ")} \u2014 but attaching to it failed.
6
+ (${a})
7
+ Attaching initialises every target, so one renderer that never answers hangs the whole connection; a DevTools window is the usual one`+(e.length?` (${e.length} unresponsive one(s) were just closed: ${e.join(", ")})`:"")+". Close the app's DevTools windows and try again."):new Error(l(this.cdpUrl,a))}const o=n.contexts()[0];if(!o)throw await n.close().catch(()=>{}),new Error(`mirasim-cu: ${this.cdpUrl} answered but exposes no browser context.`);this.browser=n,this.context=o;const s=this.surfaces();if(!s.length)throw new Error(`mirasim-cu: attached to ${this.cdpUrl} but the app has no renderer window to drive (only its DevTools or an about:blank surface). Open the app's window and try again.`);this.active=s[s.length-1],this.resetObservationState()}surfaces(){return(this.context?.pages()??[]).filter(S)}goneMessage(){return"The application you were driving has closed \u2014 every window is gone. This driver attaches to a running app and never starts one, so there is nothing to reopen and nothing to re-observe. Stop and report what you had done when it closed."}page(){if(this.active&&!this.active.isClosed())return this.active;throw new h("The bound Electron window closed. List surfaces and explicitly bind the intended remaining window; no input was redirected.")}async listTargets(){return await this.ensure(),await Promise.all(this.surfaces().map(async t=>({id:this.windowId(t),kind:"window",title:await t.title().catch(()=>"")||t.url(),active:t===this.active})))}async focusTarget(t){await this.ensure();for(const e of this.surfaces())if(this.windowId(e)===t)return this.active=e,this.resetObservationState(),{ok:!0};return{ok:!1,note:`no window with id ${t}; call computer.surfaces() for current ids`}}windowId(t){let e=this.windowIds.get(t);return e||(e=`w${this.nextWindowId++}`,this.windowIds.set(t,e)),e}async perform(t,e){if(await this.ensure(),t==="upload"){const n=Array.isArray(e.paths)?e.paths:[],o=m(n);if(o)return o;const s=String(e.ref),r=e.name,a=await this.locate(s,r,!1);if(!a)return await this.missing(s,r);const c=await f(a);return c?await g(n,s,async()=>c,()=>this.missing(s,r)):{ok:!1,note:`${s} is not a file input and the UI around it holds no single one \u2014 pass the attach control itself; if that button opens the app's OWN file dialog, the window is native and cannot be answered`}}return t==="run_js"?await T(()=>this.page(),e.code):await this.dispatchPage(t,e)??{ok:!1,note:`unknown action kind ${t}`}}async close(){await this.browser?.close().catch(()=>{}),this.browser=null,this.context=null,this.active=null,this.resetObservationState(),this.resetPageState(),await this.disconnected()}}export{j as ElectronDriver};
@@ -0,0 +1,9 @@
1
+ export interface CdpTarget {
2
+ id: string;
3
+ type: string;
4
+ url: string;
5
+ webSocketDebuggerUrl?: string;
6
+ }
7
+ export declare const isAuxUrl: (url: string) => boolean;
8
+ export declare function listTargets(cdpUrl: string, timeoutMs?: number): Promise<CdpTarget[] | null | undefined>;
9
+ export declare function closeWedgedAuxTargets(cdpUrl: string, targets: CdpTarget[], probeMs?: number): Promise<string[]>;
@@ -0,0 +1 @@
1
+ import{WebSocket as a}from"ws";const c=t=>/^(devtools|chrome|chrome-extension|chrome-devtools):/.test(t);async function m(t,s=3e3){if(/^https?:/i.test(t))try{const o=await fetch(new URL("/json/list",t),{signal:AbortSignal.timeout(s)});return o.ok?await o.json():null}catch{return null}}async function f(t,s,o=2e3){const n=[];for(const e of s)e.type!=="page"||!c(e.url)||!e.webSocketDebuggerUrl||await u(e.webSocketDebuggerUrl,o)||(await fetch(new URL(`/json/close/${e.id}`,t),{signal:AbortSignal.timeout(o)}).catch(()=>{}),n.push(e.url));return n}function u(t,s){return new Promise(o=>{const n=new a(t),e=i=>{clearTimeout(r),n.terminate(),o(i)},r=setTimeout(()=>e(!1),s);n.on("open",()=>n.send(JSON.stringify({id:1,method:"Runtime.evaluate",params:{expression:"1"}}))),n.on("message",()=>e(!0)),n.on("error",()=>e(!1))})}export{f as closeWedgedAuxTargets,c as isAuxUrl,m as listTargets};
@@ -0,0 +1,3 @@
1
+ import { type VerbSpec } from "../types.ts";
2
+ export declare const UPLOAD_TO_REF_VERB: VerbSpec;
3
+ export declare const RUN_JS_VERB: VerbSpec;
@@ -0,0 +1 @@
1
+ import{Type as e}from"typebox";import{RUN_JS_CODE_DESC as t}from"../chromium/run-js.js";import"../types.js";const o={kind:"upload",schema:e.Object({kind:e.Literal("upload"),paths:e.Array(e.String(),{description:"Absolute path(s) of the file(s) to upload. They must already exist on this machine.",minItems:1}),ref:e.String({description:"REQUIRED here: the attach control you can SEE \u2014 the paperclip/add button, or a `file` element if the list shows one. The input behind such a button is hidden and never appears in an observation, so it is found from this ref instead. If the button opens the app's OWN file dialog rather than a hidden input, that window is native and cannot be answered \u2014 use another route (many apps also accept a typed or pasted path)."}),name:e.Optional(e.String({description:"Visible name of the element \u2014 identity check + fallback locator"}))})},r={kind:"run_js",readOnly:!0,schema:e.Object({kind:e.Literal("run_js"),code:e.String({description:`${t} This is YOUR OWN app under development, so the console is an ordinary part of debugging it \u2014 including the command bridges it exposes.`})})};export{r as RUN_JS_VERB,o as UPLOAD_TO_REF_VERB};
@@ -0,0 +1,2 @@
1
+ export declare function computerUseHome(env?: NodeJS.ProcessEnv): string;
2
+ export declare function sharedHome(): string;
@@ -0,0 +1 @@
1
+ import{homedir as e}from"node:os";import{join as m,resolve as t}from"node:path";function u(r=process.env){const o=r.COMPUTER_USE_HOME?.trim();return o?t(o):i()}function i(){return m(e(),".mirasim-computer-use")}export{u as computerUseHome,i as sharedHome};
@@ -0,0 +1,27 @@
1
+ import type { ActResult } from "../types.ts";
2
+ export interface RefTarget {
3
+ key: string;
4
+ name: string;
5
+ role: string;
6
+ actions: string[];
7
+ enabled: boolean;
8
+ }
9
+ export type AxCall = <T>(op: string, params?: Record<string, unknown>) => Promise<T>;
10
+ export declare class ElementActs {
11
+ readonly call: AxCall;
12
+ keys: Map<string, RefTarget>;
13
+ constructor(call: AxCall);
14
+ nameKeys: (msg: string) => string;
15
+ resolve(ref: unknown, name: unknown): RefTarget | ActResult;
16
+ refForKey(key: string): string | null;
17
+ staleRef(ref: unknown): ActResult;
18
+ what(k: RefTarget, ref: unknown): string;
19
+ private static readonly MENU_TAIL;
20
+ action(ref: unknown, name: unknown, action: string): Promise<ActResult>;
21
+ press(ref: unknown, name: unknown, times: number): Promise<ActResult>;
22
+ focus(ref: unknown, name: unknown): Promise<ActResult>;
23
+ setValue(ref: unknown, name: unknown, text: string): Promise<ActResult>;
24
+ private readBack;
25
+ private readBackUntil;
26
+ tookFocus(key: string): Promise<boolean>;
27
+ }
@@ -0,0 +1 @@
1
+ import{AxRequestError as c}from"./ax-client.js";import{normName as d}from"./ax-shapes.js";import{SECONDARY_ACTIONS as y,axActionName as k}from"./elements.js";import{nameAgrees as p}from"../driver-refs.js";const w=800,m=60;function f(l,t){if(l===t||l.trim()===t.trim())return!0;const n=Number(l),s=Number(t);return l.trim()!==""&&t.trim()!==""&&Number.isFinite(n)&&Number.isFinite(s)&&n===s}class u{call;keys=new Map;constructor(t){this.call=t}nameKeys=t=>t.replace(/\bk\d+\b/g,n=>{for(const[s,e]of this.keys)if(e.key===n)return s;return"an element outside the listing"});resolve(t,n){const s=typeof t=="string"?this.keys.get(t):void 0;if(!s)return this.staleRef(t);if(typeof n=="string"&&n.trim()&&s.name&&!p(s.name,n)){const e=d(n),i=[...this.keys].find(([,a])=>d(a.name)===e)?.[0];return{ok:!1,note:`${String(t)} is now "${s.name}", not "${n}"${i?` \u2014 "${n}" is ${i}`:" \u2014 re-observe"}; nothing was pressed`}}return s}refForKey(t){for(const[n,s]of this.keys)if(s.key===t)return n;return null}staleRef(t){return{ok:!1,note:`ref ${String(t??"(none)")} is not in the latest observation \u2014 re-observe and act on a current ref`}}what(t,n){return t.name?`"${t.name}"`:`the unnamed ${t.role} ${String(n)}`}static MENU_TAIL=". Escape closes it; if Escape does nothing the menu is the system's and only hears the keyboard while the app is frontmost \u2014 activate, then Escape";async action(t,n,s){const e=this.resolve(t,n);if(!("key"in e))return e;const i=k(s);if(!i)return{ok:!1,note:`"${s}" is not an accessibility action \u2014 use one of ${Object.values(y).join(", ")}, or an AX name like AXShowMenu`};const a=this.what(e,t);if(e.actions.length&&!e.actions.includes(i))return{ok:!1,note:`${a} does not offer ${i} \u2014 it offers ${e.actions.join(", ")}. Run one of those, or click it`};try{await this.call("press",{key:e.key,action:i})}catch(o){if(o instanceof c&&o.code==="stale_key")return this.staleRef(t);if(o instanceof c&&o.code==="ax_error")return{ok:!1,mayHaveActed:!0,note:`the app answered AXError ${o.ax??"?"} to ${i} on ${a} \u2014 it advertises the action but reports it cannot run it. Some apps answer this and act anyway, sometimes after a delay; if the observation shows nothing happened, activate the app and drive it with keys`+(i==="AXShowMenu"?u.MENU_TAIL:"")};throw o}return{ok:!0,note:`ran ${i} on ${a}${i==="AXShowMenu"?u.MENU_TAIL:""}`}}async press(t,n,s){const e=this.resolve(t,n);if(!("key"in e))return e;const i=this.what(e,t);if(!e.actions.includes("AXPress")&&(e.role==="textbox"||e.role==="combobox")&&!e.actions.includes("AXOpen")){const o=await this.focus(t,n);return o.ok?{ok:!0,note:`a ${e.role} has no press, so the click focused it \u2014 set_text, type or keys go there now`}:o}const a=e.actions.includes("AXPress")?"AXPress":["AXOpen","AXPick"].find(o=>e.actions.includes(o));try{for(let o=0;o<s;o++)await this.call("press",{key:e.key,...a&&a!=="AXPress"?{action:a}:{}})}catch(o){if(o instanceof c&&o.code==="stale_key")return this.staleRef(t);if(o instanceof c&&o.code==="ax_error"){const r=a?a==="AXPress"?"it may need real focus: try activate, then keys":`the element advertises ${a} but the app reports it cannot run it; if nothing changed below, activate the app and drive it with keys`:`it has no action that can stand in for a click \u2014 ${e.actions.length?`it offers only ${e.actions.join(", ")}`:"it advertises none at all"}. Act on a listed control that has one, or activate the app and drive it with keys`;return{ok:!1,mayHaveActed:!0,note:`the app answered AXError ${o.ax??"?"} to ${a??"AXPress"} on ${i} \u2014 ${r}`}}throw o}return a&&a!=="AXPress"?{ok:!0,note:`this element has no AXPress, so its ${a} ran instead \u2014 the app's own ${a==="AXOpen"?"open":"selection"}, which may do more than a click would`}:{ok:!0}}async focus(t,n){const s=this.resolve(t,n);if(!("key"in s))return s;try{await this.call("focus",{key:s.key})}catch(e){if(e instanceof c&&e.code==="stale_key")return this.staleRef(t);if(e instanceof c&&e.code==="ax_error")return{ok:!1,note:`${this.what(s,t)} will not take focus (AXError ${e.ax??"?"}) \u2014 click it first, or act on the control that does hold focus`};throw e}return{ok:!0}}async setValue(t,n,s){const e=this.resolve(t,n);if(!("key"in e))return e;try{await this.call("setvalue",{key:e.key,text:s})}catch(r){if(r instanceof c&&r.code==="stale_key")return this.staleRef(t);if(r instanceof c&&r.code==="ax_error")return{ok:!1,mayHaveActed:!0,note:`the app answered AXError ${r.ax??"?"} to AXSetValue on ${this.what(e,t)} \u2014 it takes typed input only. Focus it (click it, or select_text with a caret), then type({text}).`};throw r}const a=await this.tookFocus(e.key)?" The field now holds the keyboard focus, so keys and type go here.":` ${this.what(e,t)} would NOT take the keyboard focus, so keys and type go to whatever the app has focused \u2014 click the field, or select_text with a caret, before pressing a key.`;if(e.actions.includes("AXConfirm"))return/^[~/]/.test(s)&&s.includes("/")&&e.name!=="#PathTextField"?{ok:!0,note:`WARNING: ${this.what(e,t)} is a NAME field and "${s}" is a path \u2014 a Save panel does not follow a path written this way: it saves a file named with the slashes turned into colons, in the folder it is showing now. Put only the file name here, and choose the folder first (the panel's location popup or sidebar by ref, or \u2318\u21E7G Go To Folder with the app frontmost). This field commits on Enter.${a}`}:{ok:!0,note:`value set through accessibility (replaces the field's content). This field commits on Enter \u2014 keys('Enter') commits it, Escape discards it. If the value does not stick (a file being renamed), the field takes text only while editing: Enter to start editing, then type({text}), then Enter.${a}`};const o=s===""?null:await this.readBackUntil(e.key,s);if(o===null)return{ok:!0,note:`value set through accessibility (replaces the field's content).${a}`};if(!f(o,s)){const r=h=>h.length>60?`${h.slice(0,60)}\u2026`:h;return{ok:!0,verified:!1,note:`WARNING: ${this.what(e,t)} ${o?`reads \xAB${r(o)}\xBB`:"is still empty"} after the write, not what you sent \u2014 the app accepted AXSetValue and discarded it. A control that takes typed input only (a slider, a search field that filters as you type) needs type({text}) after a click.${a}`}}return{ok:!0,verified:!0,note:`value set through accessibility (replaces the field's content).${a}`}}async readBack(t){try{const n=(await this.call("value",{key:t})).value;return n==null?null:String(n)}catch{return null}}async readBackUntil(t,n){const s=Date.now()+w;for(;;){const e=await this.readBack(t);if(e===null||f(e,n)||Date.now()>=s)return e;await new Promise(i=>setTimeout(i,m))}}async tookFocus(t){try{return await this.call("focus",{key:t}),!0}catch{return!1}}}export{u as ElementActs};
@@ -0,0 +1,2 @@
1
+ export type AppNameResolver = (name: string) => Promise<string[]>;
2
+ export declare const findInstalledApps: AppNameResolver;
@@ -0,0 +1,2 @@
1
+ import{execFile as c}from"node:child_process";import{readdirSync as l}from"node:fs";import{homedir as f}from"node:os";import{join as s}from"node:path";const m=["/Applications","/Applications/Utilities","/System/Applications","/System/Applications/Utilities",s(f(),"Applications"),"/System/Library/CoreServices"],u=3e3;function p(t,i){return new Promise(n=>{c(t,i,{timeout:u,encoding:"utf8"},(e,o)=>n(e?"":o))})}async function d(t){return(await p("/usr/bin/plutil",["-extract","CFBundleIdentifier","raw","-o","-",s(t,"Contents","Info.plist")])).trim()||null}function a(t){return t.trim().replace(/\.app$/i,"").toLowerCase()}function y(t){const i=a(t),n=[];for(const e of m){let o;try{o=l(e)}catch{continue}for(const r of o)/\.app$/i.test(r)&&a(r)===i&&n.push(s(e,r))}return n}async function w(t){const i=t.trim().replace(/\.app$/i,"");if(!i||/["\\*]/.test(i))return[];const n=`kMDItemContentType == "com.apple.application-bundle" && (kMDItemDisplayName == "${i}"cd || kMDItemDisplayName == "${i}.app"cd)`;return(await p("/usr/bin/mdfind",[n])).split(`
2
+ `).map(e=>e.trim()).filter(Boolean)}const S=async t=>{if(process.platform!=="darwin"||!t.trim())return[];let i=y(t);i.length||(i=await w(t));const n=[];for(const e of i){const o=await d(e);o&&!n.includes(o)&&n.push(o)}return n};export{S as findInstalledApps};
@@ -0,0 +1,2 @@
1
+ export declare const SAVE_PANEL_NOTE = "Save panel, known quirks:\n- A folder in the sidebar (Desktop, Documents, Downloads\u2026): click its row, the unnamed cell listed\n just before the folder's text. Where: then names that folder.\n- Parent folders and Recent Places: click the Where: popup, then click the menu item.\n- A folder inside the file list: in column view the list exposes no rows at all. Switch the view\n button (column view) to List, then ax_action AXOpen on the folder's row \u2014 it answers AXError\n -25205 and opens the folder anyway; read Where: to confirm. The view choice is saved for every\n app's Save panel, so switch back to Columns before pressing Save.\n- Only a file name goes in Save As:. \u2318\u21E7G Go To Folder works only with the app frontmost.";
2
+ export declare function appNote(bundle: string | null | undefined): string | null;
@@ -0,0 +1,86 @@
1
+ const n={"com.apple.finder":`Finder, known quirks:
2
+ - RENAMING a file does not work with set_text. The name cell accepts AXSetValue and reads the new
3
+ name back, and the file keeps its old name \u2014 the cell commits on Enter and starts a fresh edit.
4
+ The route that works is: select the row, keys('Enter') to open the editor, type({text}) the new
5
+ name, keys('Enter') to commit. A field that offers AXConfirm says so in its set_text result; that
6
+ is the same warning.
7
+ - The rename editor is a transient untitled WINDOW while it is open, so an "opened a window" note
8
+ and a surfaces() entry that vanishes after Enter are both expected, not a problem.`,"com.apple.TextEdit":`TextEdit, known quirks:
9
+ - Every item of a context menu advertises AXCancel, and running it does NOTHING \u2014 the menu stays
10
+ up and the verdict reads frozen. Close a menu with keys('Escape'); pick an item with click.
11
+ - An Open or Save panel is not TextEdit: it is a remote view hosted by openAndSavePanelService.
12
+ keys() goes to that panel's own process, but a \u2318-chord there (\u2318\u21E7G Go To Folder) takes effect only
13
+ with the app frontmost. Drive it BY REF \u2014 its Cancel button, its name field and its format popup
14
+ all answer accessibility normally, in the background too.`,"com.apple.calculator":`Calculator, known quirks:
15
+ - Its toolbar buttons (Show Sidebar, Mode) advertise AXIncrement, AXDecrement and
16
+ AXCancel. None of them do anything \u2014 they are NSAccessibility defaults for the control class, not
17
+ capabilities a toolbar button has. Click them instead of reaching for ax_action.`,"com.apple.QuickTimePlayerX":`QuickTime Player, known quirks:
18
+ - Its playback controls exist only while the pointer is ON the window, and they leave the tree
19
+ about three seconds after the pointer stops (measured: 27 elements at 0-2s, 5 at 3s). A plain
20
+ observe() shows five window-chrome elements and no player at all. So hover({x, y}) over the video
21
+ and ACT IN THE SAME CALL \u2014 a ref minted in one call is dead in the next, and re-observing without
22
+ a hover will list those same five for ever, whatever the stale-ref advice says.
23
+ - The Timeline slider takes set_text and discards it (the value reads back unchanged), and AXDecrement
24
+ on it does nothing. Move the playhead with Rewind / Fast Forward \u2014 one click starts a CONTINUOUS 5x scan
25
+ that only Play/Pause stops \u2014 or drag the slider.`,"org.blenderfoundation.blender":`Blender, known quirks:
26
+ - Its shortcuts are routed by the region under the POINTER, not by the window's focus: keys sent
27
+ while the pointer sits outside the 3D viewport reach whatever area it is over instead. Put it
28
+ there first with hover({x, y}) off a screenshot, then send the key.
29
+ - Modifier CHORDS do not arrive. keys('shift+a') acted as plain 'a' (select all, measured) and
30
+ keys('alt+a') did nothing, while bare keys land normally ('a', Return, Escape). Reach for a
31
+ single-key route, and check the screenshot rather than trusting the chord.
32
+ - It has a scripting CLI of its own, which is the route for anything that is really a FILE or
33
+ SCENE operation rather than a look at the interface:
34
+ \`blender --background <file.blend> --python-expr '<python>'\` (verified: bpy.ops added an
35
+ object and printed the scene graph). Hand that path back to whoever asked instead of driving
36
+ pixels for it; the GUI is for what only the GUI shows.`,"com.google.Chrome":`Chrome, known quirks:
37
+ - ax_action('menu') on the ADDRESS BAR answers AXError -25204 and then opens the menu anyway,
38
+ sometimes about 800 ms later, sometimes not at all. Treat the error as a report about the call
39
+ and not a verdict on the effect: observe before deciding it failed, and give it a beat.`,"com.microsoft.Excel":`Excel, known quirks:
40
+ - THE SHEET IS NOT IN THE TREE until a real mouse click lands in a cell. Until then the window is
41
+ ribbon only, with no cell at all. One click({x, y}) inside the grid \u2014 coordinates read off
42
+ observe({screenshot:true}) \u2014 publishes the whole used range, and it stays for the rest of the
43
+ session. Navigating with the name box does NOT do it: set_text is AXSetValue, not a click.
44
+ - After it: a filled cell is a textbox named by its address whose value is its content, an empty one
45
+ a cell named by its address, and text() renders the sheet row by row. Read the table from there
46
+ rather than one cell at a time.
47
+ - Before it, the only read is one cell at a time: set_text the name box to an address, Enter, then
48
+ read the FORMULA BAR ELEMENT'S NAME \u2014 "Formula Bar. B,4 =SUM(B2:B3)" carries the address and the
49
+ content together. Its own value is always empty and its state says empty; believe neither.`,"com.microsoft.Word":`Word, known quirks:
50
+ - set_text on the document body answers success and writes NOTHING (the read-back is empty). Type
51
+ into it instead. Word also autocorrects what arrives, so the text you read back may differ from
52
+ the text you sent \u2014 compare meaning, not bytes.
53
+ - The ribbon's Bold checkbox never changes state, whether or not the format applied. Decide by
54
+ the UNDO menu item, whose name becomes "Undo Bold" when it did.`,"com.microsoft.Powerpoint":`PowerPoint, known quirks:
55
+ - The slide canvas is not in the tree, and neither is the outline view \u2014 the window is ribbon plus
56
+ one thumbnail cell. Typing reaches the focused placeholder anyway, but nothing in the tree will
57
+ confirm it: verify with a screenshot.`,"com.microsoft.VSCode":`Visual Studio Code, known quirks:
58
+ - ITS WINDOW CAN READ AS EMPTY. Measured cold: three nameless buttons, no web area, text() empty \u2014
59
+ the editor had not published its content to accessibility, and the accessibility switch this
60
+ platform sets answers success without changing that for far longer than one read waits. It DID
61
+ come alive later in the same session (3 elements \u2192 96) and stayed alive afterwards, so reading
62
+ again is worth one call before giving up.
63
+ - While it reads as empty, two routes still work and neither needs the tree: its MENU carries the
64
+ whole command set (209 commands runnable with the app in the background, the Command Palette
65
+ among them), and a control you can see is reachable by position \u2014 observe({screenshot: true}),
66
+ then click({x, y}).`,"com.openai.codex":`ChatGPT, known quirks:
67
+ - The composer's VALUE is its own placeholder when it is empty: it reads filled:Do anything with
68
+ nothing typed in it, because Chromium puts placeholder text in the value and offers no separate
69
+ placeholder attribute. A web field whose value is exactly its own label is probably empty \u2014 do
70
+ not treat it as a draft to preserve.
71
+ - The header toggles never change state. Toggle side panel, Toggle bottom panel and Toggle summary
72
+ read unchecked whether their panel is open or shut. Decide by what the observation CONTAINS \u2014 an
73
+ open side panel brings a tablist (Side chat / Browser / Terminal) and a second composer with it \u2014
74
+ never by the toggle, and never report "it was already open" from reading one. Controls inside the
75
+ panel do report their own state.
76
+ - Settings (cmd+,) replaces the whole window rather than opening one: the composer, the header and
77
+ every ref you are holding go away, while the window keeps the conversation's title. Escape does
78
+ NOT leave it. Click the Back to app link.`},s=`Save panel, known quirks:
79
+ - A folder in the sidebar (Desktop, Documents, Downloads\u2026): click its row, the unnamed cell listed
80
+ just before the folder's text. Where: then names that folder.
81
+ - Parent folders and Recent Places: click the Where: popup, then click the menu item.
82
+ - A folder inside the file list: in column view the list exposes no rows at all. Switch the view
83
+ button (column view) to List, then ax_action AXOpen on the folder's row \u2014 it answers AXError
84
+ -25205 and opens the folder anyway; read Where: to confirm. The view choice is saved for every
85
+ app's Save panel, so switch back to Columns before pressing Save.
86
+ - Only a file name goes in Save As:. \u2318\u21E7G Go To Folder works only with the app frontmost.`;function i(e){if(!e)return null;const t=e.trim().toLowerCase();for(const[o,a]of Object.entries(n))if(o.toLowerCase()===t)return a;return null}export{s as SAVE_PANEL_NOTE,i as appNote};
@@ -0,0 +1,10 @@
1
+ export declare class MacosApprovals {
2
+ readonly file: string | null;
3
+ constructor(env: NodeJS.ProcessEnv);
4
+ has(bundle: string): boolean;
5
+ list(): string[];
6
+ add(bundle: string): void;
7
+ remove(bundle: string): void;
8
+ private read;
9
+ private write;
10
+ }
@@ -0,0 +1,2 @@
1
+ import{mkdirSync as t,readFileSync as s,writeFileSync as n}from"node:fs";import{dirname as o,join as a}from"node:path";import{computerUseHome as f}from"../home.js";class h{file;constructor(r){const i=r.COMPUTER_USE_MACOS_APPROVALS;this.file=i===void 0?a(f(r),"macos-approvals.json"):i.trim()||null}has(r){return this.read().includes(r)}list(){return this.read()}add(r){const i=this.read();i.includes(r)||this.write([...i,r])}remove(r){const i=this.read();i.includes(r)&&this.write(i.filter(e=>e!==r))}read(){if(!this.file)return[];try{const r=JSON.parse(s(this.file,"utf8")).approvedBundleIdentifiers;return Array.isArray(r)?r.filter(i=>typeof i=="string"):[]}catch{return[]}}write(r){if(this.file)try{t(o(this.file),{recursive:!0}),n(this.file,JSON.stringify({approvedBundleIdentifiers:r},null,2)+`
2
+ `)}catch{}}}export{h as MacosApprovals};
@@ -0,0 +1,53 @@
1
+ import { spawn as nodeSpawn } from "node:child_process";
2
+ export { AxRequestError } from "./ax-errors.ts";
3
+ export interface AxTransport {
4
+ nameKeys?: (msg: string) => string;
5
+ onReset?: () => void;
6
+ request(op: string, params?: Record<string, unknown>): Promise<unknown>;
7
+ close(): Promise<void>;
8
+ }
9
+ export type SpawnFn = typeof nodeSpawn;
10
+ export interface AxHelperOptions {
11
+ captureLocal?: boolean;
12
+ onStart?: (pid: number) => Promise<void>;
13
+ bin?: string;
14
+ env?: NodeJS.ProcessEnv;
15
+ spawn?: SpawnFn;
16
+ timeoutMs?: number;
17
+ onLog?: (line: string) => void;
18
+ onEvent?: (event: Record<string, unknown>) => void;
19
+ }
20
+ export declare class AxHelperProcess implements AxTransport {
21
+ private child;
22
+ private starting;
23
+ private closing;
24
+ private generation;
25
+ private readonly pending;
26
+ private nextId;
27
+ private stderrTail;
28
+ private gone;
29
+ private readonly env;
30
+ private readonly spawnFn;
31
+ private readonly timeoutMs;
32
+ private readonly binOverride;
33
+ private readonly onLog;
34
+ private readonly onEvent;
35
+ private readonly onStart;
36
+ private readonly capture;
37
+ private stderrPartial;
38
+ constructor(opts?: AxHelperOptions);
39
+ request(op: string, params?: Record<string, unknown>): Promise<unknown>;
40
+ close(): Promise<void>;
41
+ private start;
42
+ nameKeys: (msg: string) => string;
43
+ onReset?: () => void;
44
+ private onLine;
45
+ private fail;
46
+ }
47
+ export interface AxHelperInfo {
48
+ bin: string;
49
+ origin: "env" | "bundle" | "package" | "sources";
50
+ sourceHash: string | null;
51
+ binHash: string | null;
52
+ }
53
+ export declare function resolveAxHelperInfo(env: NodeJS.ProcessEnv): Promise<AxHelperInfo>;
@@ -0,0 +1,3 @@
1
+ import{spawn as y,execFile as T}from"node:child_process";import{createHash as P}from"node:crypto";import{existsSync as p,mkdirSync as $,readdirSync as m,readFileSync as g,rmSync as L,statSync as w}from"node:fs";import{join as d}from"node:path";import{fileURLToPath as x}from"node:url";import{createInterface as M}from"node:readline";import{CaptureClient as A}from"./capture-client.js";import{AxRequestError as h}from"./ax-errors.js";import{computerUseHome as O}from"../home.js";import{platformPackageHelper as _}from"../platform-package.js";import{AxRequestError as z}from"./ax-errors.js";const R=2e3;class G{child=null;starting=null;closing=null;generation=0;pending=new Map;nextId=1;stderrTail="";gone=null;env;spawnFn;timeoutMs;binOverride;onLog;onEvent;onStart;capture;stderrPartial="";constructor(t={}){this.env=t.env??process.env,this.capture=t.captureLocal?null:A.fromEnv(this.env),this.spawnFn=t.spawn??y,this.timeoutMs=t.timeoutMs??15e3,this.binOverride=t.bin,this.onLog=t.onLog,this.onEvent=t.onEvent,this.onStart=t.onStart}async request(t,e={}){if(this.capture&&(t==="shot"||t==="shotscoped")){const o=this.generation,a=await this.request("captureplan",{...e,scoped:t==="shotscoped"});if(o!==this.generation)throw new h("helper_gone","The capture owner changed during preparation.");const l=await this.capture.request(t,a);if(o!==this.generation)throw new h("helper_gone","The capture owner closed before its screenshot returned.");return l}const i=this.generation;if(await this.start(),i!==this.generation)throw this.gone??new h("helper_gone","ax helper changed before the request was sent");if(this.gone)throw this.gone;const c=this.child;if(!c)throw new h("helper_gone","ax helper is not running");const r=this.nextId++,s=`${JSON.stringify({id:r,op:t,...e})}
2
+ `;return new Promise((o,a)=>{const l=setTimeout(()=>{this.pending.delete(r),this.close().then(()=>a(new h("ax_error",`ax helper: '${t}' did not answer within ${this.timeoutMs} ms; helper stopped`)))},this.timeoutMs);this.pending.set(r,{resolve:o,reject:a,timer:l});try{c.stdin.write(s)}catch(u){clearTimeout(l),this.pending.delete(r),a(u)}}).catch(async o=>{throw await this.closing,o})}close(){if(this.capture?.abortRequests(),this.closing)return this.closing;const t=this.child;if(this.fail("ax helper closed; any in-flight action's outcome is unknown \u2014 observe before acting again"),!t||t.exitCode!==null||t.signalCode!==null)return Promise.resolve();const e=new Promise(c=>{const r=setTimeout(()=>{t.kill("SIGKILL")},2e3);t.once("exit",()=>{clearTimeout(r),c()}),t.stdin.end()});this.closing=e;const i=()=>{this.closing===e&&(this.closing=null)};return e.then(i,i),e}start(){if(this.starting)return this.starting;if(this.child)return Promise.resolve();const t=this.generation,e=(async()=>{await this.closing;const c=this.binOverride??await E(this.env);if(t!==this.generation)throw new h("helper_gone","ax helper startup was cancelled by close");const r=this.spawnFn(c,[],{stdio:["pipe","pipe","pipe"],env:this.env});this.gone=null,this.stderrTail="",this.stderrPartial="",this.child=r,r.stdin.on("error",()=>{}),r.stderr.on("data",s=>{if(this.child!==r)return;const o=s.toString();if(this.stderrTail=`${this.stderrTail}${o}`.slice(-R),!this.onLog)return;const a=`${this.stderrPartial}${o}`.split(`
3
+ `);this.stderrPartial=a.pop()??"";for(const l of a){const u=l.replace(/^computer-use-ax-helper:\s*/,"").trim();u&&this.onLog(u)}}),M({input:r.stdout}).on("line",s=>{this.child===r&&this.onLine(s)}),r.on("error",s=>{this.child===r&&this.fail(`ax helper could not start: ${s.message}`)}),r.on("exit",(s,o)=>{this.child===r&&this.fail(`ax helper exited (${s??o??"?"})${this.stderrTail?`: ${this.stderrTail.trim()}`:""}`)});try{r.pid&&this.onStart&&await this.onStart(r.pid)}catch(s){throw await this.close(),s}})();this.starting=e;const i=()=>{this.starting===e&&(this.starting=null)};return e.then(i,i),e}nameKeys=t=>t;onReset;onLine(t){let e;try{e=JSON.parse(t)}catch{return}if(e.event){this.onEvent?.(e);return}const i=typeof e.id=="number"?this.pending.get(e.id):void 0;if(i)if(this.pending.delete(e.id),clearTimeout(i.timer),e.ok)i.resolve(e.result??{});else{const c=e.error?.message??"ax helper error";i.reject(new h(e.error?.code??"ax_error",this.nameKeys(c),e.error?.ax,e.error?.postedCount,e.error?.requestedCount,e.error?.capture))}}fail(t){this.generation++,this.gone=new h("helper_gone",t),this.child=null,this.starting=null;for(const[e,i]of this.pending)clearTimeout(i.timer),i.reject(this.gone),this.pending.delete(e);this.onReset?.()}}function v(){const n=x(new URL("./ax/",import.meta.url));return p(n)?n:null}const f="computer-use-ax-helper";function S(){const n=x(new URL(`./${f}`,import.meta.url));return p(n)?n:null}function b(){const n=v();if(!n)return null;const t=P("sha256");for(const e of m(n).filter(i=>i.endsWith(".swift")).sort())t.update(g(d(n,e)));return t.digest("hex").slice(0,16)}async function J(n){const t=await E(n),e=`${t}.sha`;return{bin:t,origin:n.COMPUTER_USE_MACOS_AX_BIN?.trim()?"env":S()?"bundle":_(f)?"package":"sources",sourceHash:b(),binHash:p(e)?g(e,"utf8").trim():null}}async function E(n){const t=n.COMPUTER_USE_MACOS_AX_BIN?.trim();if(t){if(!p(t))throw new Error(`COMPUTER_USE_MACOS_AX_BIN points at ${t}, which does not exist`);return t}if(process.platform!=="darwin")throw new h("unsupported","the macos driver needs macOS");const e=S()??_(f);if(e)return e;const i=v();if(!i)throw new Error(`macos ax helper: no prebuilt binary (COMPUTER_USE_MACOS_AX_BIN, \`${f}\` beside the bundle, or the @mirasim/computer-use-${process.platform}-${process.arch} package) and no Swift sources beside the bundle \u2014 a packaged build must ship the helper`);const c=m(i).filter(s=>s.endsWith(".swift")).sort().map(s=>d(i,s)),r=d(O(),"macos-ax",b(),"ax-helper");return p(r)||($(d(r,".."),{recursive:!0}),await new Promise((s,o)=>{T("swiftc",["-O",...c,"-o",r],{timeout:18e4},(a,l,u)=>{a?o(new Error(`macos ax helper: swiftc failed (is the Xcode command line toolchain installed?): ${String(u||a.message).slice(0,600)}`)):s()})}),U(d(r,"..",".."))),r}const C=6;function U(n){try{const t=m(n).map(e=>({name:e,path:d(n,e)})).filter(e=>w(e.path).isDirectory()).map(e=>({...e,at:w(e.path).mtimeMs})).sort((e,i)=>i.at-e.at);for(const e of t.slice(C))L(e.path,{recursive:!0,force:!0})}catch{}}export{G as AxHelperProcess,z as AxRequestError,J as resolveAxHelperInfo};
@@ -0,0 +1,16 @@
1
+ export type AxErrorCode = "bad_request" | "not_trusted" | "not_granted_screen" | "no_app" | "no_window" | "no_element" | "no_scroll_area" | "stale_key" | "ax_error" | "unsupported" | "helper_gone" | "capture_timeout" | "capture_service_error" | "background_key_interrupted" | "background_key_unsupported";
2
+ export interface CaptureFailure {
3
+ stage: string;
4
+ domain: string;
5
+ code: number;
6
+ helperPid: number;
7
+ screenRecording: boolean;
8
+ }
9
+ export declare class AxRequestError extends Error {
10
+ readonly code: AxErrorCode;
11
+ readonly ax?: number | undefined;
12
+ readonly postedCount?: number | undefined;
13
+ readonly requestedCount?: number | undefined;
14
+ readonly capture?: CaptureFailure | undefined;
15
+ constructor(code: AxErrorCode, message: string, ax?: number | undefined, postedCount?: number | undefined, requestedCount?: number | undefined, capture?: CaptureFailure | undefined);
16
+ }
@@ -0,0 +1 @@
1
+ class d extends Error{code;ax;postedCount;requestedCount;capture;constructor(t,e,s,r,o,u){super(e),this.code=t,this.ax=s,this.postedCount=r,this.requestedCount=o,this.capture=u}}export{d as AxRequestError};
@@ -0,0 +1,53 @@
1
+ import type { AxWindow } from './elements.ts';
2
+ export declare const SHOT_MAX_LONG_SIDE = 1568;
3
+ export declare const TREE_MAX_VISITED = 8000;
4
+ export declare const TREE_WALK_DEADLINE_MS = 1500;
5
+ export declare const TREE_MAX_ELEMENTS = 300;
6
+ export declare const TREE_MAX_TEXT = 2000;
7
+ export declare const TREE_MAX_DEPTH = 64;
8
+ export declare const TEXT_PREVIEW = 600;
9
+ export interface AxApp {
10
+ bundle: string;
11
+ name: string;
12
+ pid: number;
13
+ active: boolean;
14
+ hidden: boolean;
15
+ background?: boolean;
16
+ webShell?: boolean;
17
+ }
18
+ export interface AxLaunch {
19
+ app: AxApp;
20
+ ready: boolean;
21
+ started?: boolean;
22
+ windows?: number;
23
+ panel?: boolean;
24
+ }
25
+ export interface AxWindowRow extends AxWindow {
26
+ main: boolean;
27
+ focused: boolean;
28
+ }
29
+ export interface AxShot {
30
+ png: string;
31
+ id: number;
32
+ x: number;
33
+ y: number;
34
+ w: number;
35
+ h: number;
36
+ scale: number;
37
+ }
38
+ export interface AxScopedShot extends AxShot {
39
+ region: {
40
+ x: number;
41
+ y: number;
42
+ w: number;
43
+ h: number;
44
+ };
45
+ pixelWidth: number;
46
+ pixelHeight: number;
47
+ scaleY: number;
48
+ trimmed: boolean;
49
+ }
50
+ export declare const pinnable: (id: number | undefined) => number | null;
51
+ export declare const normName: (s: string) => string;
52
+ export declare const unreadable: (e: unknown) => unknown;
53
+ export declare const PANEL_SERVICE_BUNDLE = "com.apple.appkit.xpc.openAndSavePanelService";
@@ -0,0 +1 @@
1
+ import{SurfaceUnreadableError as e}from"../types.js";import{AxRequestError as r}from"./ax-client.js";const n=1568,p=8e3,c=1500,_=300,s=2e3,a=64,x=600,T=o=>typeof o=="number"&&o>=0?o:null,m=o=>o.trim().toLowerCase().replace(/\s+/g," "),A=o=>o instanceof r&&o.code==="no_window"?new e(o.message):o,S="com.apple.appkit.xpc.openAndSavePanelService";export{S as PANEL_SERVICE_BUNDLE,n as SHOT_MAX_LONG_SIDE,x as TEXT_PREVIEW,a as TREE_MAX_DEPTH,_ as TREE_MAX_ELEMENTS,s as TREE_MAX_TEXT,p as TREE_MAX_VISITED,c as TREE_WALK_DEADLINE_MS,m as normName,T as pinnable,A as unreadable};
@@ -0,0 +1,11 @@
1
+ export declare class CaptureClient {
2
+ private readonly socketPath;
3
+ private readonly token;
4
+ private readonly requests;
5
+ abortRequests(): void;
6
+ constructor(socketPath: string, token: string);
7
+ static fromEnv(env: NodeJS.ProcessEnv): CaptureClient | null;
8
+ private open;
9
+ request(op: "shot" | "shotscoped", params: Record<string, unknown>): Promise<unknown>;
10
+ preview(pid: number, window: number, event: (value: Record<string, unknown>) => void, signal: AbortSignal): Promise<void>;
11
+ }
@@ -0,0 +1,2 @@
1
+ import w from"node:http";import{StringDecoder as l}from"node:string_decoder";import{AxRequestError as h}from"./ax-errors.js";const f=32*1024*1024;class p{socketPath;token;requests=new Set;abortRequests(){for(const o of this.requests)o.destroy(new Error("This capture client closed."))}constructor(o,n){this.socketPath=o,this.token=n}static fromEnv(o){const n=o.COMPUTER_USE_MACOS_CAPTURE_SOCKET,r=o.COMPUTER_USE_MACOS_CAPTURE_TOKEN;if(!n&&!r)return null;if(!n||!r)throw new Error("The native capture connection is incomplete; restart this host.");return new p(n,r)}async open(o,n,r){const i=JSON.stringify(n),c=Date.now()+5e3;for(;;)try{return await new Promise((t,s)=>{const e=w.request({socketPath:this.socketPath,path:o,method:"POST",signal:r,headers:{authorization:`Bearer ${this.token}`,"content-type":"application/json","content-length":Buffer.byteLength(i)}},a=>{e.setTimeout(0),t(a)});this.requests.add(e),e.once("close",()=>this.requests.delete(e)),e.setTimeout(3e4,()=>e.destroy(new Error("Native capture did not answer within 30 seconds."))),e.on("error",s),e.end(i)})}catch(t){if(r?.aborted)throw t;const s=t.code;if(!["ENOENT","ECONNREFUSED"].includes(s??"")||Date.now()>=c)throw new h("capture_service_error","The host's native capture service is unavailable. No alternate capture process was started.");await new Promise(e=>setTimeout(e,100))}}async request(o,n){const r=await this.open("/capture",{op:o,params:n});let i=0;const c=[];r.setTimeout(3e4,()=>r.destroy(new Error("Native capture response timed out.")));for await(const s of r){const e=Buffer.from(s);if(i+=e.length,i>f)throw r.destroy(),new Error("Native capture response exceeded its size limit.");c.push(e)}const t=JSON.parse(Buffer.concat(c).toString());if(!t.ok)throw new h(t.error?.code??"capture_service_error",t.error?.message??"Native capture failed.",void 0,void 0,void 0,t.error?.capture);return t.result}async preview(o,n,r,i){const c=await this.open("/preview",{pid:o,window:n},i),t=()=>c.destroy();i.addEventListener("abort",t,{once:!0}),i.aborted&&t();let s="";const e=new l("utf8");try{for await(const a of c){if(s+=e.write(Buffer.from(a)),s.length>f)throw new Error("Native preview event exceeded its size limit.");let u;for(;(u=s.indexOf(`
2
+ `))!==-1;){const d=s.slice(0,u);s=s.slice(u+1),d&&r(JSON.parse(d))}}if(!i.aborted)throw new Error("Native capture connection closed; reopen the preview.")}finally{i.removeEventListener("abort",t),c.destroy()}}}export{p as CaptureClient};
@@ -0,0 +1,4 @@
1
+ import type { ActResult } from "../types.ts";
2
+ import type { ElementActs } from "./act-element.ts";
3
+ import { type MouseHost } from "./press-rungs.ts";
4
+ export declare function clickVerb(host: MouseHost, acts: ElementActs, a: Record<string, any>, times: number): Promise<ActResult>;
@@ -0,0 +1 @@
1
+ import{AxRequestError as $}from"./ax-client.js";import{roleOf as X}from"./element-lines.js";import{centre as W,mouse as _,NO_MOUSE as F,outOfReach as I}from"./mouse.js";import{activateByAncestor as R,activateByKey as U,keyRoute as E,changedSince as O,surfaceGone as A,SURFACE_GONE_MSG as v,evidence as S,PRESS_SETTLE_MS as j}from"./press-rungs.js";const B=2e3,D=1500,G=/\b(send|submit|delete|remove|pay|purchase|buy|confirm|post|publish|order|checkout)\b|发送|提交|删除|移除|支付|购买|确认|发布|下单/i;async function q(e,u,n){const p=Date.now()+D;for(;;){let m;try{m=(await e.call("humanidle",{})).seconds}catch(a){if(a instanceof $)return null;throw a}if(m*1e3>=B)return null;if(Date.now()>=p)return{ok:!1,note:`${n}, so the mouse was next \u2014 but it was NOT clicked: the user touched the keyboard or pointer ${m.toFixed(1)} s ago, and a mouse click would raise ${e.appName()} and pull their cursor off whatever they are doing. No mouse event was posted; no visible change was detected. Wait and click again \u2014 it goes through once they stop. If it cannot wait for them, activate first, which takes the front window deliberately`};await new Promise(a=>setTimeout(a,150))}}function K(e,u,n){return`${n}, so the mouse was next \u2014 but it was NOT clicked: ${u} reads as disabled in ${e.appName()}'s own accessibility tree, which is why the press was ignored, and a synthesised click would raise the app and take the user's front window to press something that is still not listening. No mouse event was posted; no visible change was detected. Whatever gates the control \u2014 a selection, a field, a mode \u2014 has to change first; then click again. If the tree is wrong about this control, click({x, y}) reaches the mouse deliberately.`}function L(e,u,n){return`${u}${n?", and focusing it and sending one key changed nothing either":""} \u2014 so the mouse was next, but this call is background-only: it was NOT clicked and no mouse event was posted. A real click would raise ${e.appName()} and use the user's pointer. Inspect the result first; to use the mouse, explain that effect, obtain the user's permission, and click again with interaction:'desktop'.`}async function J(e,u,n,p){const m=n.button==="right"||n.button==="middle"?n.button:"left",a=typeof n.x=="number"&&typeof n.y=="number",r=a?null:u.resolve(n.ref,n.name);if(r&&!("key"in r))return r;const i=a?"the point":`${r.role} "${r.name}"`,b=()=>a?e.toScreen(n.x,n.y):(()=>{const t=e.rectOf(String(n.ref));return t?W(t):null})();let H=!1,N=!1;const T=async t=>(r&&E(r.role)&&(N=!0),U(e,u,n.ref,n.name,t)),y=async(t,s,l)=>{const w=await P(s,l);return w?(H=!0,w):_(e,t,"left",1,i,s,l)},P=async(t,s)=>e.pointerAllowed()?s&&e.offWindow(String(n.ref))?I(i,n.ref,"click"):r&&!r.enabled?{ok:!1,note:K(e,i,t)}:q(e,i,t):{ok:!1,note:L(e,t,N)};if(m!=="left"||p>1){if(!a&&e.offWindow(String(n.ref)))return I(i,n.ref,`${m}-click`);const t=b();return t?_(e,t,m,p,i):{ok:!1,note:`${i} has no frame on this walk, so there is nowhere to ${m}-click \u2014 observe and act on a listed control`}}const g=e.memory.takeRedo(e.bundle(),i),M=e.memory.count(e.bundle());if(g||e.memory.ignores(e.bundle())){if(r&&(g||e.memory.keyActivates(e.bundle())||!e.pointerAllowed())){let s=null;try{s=await S(e)}catch{}const l=await T(s);if(l)return l}const t=b();return t?y(t,g?`the last click on ${i} was an AXPress the app accepted and ignored, and this second click is the decision to redo it with the mouse`:`${e.appName()} has ignored AXPress ${M} times this session, so the mouse goes first`,!a):{ok:!1,note:`${i} has no frame on this walk, so there is nowhere to click \u2014 observe and act on a listed control`}}let d=null;try{d=await S(e)}catch{}let o;if(a){const t=e.toScreen(n.x,n.y);let s="";const l=await e.call("at",{pid:e.pid(),...t}).catch(c=>c instanceof $&&(c.code==="no_element"||c.code==="ax_error")?(s=c.code==="no_element"?"nothing pressable under the point":`the tree could not say what is under the point (${c.message})`,null):Promise.reject(c));if(!l)return y(t,s||"nothing pressable under the point",!1);const w=`${X(l.element)} "${l.element.title||l.element.desc}"`;let k="";if(await e.call("press",{key:l.element.key}).catch(c=>{if(c instanceof $&&(c.code==="no_element"||c.code==="ax_error")){k=`the ${w} under the point does not take a press (${c.message})`;return}return Promise.reject(c)}),k)return n.retry===!0?y(t,k,!1):{ok:!1,mayHaveActed:!0,note:`${k}. The press result is uncertain; no mouse retry was sent. Inspect the result before retrying.`};o={ok:!0,note:`pressed ${w} under the point`}}else{if(r&&!r.actions.length){const t=await R(e,u,n.ref,n.name,d);if(t)return t}if(r&&!r.actions.includes("AXPress")&&r.actions.includes("AXOpen")){const t=await R(e,u,n.ref,n.name,d);if(t)return t}if(o=await u.press(n.ref,n.name,1),!o.ok&&!o.mayHaveActed||o.ok&&o.note)return o}let f;if(o.ok){if(d===null)return o;const t=await O(e,d);if(t!==null)return e.memory.noteHonoured(e.bundle()),A(t)?{...o,note:`${o.note??"pressed"} \u2014 ${v}`}:o;if(e.memory.noteIgnored(e.bundle()),f=`AXPress on ${i} was accepted but nothing in the window changed within ${j} ms`,n.retry!==!0||r&&G.test(r.name)){e.memory.armRedo(e.bundle(),i);const s=r&&E(r.role)?`focusing it and sending one key (${e.appName()} stays where it is), then a real mouse click`:"a real mouse click";return{ok:!0,mayHaveActed:!0,note:`${f}. It was not repeated: pressing ${i} twice could act twice. What is left is ${s}${e.pointerAllowed()?"":" (not in a background-only call)"}. Inspect the actual result; only after ruling out a completed or pending action, click it again to try that. For an action known to be harmless to repeat, click(t, {retry:true}) permits it in the same call. The mouse still requires desktop permission.`}}}else{f=o.note?.split(/\. /)[0]||`the app refused AXPress on ${i}`;const t=d===null?null:await O(e,d);if(t!==null)return e.memory.noteHonoured(e.bundle()),{ok:!0,note:`${f} \u2014 but ${A(t)?v:"the window changed"}, so it acted: the error was about the call, not about the effect. It was not redone with the mouse, so nothing here brought ${e.appName()} to the front`};if(n.retry!==!0)return{ok:!1,mayHaveActed:!0,note:`${f}. The result is uncertain; no keyboard or mouse retry was sent. Inspect the result before retrying. click(t, {retry:true}) permits another dispatch only when repeating the action is known to be harmless.`}}if(r){const t=await T(d);if(t)return t}const x=b();if(!x)return{...o,note:`${o.note??f} \u2014 and it has no frame on this walk for a mouse click to fall back to`};const h=await y(x,f,!a);if(h.journal===F)return{...o,mayHaveActed:!0,note:`${f}; ${h.note}`};if(!h.ok&&H&&d!==null){const t=await S(e).catch(()=>null);if(t!==null&&t!==d)return e.memory.noteHonoured(e.bundle()),{ok:!0,note:`${f} \u2014 but the window HAD changed by the time the mouse was refused (${A(t)?v:"a late redraw or a new window"}), so the press landed after the settle; the mouse was not used`}}return!h.ok&&o.ok&&e.memory.hasHonoured(e.bundle())?{ok:!0,mayHaveActed:!0,note:`${f}, and the mouse could not confirm it \u2014 ${h.note}. This app HAS honoured AXPress in this session, so the likeliest reading is that the press landed and had nothing to change. Observe before deciding it failed, and click again if the screen says otherwise`}:h.ok?h:{...h,mayHaveActed:!0}}export{J as clickVerb};
@@ -0,0 +1,59 @@
1
+ import { ComputerUseDriver } from "../driver.ts";
2
+ import { type AxTransport } from "./ax-client.ts";
3
+ import type { UserConsent } from "../types.ts";
4
+ import type { MacosApprovals } from "./approvals.ts";
5
+ import type { AppNameResolver } from "./app-names.ts";
6
+ import { type AxApp, type AxWindowRow } from "./ax-shapes.ts";
7
+ export declare abstract class MacosDriverApps extends ComputerUseDriver {
8
+ protected dispatchedActions: number;
9
+ protected abstract readonly ax: AxTransport;
10
+ protected abstract readonly fallback: Set<string> | null;
11
+ protected abstract readonly hostApps: ReadonlySet<string>;
12
+ protected abstract readonly consent: UserConsent | null;
13
+ protected readonly approved: Set<string>;
14
+ private readonly approvedThisCall;
15
+ protected abstract readonly stored: MacosApprovals;
16
+ protected abstract readonly appsNamed: AppNameResolver;
17
+ endCall(): void;
18
+ private readonly launchedPids;
19
+ protected startedHere(pid: number): boolean;
20
+ protected noteStarted(pid: number): void;
21
+ protected abstract readonly wantBundle: string | undefined;
22
+ protected abstract forgetApp(): void;
23
+ protected abstract addNote(note: string): void;
24
+ protected app: AxApp | null;
25
+ protected windowId: number | null;
26
+ protected granted: {
27
+ accessibility: boolean;
28
+ screenRecording: boolean;
29
+ } | null;
30
+ protected accessRefused: boolean;
31
+ protected notAllowed(bundle: string): string;
32
+ protected get asking(): boolean;
33
+ protected cleared(bundle: string): boolean;
34
+ protected authorize(bundle: string, name: string | (() => Promise<string>)): Promise<void>;
35
+ protected revoke(bundles: string[]): void;
36
+ protected displayName(bundle: string): Promise<string>;
37
+ protected call<T>(op: string, params?: Record<string, unknown>): Promise<T>;
38
+ protected refreshGrants(): Promise<void>;
39
+ targetsNote(): string | null;
40
+ protected apps(): Promise<AxApp[]>;
41
+ protected lookup(by: {
42
+ bundles?: string[];
43
+ pids?: number[];
44
+ }): Promise<AxApp[]>;
45
+ protected scopedApps(): Promise<AxApp[]>;
46
+ protected installed(bundles: string[]): Promise<Array<{
47
+ bundle: string;
48
+ name: string;
49
+ }>>;
50
+ protected windows(pid: number): Promise<{
51
+ rows: AxWindowRow[];
52
+ locked: boolean;
53
+ }>;
54
+ protected ensure(): Promise<{
55
+ pid: number;
56
+ window: number | undefined;
57
+ }>;
58
+ private launchNamed;
59
+ }
@@ -0,0 +1,2 @@
1
+ import{ComputerUseDriver as l}from"../driver.js";import{SurfaceGoneError as o,SurfaceUnreadableError as c}from"../types.js";import{AxRequestError as n}from"./ax-client.js";import{DESKTOP_INPUT_OPS as u,DesktopInteractionRequired as w,clipboardChord as f}from"./interaction-policy.js";import{ACT_OPS as h,NO_ACCESSIBILITY_ACT as m,NO_SCREEN_RECORDING as g,grantRoute as p,noAccessibility as y}from"./permissions.js";import{approvalsAddCommand as k}from"../cli-command.js";import{NAME_AN_APP as A,appExitedNote as d,backgroundOnlyNote as b,consentQuestion as E,declinedNote as N,launchedNote as v,notAllowedNote as S,noWindowYetNote as R,ownAppNote as _,panelOnLaunchNote as C}from"./narrate.js";import"./ax-shapes.js";const I=400;function T(r){try{return process.kill(r,0),!0}catch(t){return t.code==="EPERM"}}class q extends l{dispatchedActions=0;approved=new Set;approvedThisCall=new Set;endCall(){this.approvedThisCall.clear()}launchedPids=new Set;startedHere(t){return this.launchedPids.has(t)}noteStarted(t){this.launchedPids.add(t)}app=null;windowId=null;granted=null;accessRefused=!1;notAllowed(t){return S(t,this.fallback)}get asking(){return this.consent?.available()===!0}cleared(t){return this.hostApps.has(t)?!1:this.approved.has(t)||this.approvedThisCall.has(t)||this.fallback?.has(t)?!0:this.asking?this.stored.has(t):this.fallback===null}async authorize(t,e){if(this.hostApps.has(t))throw new Error(`mirasim-cu: ${_(t)}`);if(this.cleared(t))return;if(!this.asking)throw this.permissionRefusal=`mirasim-cu: ${this.notAllowed(t)}`,new Error(this.permissionRefusal);const s=typeof e=="string"?e:await e(),i=Date.now();let a;try{a=await this.consent.ask(E(s,t),{"mirasim-computer-use/macosApp":{bundle:t,name:s,...this.consentPurpose?{purpose:this.consentPurpose}:{}},persist:["session","always"]})}finally{this.waitedOnUserMs+=Date.now()-i}if(!a.allowed)throw this.permissionRefusal=`mirasim-cu: ${N(s,t,a.reason,this.stored.file!==null?k(t):void 0)}`,new Error(this.permissionRefusal);if(!a.persist){this.approvedThisCall.add(t);return}this.approved.add(t),a.persist==="always"&&this.stored.add(t)}revoke(t){for(const e of t)this.approved.delete(e),this.approvedThisCall.delete(e),this.stored.remove(e)}async displayName(t){const e=(await this.lookup({bundles:[t]}))[0];return e?e.name:(await this.installed([t]))[0]?.name??t}async call(t,e={}){if(this.interactionMode==="background"&&(u.has(t)||["key","backgroundkey"].includes(t)&&f(String(e.chord??""))))throw new w(t);try{return h.has(t)&&this.dispatchedActions++,await this.ax.request(t,e)}catch(s){if(s instanceof n&&s.code==="not_trusted")throw this.accessRefused=!0,new c(h.has(t)?m:y(this.granted?.screenRecording===!1));if(s instanceof n&&s.code==="not_granted_screen")throw new c(g);if(s instanceof n&&s.code==="no_app"){const i=this.app;throw this.app=null,this.windowId=null,new o(i?d(i.name,t):s.message)}if(s instanceof n&&s.code==="ax_error"&&this.app&&/did not answer Accessibility/.test(s.message)&&(await new Promise(i=>setTimeout(i,I)),!T(this.app.pid))){const i=this.app;throw this.app=null,this.windowId=null,new o(d(i.name,t))}throw s}}async refreshGrants(){if(!(this.granted?.accessibility&&this.granted.screenRecording))try{const t=await this.call("capabilities");this.granted={accessibility:t.accessibility===!0,screenRecording:t.screenRecording===!0}}catch{}}targetsNote(){if(!this.granted)return null;const t=[];return this.granted.accessibility||t.push(`Accessibility is not granted: the apps above are real, but their WINDOWS and controls cannot be read \u2014 that is why every one of them lists as "no windows", and why an observation would come back empty. ${p("Accessibility")}`),this.granted.screenRecording||t.push(`Screen Recording is not granted: no window here can be photographed. ${p("Screen Recording")}`),t.length?t.join(`
2
+ `):null}async apps(){return(await this.call("apps")).apps}async lookup(t){return(await this.call("lookup",{bundles:t.bundles??[],pids:t.pids??[]})).apps}async scopedApps(){return(this.fallback&&!this.asking?this.fallback.size?await this.lookup({bundles:[...this.fallback]}):[]:await this.apps()).filter(e=>!this.hostApps.has(e.bundle))}async installed(t){return t.length?(await this.call("installed",{bundles:t})).apps:[]}async windows(t){const e=await this.call("windows",{pid:t});return{rows:e.windows,locked:e.locked}}async ensure(){if(this.app)return await this.authorize(this.app.bundle,this.app.name),{pid:this.app.pid,window:this.windowId??void 0};const t=this.wantBundle;if(!t)throw new Error(A);const e=(await this.lookup({bundles:[t]}))[0];await this.authorize(t,e?.name??(()=>this.displayName(t)));const s=e??await this.launchNamed(t);if(s.background)throw new Error(`mirasim-cu: ${b(t,s.pid)}`);return this.app=s,{pid:s.pid,window:void 0}}async launchNamed(t){let e;try{e=await this.call("launch",{bundle:t})}catch(a){throw new Error(`mirasim-cu: ${t} is not running and could not be launched \u2014 ${a instanceof Error?a.message:String(a)}; computer.surfaces() shows what IS running`)}this.forgetApp(),e.started!==!1&&this.noteStarted(e.app.pid);const s=v(e.app.name,e.app.pid,e.started!==!1),i=e.windows===0?`. ${R(e.app.name)}`:e.panel?`. ${C(e.app.name)}`:"";return this.addNote(e.ready?`${s}${i}`:`${s}, but it is not answering Accessibility yet. If this observation is empty, wait({ms:2000}) and observe again`),e.app}}export{q as MacosDriverApps};