@zenalexa/unicli 0.217.0 → 0.217.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/AGENTS.md +7 -6
  2. package/README.md +59 -19
  3. package/README.zh-CN.md +36 -15
  4. package/crates/unicli-atspi/Cargo.toml +47 -0
  5. package/crates/unicli-atspi/README.md +6 -0
  6. package/crates/unicli-atspi/src/errors.rs +213 -0
  7. package/crates/unicli-atspi/src/input.rs +1004 -0
  8. package/crates/unicli-atspi/src/invoke.rs +1132 -0
  9. package/crates/unicli-atspi/src/main.rs +130 -0
  10. package/crates/unicli-atspi/src/refs.rs +24 -0
  11. package/crates/unicli-atspi/src/screenshot.rs +756 -0
  12. package/crates/unicli-atspi/src/tree.rs +2319 -0
  13. package/crates/unicli-shared/Cargo.toml +13 -0
  14. package/crates/unicli-shared/src/lib.rs +77 -0
  15. package/crates/unicli-uia/Cargo.toml +29 -0
  16. package/crates/unicli-uia/README.md +6 -0
  17. package/crates/unicli-uia/src/errors.rs +179 -0
  18. package/crates/unicli-uia/src/input.rs +790 -0
  19. package/crates/unicli-uia/src/invoke.rs +977 -0
  20. package/crates/unicli-uia/src/main.rs +130 -0
  21. package/crates/unicli-uia/src/refs.rs +24 -0
  22. package/crates/unicli-uia/src/screenshot.rs +685 -0
  23. package/crates/unicli-uia/src/tree.rs +2135 -0
  24. package/dist/adapters/macos/actions.d.ts +9 -0
  25. package/dist/adapters/macos/actions.d.ts.map +1 -0
  26. package/dist/adapters/macos/actions.js +55 -0
  27. package/dist/adapters/macos/actions.js.map +1 -0
  28. package/dist/browser/bridge.d.ts +2 -0
  29. package/dist/browser/bridge.d.ts.map +1 -1
  30. package/dist/browser/bridge.js +39 -0
  31. package/dist/browser/bridge.js.map +1 -1
  32. package/dist/browser/cdp-client.d.ts +2 -0
  33. package/dist/browser/cdp-client.d.ts.map +1 -1
  34. package/dist/browser/cdp-client.js +7 -0
  35. package/dist/browser/cdp-client.js.map +1 -1
  36. package/dist/browser/page.d.ts +2 -0
  37. package/dist/browser/page.d.ts.map +1 -1
  38. package/dist/browser/page.js +35 -0
  39. package/dist/browser/page.js.map +1 -1
  40. package/dist/cli.d.ts.map +1 -1
  41. package/dist/cli.js +13 -1
  42. package/dist/cli.js.map +1 -1
  43. package/dist/commands/approvals.d.ts +3 -0
  44. package/dist/commands/approvals.d.ts.map +1 -0
  45. package/dist/commands/approvals.js +123 -0
  46. package/dist/commands/approvals.js.map +1 -0
  47. package/dist/commands/browser-operator-runtime.d.ts.map +1 -1
  48. package/dist/commands/browser-operator-runtime.js +1 -0
  49. package/dist/commands/browser-operator-runtime.js.map +1 -1
  50. package/dist/commands/browser-operator.d.ts.map +1 -1
  51. package/dist/commands/browser-operator.js +84 -12
  52. package/dist/commands/browser-operator.js.map +1 -1
  53. package/dist/commands/compute.d.ts +3 -0
  54. package/dist/commands/compute.d.ts.map +1 -0
  55. package/dist/commands/compute.js +324 -0
  56. package/dist/commands/compute.js.map +1 -0
  57. package/dist/commands/dispatch.d.ts.map +1 -1
  58. package/dist/commands/dispatch.js +10 -4
  59. package/dist/commands/dispatch.js.map +1 -1
  60. package/dist/commands/doctor-compute.d.ts +38 -0
  61. package/dist/commands/doctor-compute.d.ts.map +1 -0
  62. package/dist/commands/doctor-compute.js +376 -0
  63. package/dist/commands/doctor-compute.js.map +1 -0
  64. package/dist/commands/lint.d.ts.map +1 -1
  65. package/dist/commands/lint.js +69 -1
  66. package/dist/commands/lint.js.map +1 -1
  67. package/dist/commands/mcp.d.ts.map +1 -1
  68. package/dist/commands/mcp.js +4 -0
  69. package/dist/commands/mcp.js.map +1 -1
  70. package/dist/commands/runs.d.ts +3 -0
  71. package/dist/commands/runs.d.ts.map +1 -0
  72. package/dist/commands/runs.js +367 -0
  73. package/dist/commands/runs.js.map +1 -0
  74. package/dist/core/envelope.d.ts +8 -0
  75. package/dist/core/envelope.d.ts.map +1 -1
  76. package/dist/core/envelope.js +1 -0
  77. package/dist/core/envelope.js.map +1 -1
  78. package/dist/discovery/aliases.d.ts.map +1 -1
  79. package/dist/discovery/aliases.js +15 -0
  80. package/dist/discovery/aliases.js.map +1 -1
  81. package/dist/discovery/loader.d.ts.map +1 -1
  82. package/dist/discovery/loader.js +9 -0
  83. package/dist/discovery/loader.js.map +1 -1
  84. package/dist/discovery/macos-dynamic.d.ts +58 -0
  85. package/dist/discovery/macos-dynamic.d.ts.map +1 -0
  86. package/dist/discovery/macos-dynamic.js +429 -0
  87. package/dist/discovery/macos-dynamic.js.map +1 -0
  88. package/dist/discovery/search.d.ts.map +1 -1
  89. package/dist/discovery/search.js +152 -3
  90. package/dist/discovery/search.js.map +1 -1
  91. package/dist/electron-apps.d.ts +1 -0
  92. package/dist/electron-apps.d.ts.map +1 -1
  93. package/dist/electron-apps.js +1 -0
  94. package/dist/electron-apps.js.map +1 -1
  95. package/dist/engine/approval-store.d.ts +43 -0
  96. package/dist/engine/approval-store.d.ts.map +1 -0
  97. package/dist/engine/approval-store.js +193 -0
  98. package/dist/engine/approval-store.js.map +1 -0
  99. package/dist/engine/browser/action-evidence.d.ts +2 -0
  100. package/dist/engine/browser/action-evidence.d.ts.map +1 -1
  101. package/dist/engine/browser/action-evidence.js +35 -1
  102. package/dist/engine/browser/action-evidence.js.map +1 -1
  103. package/dist/engine/browser/evidence.d.ts +22 -0
  104. package/dist/engine/browser/evidence.d.ts.map +1 -1
  105. package/dist/engine/browser/evidence.js +72 -0
  106. package/dist/engine/browser/evidence.js.map +1 -1
  107. package/dist/engine/browser/session-lease.d.ts +53 -0
  108. package/dist/engine/browser/session-lease.d.ts.map +1 -0
  109. package/dist/engine/browser/session-lease.js +100 -0
  110. package/dist/engine/browser/session-lease.js.map +1 -0
  111. package/dist/engine/browser/session-lock.d.ts +17 -0
  112. package/dist/engine/browser/session-lock.d.ts.map +1 -0
  113. package/dist/engine/browser/session-lock.js +114 -0
  114. package/dist/engine/browser/session-lock.js.map +1 -0
  115. package/dist/engine/browser/session-runtime.d.ts +10 -0
  116. package/dist/engine/browser/session-runtime.d.ts.map +1 -0
  117. package/dist/engine/browser/session-runtime.js +87 -0
  118. package/dist/engine/browser/session-runtime.js.map +1 -0
  119. package/dist/engine/capability-policy.d.ts +13 -2
  120. package/dist/engine/capability-policy.d.ts.map +1 -1
  121. package/dist/engine/capability-policy.js +113 -3
  122. package/dist/engine/capability-policy.js.map +1 -1
  123. package/dist/engine/executor.d.ts +8 -3
  124. package/dist/engine/executor.d.ts.map +1 -1
  125. package/dist/engine/executor.js +9 -2
  126. package/dist/engine/executor.js.map +1 -1
  127. package/dist/engine/kernel/execute.d.ts +1 -0
  128. package/dist/engine/kernel/execute.d.ts.map +1 -1
  129. package/dist/engine/kernel/execute.js +125 -3
  130. package/dist/engine/kernel/execute.js.map +1 -1
  131. package/dist/engine/kernel/types.d.ts +13 -0
  132. package/dist/engine/kernel/types.d.ts.map +1 -1
  133. package/dist/engine/operation-policy.d.ts +9 -1
  134. package/dist/engine/operation-policy.d.ts.map +1 -1
  135. package/dist/engine/operation-policy.js +6 -2
  136. package/dist/engine/operation-policy.js.map +1 -1
  137. package/dist/engine/permission-rules.d.ts +43 -0
  138. package/dist/engine/permission-rules.d.ts.map +1 -0
  139. package/dist/engine/permission-rules.js +401 -0
  140. package/dist/engine/permission-rules.js.map +1 -0
  141. package/dist/engine/permission-runtime.d.ts +11 -0
  142. package/dist/engine/permission-runtime.d.ts.map +1 -0
  143. package/dist/engine/permission-runtime.js +21 -0
  144. package/dist/engine/permission-runtime.js.map +1 -0
  145. package/dist/engine/repair/remedies.d.ts +4 -0
  146. package/dist/engine/repair/remedies.d.ts.map +1 -0
  147. package/dist/engine/repair/remedies.js +169 -0
  148. package/dist/engine/repair/remedies.js.map +1 -0
  149. package/dist/engine/runtime-resource-guard.d.ts +23 -0
  150. package/dist/engine/runtime-resource-guard.d.ts.map +1 -0
  151. package/dist/engine/runtime-resource-guard.js +85 -0
  152. package/dist/engine/runtime-resource-guard.js.map +1 -0
  153. package/dist/engine/session/args.d.ts +3 -0
  154. package/dist/engine/session/args.d.ts.map +1 -0
  155. package/dist/engine/session/args.js +17 -0
  156. package/dist/engine/session/args.js.map +1 -0
  157. package/dist/engine/session/compare.d.ts +92 -0
  158. package/dist/engine/session/compare.d.ts.map +1 -0
  159. package/dist/engine/session/compare.js +324 -0
  160. package/dist/engine/session/compare.js.map +1 -0
  161. package/dist/engine/session/environment.d.ts +4 -0
  162. package/dist/engine/session/environment.d.ts.map +1 -0
  163. package/dist/engine/session/environment.js +25 -0
  164. package/dist/engine/session/environment.js.map +1 -0
  165. package/dist/engine/session/events.d.ts +2 -0
  166. package/dist/engine/session/events.d.ts.map +1 -1
  167. package/dist/engine/session/events.js +12 -0
  168. package/dist/engine/session/events.js.map +1 -1
  169. package/dist/engine/session/query.d.ts +47 -0
  170. package/dist/engine/session/query.d.ts.map +1 -0
  171. package/dist/engine/session/query.js +299 -0
  172. package/dist/engine/session/query.js.map +1 -0
  173. package/dist/engine/session/replay.d.ts +35 -0
  174. package/dist/engine/session/replay.d.ts.map +1 -0
  175. package/dist/engine/session/replay.js +144 -0
  176. package/dist/engine/session/replay.js.map +1 -0
  177. package/dist/engine/session/run-loop.d.ts.map +1 -1
  178. package/dist/engine/session/run-loop.js +62 -23
  179. package/dist/engine/session/run-loop.js.map +1 -1
  180. package/dist/engine/session/store.d.ts +7 -0
  181. package/dist/engine/session/store.d.ts.map +1 -1
  182. package/dist/engine/session/store.js +131 -1
  183. package/dist/engine/session/store.js.map +1 -1
  184. package/dist/engine/session/types.d.ts +3 -1
  185. package/dist/engine/session/types.d.ts.map +1 -1
  186. package/dist/engine/steps/compute.d.ts +41 -0
  187. package/dist/engine/steps/compute.d.ts.map +1 -0
  188. package/dist/engine/steps/compute.js +55 -0
  189. package/dist/engine/steps/compute.js.map +1 -0
  190. package/dist/engine/steps/desktop-ax.d.ts +8 -0
  191. package/dist/engine/steps/desktop-ax.d.ts.map +1 -1
  192. package/dist/engine/steps/desktop-ax.js +16 -0
  193. package/dist/engine/steps/desktop-ax.js.map +1 -1
  194. package/dist/engine/steps/desktop-sidecar.d.ts +49 -0
  195. package/dist/engine/steps/desktop-sidecar.d.ts.map +1 -0
  196. package/dist/engine/steps/desktop-sidecar.js +50 -0
  197. package/dist/engine/steps/desktop-sidecar.js.map +1 -0
  198. package/dist/engine/steps/download.d.ts +1 -1
  199. package/dist/engine/steps/download.d.ts.map +1 -1
  200. package/dist/engine/steps/download.js +24 -2
  201. package/dist/engine/steps/download.js.map +1 -1
  202. package/dist/engine/steps/exec.d.ts +1 -1
  203. package/dist/engine/steps/exec.d.ts.map +1 -1
  204. package/dist/engine/steps/exec.js +23 -7
  205. package/dist/engine/steps/exec.js.map +1 -1
  206. package/dist/engine/steps/fetch-text.d.ts +1 -1
  207. package/dist/engine/steps/fetch-text.d.ts.map +1 -1
  208. package/dist/engine/steps/fetch-text.js +12 -4
  209. package/dist/engine/steps/fetch-text.js.map +1 -1
  210. package/dist/engine/steps/fetch.d.ts +2 -1
  211. package/dist/engine/steps/fetch.d.ts.map +1 -1
  212. package/dist/engine/steps/fetch.js +29 -6
  213. package/dist/engine/steps/fetch.js.map +1 -1
  214. package/dist/engine/steps/index.d.ts +2 -0
  215. package/dist/engine/steps/index.d.ts.map +1 -1
  216. package/dist/engine/steps/index.js +2 -0
  217. package/dist/engine/steps/index.js.map +1 -1
  218. package/dist/engine/steps/navigate.d.ts +1 -1
  219. package/dist/engine/steps/navigate.d.ts.map +1 -1
  220. package/dist/engine/steps/navigate.js +29 -2
  221. package/dist/engine/steps/navigate.js.map +1 -1
  222. package/dist/fast-path.d.ts.map +1 -1
  223. package/dist/fast-path.js +96 -12
  224. package/dist/fast-path.js.map +1 -1
  225. package/dist/manifest-compact.txt +2 -2
  226. package/dist/manifest-search.json +1 -1
  227. package/dist/manifest.json +1024 -1
  228. package/dist/mcp/handler.d.ts +2 -2
  229. package/dist/mcp/handler.d.ts.map +1 -1
  230. package/dist/mcp/handler.js +59 -5
  231. package/dist/mcp/handler.js.map +1 -1
  232. package/dist/mcp/profiles/computer-use.d.ts +4 -0
  233. package/dist/mcp/profiles/computer-use.d.ts.map +1 -0
  234. package/dist/mcp/profiles/computer-use.js +305 -0
  235. package/dist/mcp/profiles/computer-use.js.map +1 -0
  236. package/dist/mcp/server.d.ts.map +1 -1
  237. package/dist/mcp/server.js +30 -6
  238. package/dist/mcp/server.js.map +1 -1
  239. package/dist/mcp/tools.d.ts +9 -0
  240. package/dist/mcp/tools.d.ts.map +1 -1
  241. package/dist/mcp/tools.js +20 -0
  242. package/dist/mcp/tools.js.map +1 -1
  243. package/dist/output/envelope.d.ts +6 -0
  244. package/dist/output/envelope.d.ts.map +1 -1
  245. package/dist/output/envelope.js.map +1 -1
  246. package/dist/output/error-map.d.ts.map +1 -1
  247. package/dist/output/error-map.js +4 -0
  248. package/dist/output/error-map.js.map +1 -1
  249. package/dist/registry.d.ts +1 -0
  250. package/dist/registry.d.ts.map +1 -1
  251. package/dist/registry.js +5 -0
  252. package/dist/registry.js.map +1 -1
  253. package/dist/transport/adapters/cdp-browser.d.ts +38 -2
  254. package/dist/transport/adapters/cdp-browser.d.ts.map +1 -1
  255. package/dist/transport/adapters/cdp-browser.js +349 -22
  256. package/dist/transport/adapters/cdp-browser.js.map +1 -1
  257. package/dist/transport/adapters/desktop-atspi.d.ts +23 -17
  258. package/dist/transport/adapters/desktop-atspi.d.ts.map +1 -1
  259. package/dist/transport/adapters/desktop-atspi.js +143 -32
  260. package/dist/transport/adapters/desktop-atspi.js.map +1 -1
  261. package/dist/transport/adapters/desktop-ax-helpers.d.ts +24 -0
  262. package/dist/transport/adapters/desktop-ax-helpers.d.ts.map +1 -0
  263. package/dist/transport/adapters/desktop-ax-helpers.js +190 -0
  264. package/dist/transport/adapters/desktop-ax-helpers.js.map +1 -0
  265. package/dist/transport/adapters/desktop-ax-swift.d.ts +13 -0
  266. package/dist/transport/adapters/desktop-ax-swift.d.ts.map +1 -1
  267. package/dist/transport/adapters/desktop-ax-swift.js +176 -2
  268. package/dist/transport/adapters/desktop-ax-swift.js.map +1 -1
  269. package/dist/transport/adapters/desktop-ax.d.ts +11 -2
  270. package/dist/transport/adapters/desktop-ax.d.ts.map +1 -1
  271. package/dist/transport/adapters/desktop-ax.js +131 -16
  272. package/dist/transport/adapters/desktop-ax.js.map +1 -1
  273. package/dist/transport/adapters/desktop-sidecar-errors.d.ts +3 -0
  274. package/dist/transport/adapters/desktop-sidecar-errors.d.ts.map +1 -0
  275. package/dist/transport/adapters/desktop-sidecar-errors.js +34 -0
  276. package/dist/transport/adapters/desktop-sidecar-errors.js.map +1 -0
  277. package/dist/transport/adapters/desktop-sidecar-snapshot.d.ts +10 -0
  278. package/dist/transport/adapters/desktop-sidecar-snapshot.d.ts.map +1 -0
  279. package/dist/transport/adapters/desktop-sidecar-snapshot.js +89 -0
  280. package/dist/transport/adapters/desktop-sidecar-snapshot.js.map +1 -0
  281. package/dist/transport/adapters/desktop-uia.d.ts +23 -17
  282. package/dist/transport/adapters/desktop-uia.d.ts.map +1 -1
  283. package/dist/transport/adapters/desktop-uia.js +142 -32
  284. package/dist/transport/adapters/desktop-uia.js.map +1 -1
  285. package/dist/transport/adapters/subprocess.d.ts +7 -0
  286. package/dist/transport/adapters/subprocess.d.ts.map +1 -1
  287. package/dist/transport/adapters/subprocess.js +64 -0
  288. package/dist/transport/adapters/subprocess.js.map +1 -1
  289. package/dist/transport/bus.d.ts +2 -0
  290. package/dist/transport/bus.d.ts.map +1 -1
  291. package/dist/transport/bus.js +7 -11
  292. package/dist/transport/bus.js.map +1 -1
  293. package/dist/transport/capability.d.ts.map +1 -1
  294. package/dist/transport/capability.js +123 -98
  295. package/dist/transport/capability.js.map +1 -1
  296. package/dist/transport/cascade.d.ts +5 -0
  297. package/dist/transport/cascade.d.ts.map +1 -0
  298. package/dist/transport/cascade.js +550 -0
  299. package/dist/transport/cascade.js.map +1 -0
  300. package/dist/transport/cdp-session.d.ts +11 -0
  301. package/dist/transport/cdp-session.d.ts.map +1 -0
  302. package/dist/transport/cdp-session.js +52 -0
  303. package/dist/transport/cdp-session.js.map +1 -0
  304. package/dist/transport/refs.d.ts +51 -0
  305. package/dist/transport/refs.d.ts.map +1 -0
  306. package/dist/transport/refs.js +135 -0
  307. package/dist/transport/refs.js.map +1 -0
  308. package/dist/transport/sidecar-binary.d.ts +18 -0
  309. package/dist/transport/sidecar-binary.d.ts.map +1 -0
  310. package/dist/transport/sidecar-binary.js +55 -0
  311. package/dist/transport/sidecar-binary.js.map +1 -0
  312. package/dist/transport/sidecar.d.ts +35 -0
  313. package/dist/transport/sidecar.d.ts.map +1 -0
  314. package/dist/transport/sidecar.js +134 -0
  315. package/dist/transport/sidecar.js.map +1 -0
  316. package/dist/transport/snapshot-encoder.d.ts +34 -0
  317. package/dist/transport/snapshot-encoder.d.ts.map +1 -0
  318. package/dist/transport/snapshot-encoder.js +139 -0
  319. package/dist/transport/snapshot-encoder.js.map +1 -0
  320. package/dist/transport/types.d.ts +6 -1
  321. package/dist/transport/types.d.ts.map +1 -1
  322. package/dist/types.d.ts +2 -0
  323. package/dist/types.d.ts.map +1 -1
  324. package/dist/types.js.map +1 -1
  325. package/docs/mcp/clients/claude-code.md +29 -0
  326. package/docs/mcp/clients/claude-desktop.md +47 -0
  327. package/docs/mcp/clients/codex.md +29 -0
  328. package/docs/mcp/clients/cursor.md +38 -0
  329. package/docs/mcp/clients/gemini-cli.md +38 -0
  330. package/docs/operate/compute.md +172 -0
  331. package/docs/operate/electron.md +87 -0
  332. package/docs/operate/focus-behavior.md +40 -0
  333. package/docs/operate/troubleshooting.md +379 -0
  334. package/package.json +29 -4
  335. package/src/adapters/juejin/hot.test.ts +25 -0
  336. package/src/adapters/juejin/hot.yaml +52 -0
  337. package/src/adapters/juejin/search.test.ts +27 -0
  338. package/src/adapters/juejin/search.yaml +58 -0
  339. package/src/adapters/leetcode/discuss-search.test.ts +29 -0
  340. package/src/adapters/leetcode/discuss-search.yaml +56 -0
  341. package/src/adapters/macos/actions.ts +63 -0
