@mseep/clawdcursor 1.5.5

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 (354) hide show
  1. package/CHANGELOG.md +2264 -0
  2. package/LICENSE +21 -0
  3. package/README.md +385 -0
  4. package/SECURITY.md +44 -0
  5. package/SKILL.md +503 -0
  6. package/dist/core/agent-loop/agent.d.ts +42 -0
  7. package/dist/core/agent-loop/agent.js +1023 -0
  8. package/dist/core/agent-loop/agent.js.map +1 -0
  9. package/dist/core/agent-loop/batch-tool.d.ts +25 -0
  10. package/dist/core/agent-loop/batch-tool.js +218 -0
  11. package/dist/core/agent-loop/batch-tool.js.map +1 -0
  12. package/dist/core/agent-loop/coord-scale.d.ts +72 -0
  13. package/dist/core/agent-loop/coord-scale.js +89 -0
  14. package/dist/core/agent-loop/coord-scale.js.map +1 -0
  15. package/dist/core/agent-loop/focus-guard.d.ts +24 -0
  16. package/dist/core/agent-loop/focus-guard.js +29 -0
  17. package/dist/core/agent-loop/focus-guard.js.map +1 -0
  18. package/dist/core/agent-loop/project-mcp.d.ts +97 -0
  19. package/dist/core/agent-loop/project-mcp.js +253 -0
  20. package/dist/core/agent-loop/project-mcp.js.map +1 -0
  21. package/dist/core/agent-loop/prompt.d.ts +45 -0
  22. package/dist/core/agent-loop/prompt.js +426 -0
  23. package/dist/core/agent-loop/prompt.js.map +1 -0
  24. package/dist/core/agent-loop/tool-meta.d.ts +93 -0
  25. package/dist/core/agent-loop/tool-meta.js +651 -0
  26. package/dist/core/agent-loop/tool-meta.js.map +1 -0
  27. package/dist/core/agent-loop/tools.d.ts +38 -0
  28. package/dist/core/agent-loop/tools.js +2134 -0
  29. package/dist/core/agent-loop/tools.js.map +1 -0
  30. package/dist/core/agent-loop/types.d.ts +170 -0
  31. package/dist/core/agent-loop/types.js +12 -0
  32. package/dist/core/agent-loop/types.js.map +1 -0
  33. package/dist/core/agent.d.ts +51 -0
  34. package/dist/core/agent.js +245 -0
  35. package/dist/core/agent.js.map +1 -0
  36. package/dist/core/app-categories.d.ts +67 -0
  37. package/dist/core/app-categories.js +108 -0
  38. package/dist/core/app-categories.js.map +1 -0
  39. package/dist/core/banner.d.ts +70 -0
  40. package/dist/core/banner.js +245 -0
  41. package/dist/core/banner.js.map +1 -0
  42. package/dist/core/classify/capability.d.ts +45 -0
  43. package/dist/core/classify/capability.js +78 -0
  44. package/dist/core/classify/capability.js.map +1 -0
  45. package/dist/core/decompose/llm-decomposer.d.ts +35 -0
  46. package/dist/core/decompose/llm-decomposer.js +156 -0
  47. package/dist/core/decompose/llm-decomposer.js.map +1 -0
  48. package/dist/core/decompose/parser.d.ts +27 -0
  49. package/dist/core/decompose/parser.js +101 -0
  50. package/dist/core/decompose/parser.js.map +1 -0
  51. package/dist/core/observability/correlation.d.ts +19 -0
  52. package/dist/core/observability/correlation.js +36 -0
  53. package/dist/core/observability/correlation.js.map +1 -0
  54. package/dist/core/observability/cost-meter.d.ts +51 -0
  55. package/dist/core/observability/cost-meter.js +134 -0
  56. package/dist/core/observability/cost-meter.js.map +1 -0
  57. package/dist/core/observability/logger.d.ts +61 -0
  58. package/dist/core/observability/logger.js +550 -0
  59. package/dist/core/observability/logger.js.map +1 -0
  60. package/dist/core/router/aliases.d.ts +50 -0
  61. package/dist/core/router/aliases.js +104 -0
  62. package/dist/core/router/aliases.js.map +1 -0
  63. package/dist/core/router/normalize.d.ts +41 -0
  64. package/dist/core/router/normalize.js +80 -0
  65. package/dist/core/router/normalize.js.map +1 -0
  66. package/dist/core/safety.d.ts +126 -0
  67. package/dist/core/safety.js +568 -0
  68. package/dist/core/safety.js.map +1 -0
  69. package/dist/core/sense/a11y-resolver.d.ts +73 -0
  70. package/dist/core/sense/a11y-resolver.js +76 -0
  71. package/dist/core/sense/a11y-resolver.js.map +1 -0
  72. package/dist/core/sense/fingerprint.d.ts +41 -0
  73. package/dist/core/sense/fingerprint.js +123 -0
  74. package/dist/core/sense/fingerprint.js.map +1 -0
  75. package/dist/core/sense/rank.d.ts +70 -0
  76. package/dist/core/sense/rank.js +192 -0
  77. package/dist/core/sense/rank.js.map +1 -0
  78. package/dist/core/sense/reactive-check.d.ts +40 -0
  79. package/dist/core/sense/reactive-check.js +48 -0
  80. package/dist/core/sense/reactive-check.js.map +1 -0
  81. package/dist/core/sense/snapshot.d.ts +19 -0
  82. package/dist/core/sense/snapshot.js +100 -0
  83. package/dist/core/sense/snapshot.js.map +1 -0
  84. package/dist/core/sense/types.d.ts +66 -0
  85. package/dist/core/sense/types.js +9 -0
  86. package/dist/core/sense/types.js.map +1 -0
  87. package/dist/core/sense/ui-map-anchors.d.ts +7 -0
  88. package/dist/core/sense/ui-map-anchors.js +24 -0
  89. package/dist/core/sense/ui-map-anchors.js.map +1 -0
  90. package/dist/core/sense/ui-map-elements.d.ts +5 -0
  91. package/dist/core/sense/ui-map-elements.js +33 -0
  92. package/dist/core/sense/ui-map-elements.js.map +1 -0
  93. package/dist/core/sense/ui-map-find.d.ts +56 -0
  94. package/dist/core/sense/ui-map-find.js +153 -0
  95. package/dist/core/sense/ui-map-find.js.map +1 -0
  96. package/dist/core/sense/ui-map-fuse.d.ts +4 -0
  97. package/dist/core/sense/ui-map-fuse.js +44 -0
  98. package/dist/core/sense/ui-map-fuse.js.map +1 -0
  99. package/dist/core/sense/ui-map-geom.d.ts +3 -0
  100. package/dist/core/sense/ui-map-geom.js +16 -0
  101. package/dist/core/sense/ui-map-geom.js.map +1 -0
  102. package/dist/core/sense/ui-map-holder.d.ts +58 -0
  103. package/dist/core/sense/ui-map-holder.js +87 -0
  104. package/dist/core/sense/ui-map-holder.js.map +1 -0
  105. package/dist/core/sense/ui-map-normalize.d.ts +19 -0
  106. package/dist/core/sense/ui-map-normalize.js +65 -0
  107. package/dist/core/sense/ui-map-normalize.js.map +1 -0
  108. package/dist/core/sense/ui-map-render.d.ts +4 -0
  109. package/dist/core/sense/ui-map-render.js +34 -0
  110. package/dist/core/sense/ui-map-render.js.map +1 -0
  111. package/dist/core/sense/ui-map-resolve.d.ts +41 -0
  112. package/dist/core/sense/ui-map-resolve.js +59 -0
  113. package/dist/core/sense/ui-map-resolve.js.map +1 -0
  114. package/dist/core/sense/ui-map-types.d.ts +66 -0
  115. package/dist/core/sense/ui-map-types.js +11 -0
  116. package/dist/core/sense/ui-map-types.js.map +1 -0
  117. package/dist/core/sense/ui-map.d.ts +29 -0
  118. package/dist/core/sense/ui-map.js +113 -0
  119. package/dist/core/sense/ui-map.js.map +1 -0
  120. package/dist/core/verify/assertions.d.ts +132 -0
  121. package/dist/core/verify/assertions.js +284 -0
  122. package/dist/core/verify/assertions.js.map +1 -0
  123. package/dist/index.d.ts +21 -0
  124. package/dist/index.js +24 -0
  125. package/dist/index.js.map +1 -0
  126. package/dist/llm/browser-config.d.ts +36 -0
  127. package/dist/llm/browser-config.js +83 -0
  128. package/dist/llm/browser-config.js.map +1 -0
  129. package/dist/llm/client.d.ts +268 -0
  130. package/dist/llm/client.js +1094 -0
  131. package/dist/llm/client.js.map +1 -0
  132. package/dist/llm/config.d.ts +79 -0
  133. package/dist/llm/config.js +375 -0
  134. package/dist/llm/config.js.map +1 -0
  135. package/dist/llm/credentials.d.ts +35 -0
  136. package/dist/llm/credentials.js +491 -0
  137. package/dist/llm/credentials.js.map +1 -0
  138. package/dist/llm/external-creds.d.ts +42 -0
  139. package/dist/llm/external-creds.js +169 -0
  140. package/dist/llm/external-creds.js.map +1 -0
  141. package/dist/llm/providers.d.ts +123 -0
  142. package/dist/llm/providers.js +717 -0
  143. package/dist/llm/providers.js.map +1 -0
  144. package/dist/paths.d.ts +31 -0
  145. package/dist/paths.js +147 -0
  146. package/dist/paths.js.map +1 -0
  147. package/dist/platform/accessibility.d.ts +139 -0
  148. package/dist/platform/accessibility.js +670 -0
  149. package/dist/platform/accessibility.js.map +1 -0
  150. package/dist/platform/cdp-driver.d.ts +318 -0
  151. package/dist/platform/cdp-driver.js +1179 -0
  152. package/dist/platform/cdp-driver.js.map +1 -0
  153. package/dist/platform/index.d.ts +11 -0
  154. package/dist/platform/index.js +69 -0
  155. package/dist/platform/index.js.map +1 -0
  156. package/dist/platform/keys.d.ts +17 -0
  157. package/dist/platform/keys.js +129 -0
  158. package/dist/platform/keys.js.map +1 -0
  159. package/dist/platform/launch-poll.d.ts +101 -0
  160. package/dist/platform/launch-poll.js +177 -0
  161. package/dist/platform/launch-poll.js.map +1 -0
  162. package/dist/platform/linux.d.ts +173 -0
  163. package/dist/platform/linux.js +1253 -0
  164. package/dist/platform/linux.js.map +1 -0
  165. package/dist/platform/macos.d.ts +136 -0
  166. package/dist/platform/macos.js +976 -0
  167. package/dist/platform/macos.js.map +1 -0
  168. package/dist/platform/native-desktop.d.ts +145 -0
  169. package/dist/platform/native-desktop.js +936 -0
  170. package/dist/platform/native-desktop.js.map +1 -0
  171. package/dist/platform/native-helper.d.ts +130 -0
  172. package/dist/platform/native-helper.js +592 -0
  173. package/dist/platform/native-helper.js.map +1 -0
  174. package/dist/platform/ocr-engine.d.ts +78 -0
  175. package/dist/platform/ocr-engine.js +363 -0
  176. package/dist/platform/ocr-engine.js.map +1 -0
  177. package/dist/platform/ps-runner.d.ts +28 -0
  178. package/dist/platform/ps-runner.js +228 -0
  179. package/dist/platform/ps-runner.js.map +1 -0
  180. package/dist/platform/types.d.ts +397 -0
  181. package/dist/platform/types.js +15 -0
  182. package/dist/platform/types.js.map +1 -0
  183. package/dist/platform/uri-handler.d.ts +75 -0
  184. package/dist/platform/uri-handler.js +273 -0
  185. package/dist/platform/uri-handler.js.map +1 -0
  186. package/dist/platform/wayland-backend.d.ts +53 -0
  187. package/dist/platform/wayland-backend.js +348 -0
  188. package/dist/platform/wayland-backend.js.map +1 -0
  189. package/dist/platform/windows.d.ts +232 -0
  190. package/dist/platform/windows.js +1210 -0
  191. package/dist/platform/windows.js.map +1 -0
  192. package/dist/postbuild.d.ts +10 -0
  193. package/dist/postbuild.js +98 -0
  194. package/dist/postbuild.js.map +1 -0
  195. package/dist/schema/snapshot.d.ts +33 -0
  196. package/dist/schema/snapshot.js +90 -0
  197. package/dist/schema/snapshot.js.map +1 -0
  198. package/dist/shortcuts.d.ts +30 -0
  199. package/dist/shortcuts.js +261 -0
  200. package/dist/shortcuts.js.map +1 -0
  201. package/dist/surface/cli.d.ts +7 -0
  202. package/dist/surface/cli.js +1556 -0
  203. package/dist/surface/cli.js.map +1 -0
  204. package/dist/surface/dashboard.d.ts +8 -0
  205. package/dist/surface/dashboard.js +1193 -0
  206. package/dist/surface/dashboard.js.map +1 -0
  207. package/dist/surface/doctor.d.ts +29 -0
  208. package/dist/surface/doctor.js +1514 -0
  209. package/dist/surface/doctor.js.map +1 -0
  210. package/dist/surface/format.d.ts +10 -0
  211. package/dist/surface/format.js +37 -0
  212. package/dist/surface/format.js.map +1 -0
  213. package/dist/surface/http-utility.d.ts +65 -0
  214. package/dist/surface/http-utility.js +336 -0
  215. package/dist/surface/http-utility.js.map +1 -0
  216. package/dist/surface/mcp-server.d.ts +91 -0
  217. package/dist/surface/mcp-server.js +280 -0
  218. package/dist/surface/mcp-server.js.map +1 -0
  219. package/dist/surface/onboarding.d.ts +15 -0
  220. package/dist/surface/onboarding.js +184 -0
  221. package/dist/surface/onboarding.js.map +1 -0
  222. package/dist/surface/pidfile.d.ts +79 -0
  223. package/dist/surface/pidfile.js +263 -0
  224. package/dist/surface/pidfile.js.map +1 -0
  225. package/dist/surface/readiness.d.ts +45 -0
  226. package/dist/surface/readiness.js +230 -0
  227. package/dist/surface/readiness.js.map +1 -0
  228. package/dist/surface/report.d.ts +68 -0
  229. package/dist/surface/report.js +341 -0
  230. package/dist/surface/report.js.map +1 -0
  231. package/dist/surface/skill-register.d.ts +14 -0
  232. package/dist/surface/skill-register.js +150 -0
  233. package/dist/surface/skill-register.js.map +1 -0
  234. package/dist/surface/version.d.ts +6 -0
  235. package/dist/surface/version.js +27 -0
  236. package/dist/surface/version.js.map +1 -0
  237. package/dist/tools/a11y.d.ts +8 -0
  238. package/dist/tools/a11y.js +545 -0
  239. package/dist/tools/a11y.js.map +1 -0
  240. package/dist/tools/a11y_depth.d.ts +19 -0
  241. package/dist/tools/a11y_depth.js +455 -0
  242. package/dist/tools/a11y_depth.js.map +1 -0
  243. package/dist/tools/agent.d.ts +15 -0
  244. package/dist/tools/agent.js +248 -0
  245. package/dist/tools/agent.js.map +1 -0
  246. package/dist/tools/batch.d.ts +46 -0
  247. package/dist/tools/batch.js +230 -0
  248. package/dist/tools/batch.js.map +1 -0
  249. package/dist/tools/cdp.d.ts +8 -0
  250. package/dist/tools/cdp.js +233 -0
  251. package/dist/tools/cdp.js.map +1 -0
  252. package/dist/tools/compact.d.ts +63 -0
  253. package/dist/tools/compact.js +418 -0
  254. package/dist/tools/compact.js.map +1 -0
  255. package/dist/tools/cost-class.d.ts +38 -0
  256. package/dist/tools/cost-class.js +117 -0
  257. package/dist/tools/cost-class.js.map +1 -0
  258. package/dist/tools/desktop.d.ts +9 -0
  259. package/dist/tools/desktop.js +346 -0
  260. package/dist/tools/desktop.js.map +1 -0
  261. package/dist/tools/electron_bridge.d.ts +41 -0
  262. package/dist/tools/electron_bridge.js +261 -0
  263. package/dist/tools/electron_bridge.js.map +1 -0
  264. package/dist/tools/extras.d.ts +22 -0
  265. package/dist/tools/extras.js +942 -0
  266. package/dist/tools/extras.js.map +1 -0
  267. package/dist/tools/favorites.d.ts +13 -0
  268. package/dist/tools/favorites.js +137 -0
  269. package/dist/tools/favorites.js.map +1 -0
  270. package/dist/tools/introspection.d.ts +13 -0
  271. package/dist/tools/introspection.js +55 -0
  272. package/dist/tools/introspection.js.map +1 -0
  273. package/dist/tools/ocr.d.ts +8 -0
  274. package/dist/tools/ocr.js +66 -0
  275. package/dist/tools/ocr.js.map +1 -0
  276. package/dist/tools/orchestration.d.ts +7 -0
  277. package/dist/tools/orchestration.js +377 -0
  278. package/dist/tools/orchestration.js.map +1 -0
  279. package/dist/tools/playbooks/extract-compose.d.ts +22 -0
  280. package/dist/tools/playbooks/extract-compose.js +85 -0
  281. package/dist/tools/playbooks/extract-compose.js.map +1 -0
  282. package/dist/tools/playbooks/find-replace.d.ts +11 -0
  283. package/dist/tools/playbooks/find-replace.js +56 -0
  284. package/dist/tools/playbooks/find-replace.js.map +1 -0
  285. package/dist/tools/playbooks/index.d.ts +63 -0
  286. package/dist/tools/playbooks/index.js +70 -0
  287. package/dist/tools/playbooks/index.js.map +1 -0
  288. package/dist/tools/playbooks/keys-blocklist.d.ts +24 -0
  289. package/dist/tools/playbooks/keys-blocklist.js +89 -0
  290. package/dist/tools/playbooks/keys-blocklist.js.map +1 -0
  291. package/dist/tools/registry.d.ts +40 -0
  292. package/dist/tools/registry.js +560 -0
  293. package/dist/tools/registry.js.map +1 -0
  294. package/dist/tools/safety-gate.d.ts +16 -0
  295. package/dist/tools/safety-gate.js +70 -0
  296. package/dist/tools/safety-gate.js.map +1 -0
  297. package/dist/tools/scheduler.d.ts +76 -0
  298. package/dist/tools/scheduler.js +413 -0
  299. package/dist/tools/scheduler.js.map +1 -0
  300. package/dist/tools/shortcuts.d.ts +13 -0
  301. package/dist/tools/shortcuts.js +205 -0
  302. package/dist/tools/shortcuts.js.map +1 -0
  303. package/dist/tools/smart.d.ts +15 -0
  304. package/dist/tools/smart.js +785 -0
  305. package/dist/tools/smart.js.map +1 -0
  306. package/dist/tools/types.d.ts +174 -0
  307. package/dist/tools/types.js +67 -0
  308. package/dist/tools/types.js.map +1 -0
  309. package/dist/tools/window-text.d.ts +15 -0
  310. package/dist/tools/window-text.js +39 -0
  311. package/dist/tools/window-text.js.map +1 -0
  312. package/dist/types.d.ts +122 -0
  313. package/dist/types.js +41 -0
  314. package/dist/types.js.map +1 -0
  315. package/native/Package.swift +38 -0
  316. package/native/README.md +113 -0
  317. package/native/Sources/ClawdCursorHelper/main.swift +602 -0
  318. package/native/Sources/ClawdCursorHost/main.swift +182 -0
  319. package/native/Sources/PermissionCheck/main.swift +53 -0
  320. package/native/Sources/ScreenshotHelper/main.swift +219 -0
  321. package/native/build.sh +139 -0
  322. package/native/entitlements.plist +12 -0
  323. package/package.json +115 -0
  324. package/scripts/banner.ps1 +112 -0
  325. package/scripts/coord-accuracy.ps1 +140 -0
  326. package/scripts/coord-uwp.ps1 +80 -0
  327. package/scripts/edge-glow.ps1 +180 -0
  328. package/scripts/find-element.ps1 +198 -0
  329. package/scripts/get-foreground-window.ps1 +71 -0
  330. package/scripts/get-screen-context.ps1 +183 -0
  331. package/scripts/get-windows.ps1 +66 -0
  332. package/scripts/install-panic-hotkey.ps1 +46 -0
  333. package/scripts/interact-element.ps1 +431 -0
  334. package/scripts/invoke-element.ps1 +314 -0
  335. package/scripts/linux/atspi-bridge.py +356 -0
  336. package/scripts/linux/ocr-recognize.py +154 -0
  337. package/scripts/mac/_window-picker.jxa +163 -0
  338. package/scripts/mac/find-element.jxa +0 -0
  339. package/scripts/mac/find-element.sh +161 -0
  340. package/scripts/mac/focus-window.jxa +284 -0
  341. package/scripts/mac/get-focused-element.jxa +102 -0
  342. package/scripts/mac/get-foreground-window.jxa +173 -0
  343. package/scripts/mac/get-screen-context.jxa +197 -0
  344. package/scripts/mac/get-ui-tree.sh +141 -0
  345. package/scripts/mac/get-windows.jxa +117 -0
  346. package/scripts/mac/interact-element.sh +235 -0
  347. package/scripts/mac/invoke-element.jxa +408 -0
  348. package/scripts/mac/ocr-recognize.swift +124 -0
  349. package/scripts/ocr-recognize.ps1 +102 -0
  350. package/scripts/postinstall-native.js +48 -0
  351. package/scripts/ps-bridge.ps1 +830 -0
  352. package/scripts/smoke-mcp.ps1 +119 -0
  353. package/scripts/sync-version.ts +178 -0
  354. package/scripts/verify-install.js +81 -0