@@ -0,0 +1,13 @@
1
+ [package]
2
+ name = "unicli-shared"
3
+ version.workspace = true
4
+ edition.workspace = true
5
+ rust-version.workspace = true
6
+ license.workspace = true
7
+ homepage.workspace = true
8
+ repository.workspace = true
9
+
10
+ [dependencies]
11
+ serde.workspace = true
12
+ serde_json.workspace = true
13
+ thiserror.workspace = true
@@ -0,0 +1,77 @@
1
+ use serde::{Deserialize, Serialize};
2
+ use serde_json::Value;
3
+
4
+ pub const PROTOCOL_VERSION: &str = "compute-sidecar.v1";
5
+
6
+ #[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
7
+ pub struct SidecarRequest {
8
+ pub id: u64,
9
+ pub kind: String,
10
+ #[serde(default)]
11
+ pub params: Value,
12
+ }
13
+
14
+ #[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
15
+ pub struct SidecarResponse {
16
+ pub id: u64,
17
+ pub kind: String,
18
+ pub ok: bool,
19
+ #[serde(default, skip_serializing_if = "Option::is_none")]
20
+ pub data: Option<Value>,
21
+ #[serde(default, skip_serializing_if = "Option::is_none")]
22
+ pub error: Option<SidecarError>,
23
+ }
24
+
25
+ #[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
26
+ pub struct SidecarError {
27
+ pub transport: String,
28
+ pub action: String,
29
+ pub reason: String,
30
+ pub suggestion: String,
31
+ pub minimum_capability: String,
32
+ pub exit_code: u8,
33
+ #[serde(default, skip_serializing_if = "Option::is_none")]
34
+ pub stable_token: Option<String>,
35
+ #[serde(default, skip_serializing_if = "Option::is_none")]
36
+ pub r#ref: Option<String>,
37
+ }
38
+
39
+ impl SidecarResponse {
40
+ pub fn ok(id: u64, kind: impl Into<String>, data: impl Into<Value>) -> Self {
41
+ Self {
42
+ id,
43
+ kind: kind.into(),
44
+ ok: true,
45
+ data: Some(data.into()),
46
+ error: None,
47
+ }
48
+ }
49
+
50
+ pub fn error(
51
+ id: u64,
52
+ kind: impl Into<String>,
53
+ transport: impl Into<String>,
54
+ reason: impl Into<String>,
55
+ suggestion: impl Into<String>,
56
+ exit_code: u8,
57
+ ) -> Self {
58
+ let kind = kind.into();
59
+ let transport = transport.into();
60
+ Self {
61
+ id,
62
+ kind: kind.clone(),
63
+ ok: false,
64
+ data: None,
65
+ error: Some(SidecarError {
66
+ action: kind.clone(),
67
+ minimum_capability: format!("{transport}.{kind}"),
68
+ transport,
69
+ reason: reason.into(),
70
+ suggestion: suggestion.into(),
71
+ exit_code,
72
+ stable_token: None,
73
+ r#ref: None,
74
+ }),
75
+ }
76
+ }
77
+ }
@@ -0,0 +1,29 @@
1
+ [package]
2
+ name = "unicli-uia"
3
+ version.workspace = true
4
+ edition.workspace = true
5
+ rust-version.workspace = true
6
+ license.workspace = true
7
+ homepage.workspace = true
8
+ repository.workspace = true
9
+
10
+ [[bin]]
11
+ name = "unicli-uia"
12
+ path = "src/main.rs"
13
+
14
+ [dependencies]
15
+ anyhow.workspace = true
16
+ clap.workspace = true
17
+ serde.workspace = true
18
+ serde_json.workspace = true
19
+ tokio.workspace = true
20
+ tracing.workspace = true
21
+ tracing-subscriber.workspace = true
22
+ unicli-shared.workspace = true
23
+
24
+ [target.'cfg(target_os = "windows")'.dependencies]
25
+ windows = { version = "0.58", features = [
26
+ "Win32_Foundation",
27
+ "Win32_System_Com",
28
+ "Win32_UI_Accessibility",
29
+ ] }
@@ -0,0 +1,6 @@
1
+ # unicli-uia
2
+
3
+ Windows UI Automation sidecar for Uni-CLI compute.
4
+
5
+ P0 only establishes the buildable crate. The JSON-Lines stdio protocol and UIA
6
+ actions land in P3.
@@ -0,0 +1,179 @@
1
+ use serde_json::Value;
2
+ use unicli_shared::{SidecarError, SidecarResponse};
3
+
4
+ pub type HandlerResult = Result<Value, UiaError>;
5
+
6
+ #[derive(Debug, Clone)]
7
+ pub struct UiaError {
8
+ reason: String,
9
+ suggestion: String,
10
+ minimum_capability: Option<String>,
11
+ r#ref: Option<String>,
12
+ exit_code: u8,
13
+ }
14
+
15
+ impl UiaError {
16
+ pub fn unavailable(reason: impl Into<String>) -> Self {
17
+ Self {
18
+ reason: reason.into(),
19
+ suggestion: "run on Windows with the native UIA backend available, or fall back to CUA"
20
+ .into(),
21
+ minimum_capability: None,
22
+ r#ref: None,
23
+ exit_code: 69,
24
+ }
25
+ }
26
+
27
+ pub fn invalid_input(reason: impl Into<String>) -> Self {
28
+ Self {
29
+ reason: reason.into(),
30
+ suggestion: "check the compute command arguments and retry".into(),
31
+ minimum_capability: Some("desktop-uia.invalid_input".into()),
32
+ r#ref: None,
33
+ exit_code: 78,
34
+ }
35
+ }
36
+
37
+ #[allow(dead_code)] // Used by native Windows UIA handlers.
38
+ pub fn no_element(r#ref: impl Into<String>) -> Self {
39
+ let r#ref = r#ref.into();
40
+ Self {
41
+ reason: format!("no UIA element matched {ref}"),
42
+ suggestion: "re-snapshot; the ref may be stale".into(),
43
+ minimum_capability: Some("desktop-uia.no_element".into()),
44
+ r#ref: Some(r#ref),
45
+ exit_code: 66,
46
+ }
47
+ }
48
+
49
+ #[allow(dead_code)] // Used by native Windows UIA handlers.
50
+ pub fn not_invokable(r#ref: impl Into<String>) -> Self {
51
+ let r#ref = r#ref.into();
52
+ Self {
53
+ reason: format!("UIA element {ref} does not expose Invoke"),
54
+ suggestion: "try set-value, press, or focus before retrying".into(),
55
+ minimum_capability: Some("desktop-uia.not_invokable".into()),
56
+ r#ref: Some(r#ref),
57
+ exit_code: 69,
58
+ }
59
+ }
60
+
61
+ #[allow(dead_code)] // Used by the native Windows UIA handlers for UIAccess failures.
62
+ pub fn permission(reason: impl Into<String>) -> Self {
63
+ Self {
64
+ reason: reason.into(),
65
+ suggestion: "grant UIAccess or run from an elevated terminal".into(),
66
+ minimum_capability: Some("desktop-uia.permission".into()),
67
+ r#ref: None,
68
+ exit_code: 77,
69
+ }
70
+ }
71
+
72
+ #[allow(dead_code)] // Used by the native Windows UIA handlers for bounded polls.
73
+ pub fn timeout(reason: impl Into<String>) -> Self {
74
+ Self {
75
+ reason: reason.into(),
76
+ suggestion: "retry the command; run UNICLI_TRACE=1 unicli doctor compute if it repeats"
77
+ .into(),
78
+ minimum_capability: Some("desktop-uia.timeout".into()),
79
+ r#ref: None,
80
+ exit_code: 75,
81
+ }
82
+ }
83
+ }
84
+
85
+ pub trait IntoSidecarResponse {
86
+ fn into_response(self, id: u64, kind: String) -> SidecarResponse;
87
+ }
88
+
89
+ impl IntoSidecarResponse for HandlerResult {
90
+ fn into_response(self, id: u64, kind: String) -> SidecarResponse {
91
+ match self {
92
+ Ok(data) => SidecarResponse::ok(id, kind, data),
93
+ Err(err) => {
94
+ let minimum_capability = err
95
+ .minimum_capability
96
+ .unwrap_or_else(|| format!("desktop-uia.{kind}"));
97
+ SidecarResponse {
98
+ id,
99
+ kind: kind.clone(),
100
+ ok: false,
101
+ data: None,
102
+ error: Some(SidecarError {
103
+ transport: "desktop-uia".into(),
104
+ action: kind,
105
+ reason: err.reason,
106
+ suggestion: err.suggestion,
107
+ minimum_capability,
108
+ exit_code: err.exit_code,
109
+ stable_token: None,
110
+ r#ref: err.r#ref,
111
+ }),
112
+ }
113
+ }
114
+ }
115
+ }
116
+ }
117
+
118
+ pub fn backend_unavailable() -> UiaError {
119
+ if cfg!(target_os = "windows") {
120
+ UiaError::unavailable(backend_unavailable_reason("windows"))
121
+ } else {
122
+ UiaError::unavailable(backend_unavailable_reason(std::env::consts::OS))
123
+ }
124
+ }
125
+
126
+ fn backend_unavailable_reason(target_os: &str) -> String {
127
+ if target_os == "windows" {
128
+ "Windows UIA backend is unavailable for this request".into()
129
+ } else {
130
+ format!("desktop-uia is only available on Windows; current target is {target_os}")
131
+ }
132
+ }
133
+
134
+ #[cfg(test)]
135
+ mod tests {
136
+ use super::*;
137
+
138
+ fn error_for(err: UiaError) -> unicli_shared::SidecarError {
139
+ let response = Err::<Value, _>(err).into_response(7, "uia_invoke".into());
140
+ response.error.expect("error response")
141
+ }
142
+
143
+ #[test]
144
+ fn no_element_uses_semantic_minimum_capability() {
145
+ let error = error_for(UiaError::no_element("@e42"));
146
+ assert_eq!(error.minimum_capability, "desktop-uia.no_element");
147
+ assert_eq!(error.r#ref.as_deref(), Some("@e42"));
148
+ assert_eq!(error.exit_code, 66);
149
+ }
150
+
151
+ #[test]
152
+ fn not_invokable_uses_semantic_minimum_capability() {
153
+ let error = error_for(UiaError::not_invokable("@e42"));
154
+ assert_eq!(error.minimum_capability, "desktop-uia.not_invokable");
155
+ assert_eq!(error.r#ref.as_deref(), Some("@e42"));
156
+ }
157
+
158
+ #[test]
159
+ fn permission_uses_semantic_minimum_capability() {
160
+ let error = error_for(UiaError::permission("access denied"));
161
+ assert_eq!(error.minimum_capability, "desktop-uia.permission");
162
+ assert_eq!(error.exit_code, 77);
163
+ }
164
+
165
+ #[test]
166
+ fn timeout_uses_semantic_minimum_capability() {
167
+ let error = error_for(UiaError::timeout("UIA request timed out"));
168
+ assert_eq!(error.minimum_capability, "desktop-uia.timeout");
169
+ assert_eq!(error.exit_code, 75);
170
+ }
171
+
172
+ #[test]
173
+ fn backend_unavailable_reason_does_not_claim_native_traversal_pending() {
174
+ let reason = backend_unavailable_reason("windows");
175
+
176
+ assert!(!reason.contains("pending"));
177
+ assert!(reason.contains("unavailable"));
178
+ }
179
+ }