@@ -0,0 +1,408 @@
1
+ #!/usr/bin/env osascript -l JavaScript
2
+
3
+ /**
4
+ * invoke-element.jxa
5
+ *
6
+ * Finds a UI element and invokes an action on it.
7
+ *
8
+ * Parameters:
9
+ * -action <string> - Required. One of: click | focus | set-value | get-value |
10
+ * expand | collapse | toggle | select
11
+ * -name <string> - Match elements by name (contains match, case-insensitive)
12
+ * -role <string> - Match elements by role (e.g., "button", "text field")
13
+ * -processId <number> - Required. The process ID of the target application
14
+ * -value <string> - Value to set (only used with set-value action)
15
+ *
16
+ * Returns JSON result with success status and action-specific data.
17
+ *
18
+ * Usage: osascript -l JavaScript invoke-element.jxa -action click -name "OK" -processId 1234
19
+ * osascript -l JavaScript invoke-element.jxa -action set-value -name "Username" -value "john" -processId 1234
20
+ */
21
+
22
+ // Utility function to safely get property values
23
+ function safeGet(obj, property, defaultValue) {
24
+ try {
25
+ var val = obj[property]();
26
+ return val !== undefined && val !== null ? val : defaultValue;
27
+ } catch (e) {
28
+ return defaultValue;
29
+ }
30
+ }
31
+
32
+ // Find element matching criteria
33
+ function findElement(root, targetName, targetRole, maxDepth, currentDepth) {
34
+ if (currentDepth > maxDepth) {
35
+ return null;
36
+ }
37
+
38
+ try {
39
+ var elName = '';
40
+ var elRole = '';
41
+
42
+ try {
43
+ elName = root.name() || '';
44
+ } catch (e) {}
45
+
46
+ try {
47
+ elRole = root.role() || '';
48
+ } catch (e) {}
49
+
50
+ // Check if this element matches
51
+ var nameMatch = !targetName ||
52
+ (elName && elName.toLowerCase().indexOf(targetName.toLowerCase()) !== -1);
53
+ var roleMatch = !targetRole ||
54
+ (elRole && elRole.toLowerCase().indexOf(targetRole.toLowerCase()) !== -1);
55
+
56
+ if (nameMatch && roleMatch && (elName || elRole)) {
57
+ return root;
58
+ }
59
+
60
+ // Search children
61
+ try {
62
+ var children = root.uiElements();
63
+ for (var i = 0; i < children.length; i++) {
64
+ var found = findElement(children[i], targetName, targetRole, maxDepth, currentDepth + 1);
65
+ if (found) return found;
66
+ }
67
+ } catch (e) {}
68
+
69
+ // Check specific element types
70
+ var elementTypes = ['buttons', 'textFields', 'popUpButtons', 'checkboxes', 'radioButtons', 'menus'];
71
+ for (var j = 0; j < elementTypes.length; j++) {
72
+ try {
73
+ var typedElements = root[elementTypes[j]]();
74
+ for (var k = 0; k < typedElements.length; k++) {
75
+ var found = findElement(typedElements[k], targetName, targetRole, maxDepth, currentDepth + 1);
76
+ if (found) return found;
77
+ }
78
+ } catch (e) {}
79
+ }
80
+ } catch (e) {}
81
+
82
+ return null;
83
+ }
84
+
85
+ // Get element bounds for coordinate fallback
86
+ function getElementBounds(element) {
87
+ try {
88
+ if (element.position && element.size) {
89
+ var pos = element.position();
90
+ var sz = element.size();
91
+ return {
92
+ x: pos[0] || 0,
93
+ y: pos[1] || 0,
94
+ width: sz[0] || 0,
95
+ height: sz[1] || 0
96
+ };
97
+ }
98
+ } catch (e) {}
99
+ return null;
100
+ }
101
+
102
+ // run(argv) is the JXA entry point — osascript calls it and its return value becomes stdout.
103
+ // argv receives command-line arguments passed after the script path.
104
+ function run(argv) {
105
+ try {
106
+ // Parse arguments from argv array
107
+ var params = {
108
+ action: null,
109
+ name: null,
110
+ role: null,
111
+ processId: null,
112
+ value: null
113
+ };
114
+ // Windows ControlType → macOS AX role mapping (mirrors find-element.jxa)
115
+ var CONTROL_TYPE_MAP = {
116
+ 'Button': 'button', 'Edit': 'text field', 'Document': 'web area',
117
+ 'ComboBox': 'pop up button', 'CheckBox': 'checkbox',
118
+ 'RadioButton': 'radio button', 'Hyperlink': 'link',
119
+ 'MenuItem': 'menu item', 'Menu': 'menu', 'Tab': 'tab group',
120
+ 'TabItem': 'radio button', 'ListItem': 'row', 'TreeItem': 'row',
121
+ 'Slider': 'slider', 'ScrollBar': 'scroll bar',
122
+ 'ToolBar': 'toolbar', 'StaticText': 'static text', 'Window': 'window'
123
+ };
124
+
125
+ for (var i = 0; i < argv.length; i++) {
126
+ var a = argv[i];
127
+ var hasNext = i + 1 < argv.length;
128
+ if ((a === '-action' || a === '-Action') && hasNext) {
129
+ params.action = argv[++i];
130
+ } else if ((a === '-name' || a === '-Name') && hasNext) {
131
+ params.name = argv[++i];
132
+ } else if ((a === '-role') && hasNext) {
133
+ params.role = argv[++i];
134
+ } else if (a === '-ControlType' && hasNext) {
135
+ var ct = argv[++i];
136
+ params.role = CONTROL_TYPE_MAP[ct] || ct.toLowerCase();
137
+ } else if ((a === '-processId' || a === '-ProcessId' || a === '-FocusedProcessId') && hasNext) {
138
+ // -FocusedProcessId accepted as an alias for callers that share
139
+ // arg-building with get-screen-context.jxa (defense-in-depth).
140
+ params.processId = parseInt(argv[++i], 10);
141
+ } else if ((a === '-value' || a === '-Value') && hasNext) {
142
+ params.value = argv[++i];
143
+ }
144
+ // -AutomationId and -Restore have no macOS equivalent; silently ignore
145
+ }
146
+
147
+ // Validate required parameters
148
+ if (!params.action) {
149
+ return JSON.stringify({
150
+ success: false,
151
+ error: 'Missing required parameter: -action'
152
+ });
153
+ }
154
+
155
+ if (!params.processId) {
156
+ return JSON.stringify({
157
+ success: false,
158
+ error: 'Missing required parameter: -processId'
159
+ });
160
+ }
161
+
162
+ var SystemEvents = Application('System Events');
163
+ SystemEvents.includeStandardAdditions = true;
164
+
165
+ // Find the target process
166
+ var targetProcess = null;
167
+ var processes = SystemEvents.processes.where({ unixId: params.processId });
168
+
169
+ if (processes.length === 0) {
170
+ return JSON.stringify({
171
+ success: false,
172
+ error: 'No process found with ID ' + params.processId
173
+ });
174
+ }
175
+
176
+ targetProcess = processes[0];
177
+
178
+ // Find target element
179
+ var targetElement = null;
180
+ var windows = targetProcess.windows;
181
+
182
+ for (var w = 0; w < windows.length && !targetElement; w++) {
183
+ targetElement = findElement(windows[w], params.name, params.role, 10, 0);
184
+ }
185
+
186
+ if (!targetElement) {
187
+ var searchDesc = '';
188
+ if (params.name) searchDesc += 'name="' + params.name + '" ';
189
+ if (params.role) searchDesc += 'role="' + params.role + '" ';
190
+ return JSON.stringify({
191
+ success: false,
192
+ error: 'Element not found: ' + searchDesc.trim()
193
+ });
194
+ }
195
+
196
+ // Execute the requested action
197
+ var result = { success: false };
198
+
199
+ switch (params.action) {
200
+ case 'click':
201
+ try {
202
+ targetElement.click();
203
+ result = {
204
+ success: true,
205
+ action: 'click',
206
+ method: 'click()'
207
+ };
208
+ } catch (e) {
209
+ // Fallback: return bounds for coordinate click
210
+ var bounds = getElementBounds(targetElement);
211
+ if (bounds) {
212
+ result = {
213
+ success: false,
214
+ action: 'click',
215
+ error: 'Element does not support click(). Use coordinate click.',
216
+ clickPoint: {
217
+ x: bounds.x + Math.floor(bounds.width / 2),
218
+ y: bounds.y + Math.floor(bounds.height / 2)
219
+ }
220
+ };
221
+ } else {
222
+ result = {
223
+ success: false,
224
+ action: 'click',
225
+ error: 'Click failed and no bounds available: ' + e.toString()
226
+ };
227
+ }
228
+ }
229
+ break;
230
+
231
+ case 'set-value':
232
+ if (params.value === null) {
233
+ result = {
234
+ success: false,
235
+ error: 'Value parameter required for set-value action'
236
+ };
237
+ } else {
238
+ try {
239
+ targetElement.value = params.value;
240
+ result = {
241
+ success: true,
242
+ action: 'set-value',
243
+ value: params.value
244
+ };
245
+ } catch (e) {
246
+ // Try setting through focused property
247
+ try {
248
+ targetElement.focused = true;
249
+ // Use System Events to type the value
250
+ var app = Application.currentApplication();
251
+ app.includeStandardAdditions = true;
252
+ app.keystroke(params.value);
253
+ result = {
254
+ success: true,
255
+ action: 'set-value',
256
+ value: params.value,
257
+ method: 'keystroke'
258
+ };
259
+ } catch (ke) {
260
+ result = {
261
+ success: false,
262
+ error: 'Failed to set value: ' + e.toString()
263
+ };
264
+ }
265
+ }
266
+ }
267
+ break;
268
+
269
+ case 'get-value':
270
+ // Prefer AXValue, but fall back to the name property when AXValue
271
+ // is absent OR empty. Some controls expose an AXValue that reads
272
+ // "" while the real text is only in the title/name — returning the
273
+ // empty string there caused false "value did not change" reads
274
+ // (parity with the Windows ValuePattern→TextPattern fix).
275
+ var gotVal = null, gotMethod = null;
276
+ try {
277
+ var val = targetElement.value();
278
+ if (val !== null && val !== undefined && String(val).length > 0) {
279
+ gotVal = val; gotMethod = 'AXValue';
280
+ }
281
+ } catch (e) { /* no AXValue — try name */ }
282
+ if (gotVal === null) {
283
+ try {
284
+ var name = targetElement.name();
285
+ if (name !== null && name !== undefined && String(name).length > 0) {
286
+ gotVal = name; gotMethod = 'name';
287
+ }
288
+ } catch (ne) { /* no name either */ }
289
+ }
290
+ if (gotVal !== null) {
291
+ result = { success: true, action: 'get-value', value: gotVal, method: gotMethod };
292
+ } else {
293
+ // Genuinely empty (e.g. an empty field) — report "" success, not an error.
294
+ result = { success: true, action: 'get-value', value: '', method: 'empty' };
295
+ }
296
+ break;
297
+
298
+ case 'focus':
299
+ try {
300
+ targetElement.focused = true;
301
+ result = {
302
+ success: true,
303
+ action: 'focus'
304
+ };
305
+ } catch (e) {
306
+ result = {
307
+ success: false,
308
+ error: 'Failed to set focus: ' + e.toString()
309
+ };
310
+ }
311
+ break;
312
+
313
+ // ── Tranche 1A: AX Expand/Collapse/Toggle/Select ────────────
314
+ // macOS AX exposes these through attributes (`AXExpanded`,
315
+ // `AXValue` for checkboxes) rather than actions. JXA lets us
316
+ // set them directly. Failing gracefully when an element
317
+ // doesn't support the attribute is important — UIA-style
318
+ // pattern-query equivalents don't exist on AX, so we just
319
+ // attempt the assignment and catch.
320
+ case 'expand':
321
+ try {
322
+ targetElement.attributes['AXExpanded'].value = true;
323
+ result = { success: true, action: 'expand' };
324
+ } catch (e) {
325
+ try {
326
+ // Menu-style elements respond to AXShowMenu action.
327
+ targetElement.actions['AXShowMenu'].perform();
328
+ result = { success: true, action: 'expand', method: 'AXShowMenu' };
329
+ } catch (e2) {
330
+ result = {
331
+ success: false,
332
+ error: 'Element does not support expand (no AXExpanded attribute or AXShowMenu action)'
333
+ };
334
+ }
335
+ }
336
+ break;
337
+
338
+ case 'collapse':
339
+ try {
340
+ targetElement.attributes['AXExpanded'].value = false;
341
+ result = { success: true, action: 'collapse' };
342
+ } catch (e) {
343
+ result = {
344
+ success: false,
345
+ error: 'Element does not support collapse (no AXExpanded attribute)'
346
+ };
347
+ }
348
+ break;
349
+
350
+ case 'toggle':
351
+ // Checkboxes / radios expose AXValue as 0/1.
352
+ try {
353
+ var currentValue;
354
+ try { currentValue = targetElement.attributes['AXValue'].value; }
355
+ catch (vErr) { currentValue = 0; }
356
+ var newValue = currentValue ? 0 : 1;
357
+ targetElement.attributes['AXValue'].value = newValue;
358
+ result = {
359
+ success: true,
360
+ action: 'toggle',
361
+ data: { toggleState: newValue ? 'On' : 'Off' }
362
+ };
363
+ } catch (e) {
364
+ // Fallback: invoke a click (AXPress) — matches UIA Toggle semantics.
365
+ try {
366
+ targetElement.actions['AXPress'].perform();
367
+ result = { success: true, action: 'toggle', method: 'AXPress' };
368
+ } catch (e2) {
369
+ result = {
370
+ success: false,
371
+ error: 'Element does not support toggle (no AXValue or AXPress)'
372
+ };
373
+ }
374
+ }
375
+ break;
376
+
377
+ case 'select':
378
+ // AX uses AXSelected attribute for list items / tabs.
379
+ try {
380
+ targetElement.attributes['AXSelected'].value = true;
381
+ result = { success: true, action: 'select' };
382
+ } catch (e) {
383
+ // Some pickers use AXPick / AXMenuItemMark attributes — try AXPress as last resort.
384
+ try {
385
+ targetElement.actions['AXPress'].perform();
386
+ result = { success: true, action: 'select', method: 'AXPress' };
387
+ } catch (e2) {
388
+ result = {
389
+ success: false,
390
+ error: 'Element does not support select (no AXSelected attribute or AXPress action)'
391
+ };
392
+ }
393
+ }
394
+ break;
395
+
396
+ default:
397
+ result = {
398
+ success: false,
399
+ error: 'Unknown action: ' + params.action
400
+ };
401
+ }
402
+
403
+ return JSON.stringify(result);
404
+
405
+ } catch (error) {
406
+ return JSON.stringify({ success: false, error: error.toString() });
407
+ }
408
+ }
@@ -0,0 +1,124 @@
1
+ #!/usr/bin/env swift
2
+ // macOS OCR via Vision framework (VNRecognizeTextRequest)
3
+ // Takes an image path, outputs JSON result to stdout.
4
+ // Matches the same JSON format as ocr-recognize.ps1 (Windows).
5
+ //
6
+ // Usage: swift ocr-recognize.swift /path/to/image.png
7
+
8
+ import Foundation
9
+ import Vision
10
+ import AppKit
11
+
12
+ guard CommandLine.arguments.count > 1 else {
13
+ let err: [String: Any] = ["error": "Usage: ocr-recognize.swift <image-path>"]
14
+ if let data = try? JSONSerialization.data(withJSONObject: err),
15
+ let str = String(data: data, encoding: .utf8) {
16
+ print(str)
17
+ }
18
+ exit(0)
19
+ }
20
+
21
+ let imagePath = CommandLine.arguments[1]
22
+ let imageURL = URL(fileURLWithPath: imagePath)
23
+
24
+ guard let image = NSImage(contentsOf: imageURL),
25
+ let cgImage = image.cgImage(forProposedRect: nil, context: nil, hints: nil) else {
26
+ let err: [String: Any] = ["error": "Failed to load image: \(imagePath)"]
27
+ if let data = try? JSONSerialization.data(withJSONObject: err),
28
+ let str = String(data: data, encoding: .utf8) {
29
+ print(str)
30
+ }
31
+ exit(0)
32
+ }
33
+
34
+ let imageWidth = CGFloat(cgImage.width)
35
+ let imageHeight = CGFloat(cgImage.height)
36
+
37
+ let semaphore = DispatchSemaphore(value: 0)
38
+ var elements: [[String: Any]] = []
39
+ var fullText = ""
40
+
41
+ let request = VNRecognizeTextRequest { request, error in
42
+ defer { semaphore.signal() }
43
+
44
+ if let error = error {
45
+ let err: [String: Any] = ["error": "OCR failed: \(error.localizedDescription)"]
46
+ if let data = try? JSONSerialization.data(withJSONObject: err),
47
+ let str = String(data: data, encoding: .utf8) {
48
+ print(str)
49
+ }
50
+ return
51
+ }
52
+
53
+ guard let observations = request.results as? [VNRecognizedTextObservation] else { return }
54
+
55
+ var lineIdx = 0
56
+ var lines: [String] = []
57
+
58
+ for observation in observations {
59
+ guard let candidate = observation.topCandidates(1).first else { continue }
60
+ let text = candidate.string
61
+ let confidence = candidate.confidence
62
+ let box = observation.boundingBox
63
+
64
+ // Vision coordinates: origin bottom-left, normalized 0-1
65
+ // Convert to screen pixels: origin top-left
66
+ let x = box.origin.x * imageWidth
67
+ let y = (1.0 - box.origin.y - box.height) * imageHeight
68
+ let w = box.width * imageWidth
69
+ let h = box.height * imageHeight
70
+
71
+ // Split into words for per-word bounding boxes (approximate)
72
+ let words = text.components(separatedBy: " ")
73
+ let wordWidth = w / CGFloat(max(words.count, 1))
74
+
75
+ for (i, word) in words.enumerated() {
76
+ guard !word.isEmpty else { continue }
77
+ let element: [String: Any] = [
78
+ "text": word,
79
+ "x": Int(round(x + wordWidth * CGFloat(i))),
80
+ "y": Int(round(y)),
81
+ "width": Int(round(wordWidth)),
82
+ "height": Int(round(h)),
83
+ "confidence": round(Double(confidence) * 100) / 100,
84
+ "line": lineIdx
85
+ ]
86
+ elements.append(element)
87
+ }
88
+
89
+ lines.append(text)
90
+ lineIdx += 1
91
+ }
92
+
93
+ fullText = lines.joined(separator: "\n")
94
+ }
95
+
96
+ // Configure for accuracy (fast is also available)
97
+ request.recognitionLevel = .accurate
98
+ request.usesLanguageCorrection = true
99
+
100
+ let handler = VNImageRequestHandler(cgImage: cgImage, options: [:])
101
+ do {
102
+ try handler.perform([request])
103
+ } catch {
104
+ let err: [String: Any] = ["error": "VNImageRequestHandler failed: \(error.localizedDescription)"]
105
+ if let data = try? JSONSerialization.data(withJSONObject: err),
106
+ let str = String(data: data, encoding: .utf8) {
107
+ print(str)
108
+ }
109
+ exit(0)
110
+ }
111
+
112
+ // Wait for async completion
113
+ semaphore.wait()
114
+
115
+ // Output JSON matching Windows format
116
+ let result: [String: Any] = [
117
+ "elements": elements,
118
+ "fullText": fullText
119
+ ]
120
+
121
+ if let data = try? JSONSerialization.data(withJSONObject: result),
122
+ let str = String(data: data, encoding: .utf8) {
123
+ print(str)
124
+ }
@@ -0,0 +1,102 @@
1
+ # OCR Recognition via Windows.Media.Ocr WinRT API
2
+ # Takes an image path, runs OCR, outputs JSON result to stdout.
3
+ # Called one-shot per OCR request (results cached in TypeScript layer).
4
+
5
+ param([string]$ImagePath)
6
+
7
+ # Force UTF-8 on stdout so non-ASCII recognized text (emoji, accented
8
+ # characters, CJK) survives the round-trip to Node. PowerShell defaults
9
+ # to the system code page; Node decodes as UTF-8.
10
+ [Console]::OutputEncoding = [System.Text.Encoding]::UTF8
11
+ $OutputEncoding = [System.Text.Encoding]::UTF8
12
+
13
+ try {
14
+ # Resolve to absolute path (required by WinRT StorageFile API)
15
+ $ImagePath = (Resolve-Path $ImagePath -ErrorAction Stop).Path
16
+
17
+ # Load WinRT interop assembly
18
+ Add-Type -AssemblyName System.Runtime.WindowsRuntime
19
+
20
+ # Load WinRT types
21
+ $null = [Windows.Media.Ocr.OcrEngine, Windows.Foundation, ContentType = WindowsRuntime]
22
+ $null = [Windows.Graphics.Imaging.SoftwareBitmap, Windows.Foundation, ContentType = WindowsRuntime]
23
+ $null = [Windows.Graphics.Imaging.BitmapDecoder, Windows.Foundation, ContentType = WindowsRuntime]
24
+ $null = [Windows.Storage.StorageFile, Windows.Foundation, ContentType = WindowsRuntime]
25
+ $null = [Windows.Storage.Streams.RandomAccessStream, Windows.Foundation, ContentType = WindowsRuntime]
26
+
27
+ # Find the AsTask<TResult>(IAsyncOperation<TResult>) extension method
28
+ $asTaskOp = [System.WindowsRuntimeSystemExtensions].GetMethods() | Where-Object {
29
+ $_.Name -eq 'AsTask' -and
30
+ $_.IsGenericMethod -and
31
+ $_.GetParameters().Count -eq 1 -and
32
+ $_.GetParameters()[0].ParameterType.IsGenericType -and
33
+ $_.GetParameters()[0].ParameterType.GetGenericTypeDefinition().Name -eq 'IAsyncOperation`1'
34
+ } | Select-Object -First 1
35
+
36
+ if (-not $asTaskOp) {
37
+ [Console]::Out.WriteLine('{"error":"Cannot find AsTask method for WinRT async"}')
38
+ [Console]::Out.Flush()
39
+ exit 0
40
+ }
41
+
42
+ function Invoke-Async {
43
+ param([object]$AsyncOp, [Type]$ResultType)
44
+ $genericMethod = $script:asTaskOp.MakeGenericMethod($ResultType)
45
+ $task = $genericMethod.Invoke($null, @($AsyncOp))
46
+ $task.Wait() | Out-Null
47
+ return $task.Result
48
+ }
49
+
50
+ # Create OCR engine from user profile languages
51
+ $ocr = [Windows.Media.Ocr.OcrEngine]::TryCreateFromUserProfileLanguages()
52
+ if (-not $ocr) {
53
+ [Console]::Out.WriteLine('{"error":"Windows OCR engine not available - no recognized languages installed"}')
54
+ [Console]::Out.Flush()
55
+ exit 0
56
+ }
57
+
58
+ # Open image via WinRT StorageFile → stream → BitmapDecoder → SoftwareBitmap
59
+ $storageFile = Invoke-Async ([Windows.Storage.StorageFile]::GetFileFromPathAsync($ImagePath)) ([Windows.Storage.StorageFile])
60
+ $stream = Invoke-Async ($storageFile.OpenAsync([Windows.Storage.FileAccessMode]::Read)) ([Windows.Storage.Streams.IRandomAccessStream])
61
+ $decoder = Invoke-Async ([Windows.Graphics.Imaging.BitmapDecoder]::CreateAsync($stream)) ([Windows.Graphics.Imaging.BitmapDecoder])
62
+ $bitmap = Invoke-Async ($decoder.GetSoftwareBitmapAsync()) ([Windows.Graphics.Imaging.SoftwareBitmap])
63
+
64
+ # Run OCR recognition
65
+ $ocrResult = Invoke-Async ($ocr.RecognizeAsync($bitmap)) ([Windows.Media.Ocr.OcrResult])
66
+
67
+ # Build structured result — one entry per word with bounding box
68
+ $elements = @()
69
+ $lineIdx = 0
70
+ foreach ($line in $ocrResult.Lines) {
71
+ foreach ($word in $line.Words) {
72
+ $r = $word.BoundingRect
73
+ $elements += [PSCustomObject]@{
74
+ text = ($word.Text -replace '[\x00-\x08\x0B\x0C\x0E-\x1F]', '')
75
+ x = [math]::Round($r.X)
76
+ y = [math]::Round($r.Y)
77
+ width = [math]::Round($r.Width)
78
+ height = [math]::Round($r.Height)
79
+ confidence = 1.0 # Windows.Media.Ocr does not expose per-word confidence
80
+ line = $lineIdx
81
+ }
82
+ }
83
+ $lineIdx++
84
+ }
85
+
86
+ # Clean up WinRT resources
87
+ try { $stream.Dispose() } catch {}
88
+ try { $bitmap.Dispose() } catch {}
89
+
90
+ # Output single-line JSON
91
+ $output = [PSCustomObject]@{
92
+ elements = @($elements) # force array even if 0 or 1 element
93
+ fullText = if ($ocrResult.Text) { $ocrResult.Text } else { "" }
94
+ }
95
+ [Console]::Out.WriteLine(($output | ConvertTo-Json -Depth 3 -Compress))
96
+ [Console]::Out.Flush()
97
+
98
+ } catch {
99
+ [Console]::Out.WriteLine((@{ error = $_.Exception.Message } | ConvertTo-Json -Compress))
100
+ [Console]::Out.Flush()
101
+ exit 0
102
+ }
@@ -0,0 +1,48 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * macOS-only postinstall step (issue #149).
4
+ *
5
+ * The published npm package ships the Swift SOURCES for the native helper
6
+ * but not a prebuilt binary. Without the binary, screenshots / display
7
+ * enumeration / TCC permission checks all fail. This script builds the
8
+ * helper from the shipped sources on a fresh `npm i -g clawdcursor` so a
9
+ * Mac user gets a working install out of the box.
10
+ *
11
+ * Best-effort by design: it NEVER fails the install. If the Xcode toolchain
12
+ * (`swift`) is absent, it prints actionable guidance and exits 0 — the
13
+ * runtime emits the same guidance the first time a screenshot is needed.
14
+ *
15
+ * No-op on Windows/Linux.
16
+ */
17
+ 'use strict';
18
+ const { execFileSync, execSync } = require('child_process');
19
+ const path = require('path');
20
+ const fs = require('fs');
21
+
22
+ if (process.platform !== 'darwin') process.exit(0);
23
+
24
+ const root = path.join(__dirname, '..');
25
+ const nativeDir = path.join(root, 'native');
26
+ const buildSh = path.join(nativeDir, 'build.sh');
27
+
28
+ // Dev checkouts / odd layouts: if sources aren't present, there's nothing to do.
29
+ if (!fs.existsSync(buildSh)) process.exit(0);
30
+
31
+ // Is the Swift toolchain available?
32
+ try {
33
+ execSync('command -v swift', { stdio: 'ignore', shell: '/bin/bash' });
34
+ } catch {
35
+ console.log('[clawdcursor] Native macOS helper not built — Xcode Command Line Tools (swift) not found.');
36
+ console.log(' Screenshots, display enumeration, and permission checks need it.');
37
+ console.log(' Install the tools, then build: xcode-select --install && cd "' + nativeDir + '" && ./build.sh');
38
+ process.exit(0);
39
+ }
40
+
41
+ try {
42
+ console.log('[clawdcursor] Building native macOS helper from source (native/build.sh)…');
43
+ execFileSync('/bin/bash', [buildSh], { stdio: 'inherit', cwd: nativeDir });
44
+ console.log('[clawdcursor] Native macOS helper built.');
45
+ } catch (_e) {
46
+ console.log('[clawdcursor] Native macOS helper build failed (non-fatal). Build manually with: cd native && ./build.sh');
47
+ }
48
+ process.exit(0);