@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,73 @@
1
+ /**
2
+ * A11y bounds resolver — math-only, zero LLM, zero vision.
3
+ *
4
+ * Ported from src/a11y-click-resolver.ts. Decoupled from the legacy
5
+ * `AccessibilityBridge` class — the unified pipeline hands in a resolver
6
+ * function that returns UI element bounds (typically from
7
+ * `PlatformAdapter.findElements`).
8
+ *
9
+ * The critical invariant v0.6.3 earned through real-world bug hunting:
10
+ * reject bounds with `y:-29503` and similar absurd values that some a11y
11
+ * APIs return for hidden/off-screen elements. This file's `isValidBounds`
12
+ * is the guard.
13
+ */
14
+ export interface Bounds {
15
+ x: number;
16
+ y: number;
17
+ width: number;
18
+ height: number;
19
+ }
20
+ export interface UiElementWithBounds {
21
+ name?: string;
22
+ controlType?: string;
23
+ bounds?: Bounds;
24
+ automationId?: string;
25
+ }
26
+ /**
27
+ * Bounds sanity check. Rejects:
28
+ * - zero/negative width or height
29
+ * - off-screen coordinates that indicate hidden elements
30
+ * (e.g. macOS AX returns y:-29503 for some cached-but-invisible items)
31
+ * - out-of-range coordinates > 10k (no real screen is that large; 8K is ~8000)
32
+ */
33
+ export declare function isValidBounds(b: Bounds | undefined): boolean;
34
+ /**
35
+ * Return the integer center of a bounds rect.
36
+ */
37
+ export declare function centerOf(b: Bounds): {
38
+ x: number;
39
+ y: number;
40
+ };
41
+ /**
42
+ * Resolve an element name/automationId to its center coords.
43
+ *
44
+ * `lookup` is a caller-provided function so this module is decoupled from any
45
+ * specific `AccessibilityBridge` or `PlatformAdapter` instance — tests can
46
+ * stub it, and the pipeline can wire whatever adapter it has.
47
+ *
48
+ * Returns null if the element isn't found or its bounds fail the sanity
49
+ * check. Callers should fall back to OCR-based coord resolution on null.
50
+ */
51
+ export declare function resolveByName(name: string, lookup: (q: {
52
+ name?: string;
53
+ controlType?: string;
54
+ processId?: number;
55
+ }) => Promise<UiElementWithBounds[]>, opts?: {
56
+ controlType?: string;
57
+ processId?: number;
58
+ }): Promise<{
59
+ x: number;
60
+ y: number;
61
+ } | null>;
62
+ /**
63
+ * Resolve by a11y automationId (Windows UIA only today; noop elsewhere).
64
+ */
65
+ export declare function resolveById(automationId: string, lookup: (q: {
66
+ automationId?: string;
67
+ processId?: number;
68
+ }) => Promise<UiElementWithBounds[]>, opts?: {
69
+ processId?: number;
70
+ }): Promise<{
71
+ x: number;
72
+ y: number;
73
+ } | null>;
@@ -0,0 +1,76 @@
1
+ "use strict";
2
+ /**
3
+ * A11y bounds resolver — math-only, zero LLM, zero vision.
4
+ *
5
+ * Ported from src/a11y-click-resolver.ts. Decoupled from the legacy
6
+ * `AccessibilityBridge` class — the unified pipeline hands in a resolver
7
+ * function that returns UI element bounds (typically from
8
+ * `PlatformAdapter.findElements`).
9
+ *
10
+ * The critical invariant v0.6.3 earned through real-world bug hunting:
11
+ * reject bounds with `y:-29503` and similar absurd values that some a11y
12
+ * APIs return for hidden/off-screen elements. This file's `isValidBounds`
13
+ * is the guard.
14
+ */
15
+ Object.defineProperty(exports, "__esModule", { value: true });
16
+ exports.isValidBounds = isValidBounds;
17
+ exports.centerOf = centerOf;
18
+ exports.resolveByName = resolveByName;
19
+ exports.resolveById = resolveById;
20
+ /**
21
+ * Bounds sanity check. Rejects:
22
+ * - zero/negative width or height
23
+ * - off-screen coordinates that indicate hidden elements
24
+ * (e.g. macOS AX returns y:-29503 for some cached-but-invisible items)
25
+ * - out-of-range coordinates > 10k (no real screen is that large; 8K is ~8000)
26
+ */
27
+ function isValidBounds(b) {
28
+ if (!b || b.width <= 0 || b.height <= 0)
29
+ return false;
30
+ if (b.x < -100 || b.y < -100)
31
+ return false;
32
+ if (b.x > 10_000 || b.y > 10_000)
33
+ return false;
34
+ return true;
35
+ }
36
+ /**
37
+ * Return the integer center of a bounds rect.
38
+ */
39
+ function centerOf(b) {
40
+ return {
41
+ x: b.x + Math.floor(b.width / 2),
42
+ y: b.y + Math.floor(b.height / 2),
43
+ };
44
+ }
45
+ /**
46
+ * Resolve an element name/automationId to its center coords.
47
+ *
48
+ * `lookup` is a caller-provided function so this module is decoupled from any
49
+ * specific `AccessibilityBridge` or `PlatformAdapter` instance — tests can
50
+ * stub it, and the pipeline can wire whatever adapter it has.
51
+ *
52
+ * Returns null if the element isn't found or its bounds fail the sanity
53
+ * check. Callers should fall back to OCR-based coord resolution on null.
54
+ */
55
+ async function resolveByName(name, lookup, opts) {
56
+ const results = await lookup({ name, ...opts });
57
+ if (!results?.length)
58
+ return null;
59
+ const first = results[0];
60
+ if (!isValidBounds(first.bounds))
61
+ return null;
62
+ return centerOf(first.bounds);
63
+ }
64
+ /**
65
+ * Resolve by a11y automationId (Windows UIA only today; noop elsewhere).
66
+ */
67
+ async function resolveById(automationId, lookup, opts) {
68
+ const results = await lookup({ automationId, ...opts });
69
+ if (!results?.length)
70
+ return null;
71
+ const first = results[0];
72
+ if (!isValidBounds(first.bounds))
73
+ return null;
74
+ return centerOf(first.bounds);
75
+ }
76
+ //# sourceMappingURL=a11y-resolver.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"a11y-resolver.js","sourceRoot":"","sources":["../../../src/core/sense/a11y-resolver.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;GAYG;;AAuBH,sCAKC;AAKD,4BAKC;AAYD,sCAUC;AAKD,kCAUC;AA3DD;;;;;;GAMG;AACH,SAAgB,aAAa,CAAC,CAAqB;IACjD,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,KAAK,IAAI,CAAC,IAAI,CAAC,CAAC,MAAM,IAAI,CAAC;QAAE,OAAO,KAAK,CAAC;IACtD,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG;QAAE,OAAO,KAAK,CAAC;IAC3C,IAAI,CAAC,CAAC,CAAC,GAAG,MAAM,IAAI,CAAC,CAAC,CAAC,GAAG,MAAM;QAAE,OAAO,KAAK,CAAC;IAC/C,OAAO,IAAI,CAAC;AACd,CAAC;AAED;;GAEG;AACH,SAAgB,QAAQ,CAAC,CAAS;IAChC,OAAO;QACL,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC;QAChC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC;KAClC,CAAC;AACJ,CAAC;AAED;;;;;;;;;GASG;AACI,KAAK,UAAU,aAAa,CACjC,IAAY,EACZ,MAA0G,EAC1G,IAAmD;IAEnD,MAAM,OAAO,GAAG,MAAM,MAAM,CAAC,EAAE,IAAI,EAAE,GAAG,IAAI,EAAE,CAAC,CAAC;IAChD,IAAI,CAAC,OAAO,EAAE,MAAM;QAAE,OAAO,IAAI,CAAC;IAClC,MAAM,KAAK,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;IACzB,IAAI,CAAC,aAAa,CAAC,KAAK,CAAC,MAAM,CAAC;QAAE,OAAO,IAAI,CAAC;IAC9C,OAAO,QAAQ,CAAC,KAAK,CAAC,MAAO,CAAC,CAAC;AACjC,CAAC;AAED;;GAEG;AACI,KAAK,UAAU,WAAW,CAC/B,YAAoB,EACpB,MAA4F,EAC5F,IAA6B;IAE7B,MAAM,OAAO,GAAG,MAAM,MAAM,CAAC,EAAE,YAAY,EAAE,GAAG,IAAI,EAAE,CAAC,CAAC;IACxD,IAAI,CAAC,OAAO,EAAE,MAAM;QAAE,OAAO,IAAI,CAAC;IAClC,MAAM,KAAK,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;IACzB,IAAI,CAAC,aAAa,CAAC,KAAK,CAAC,MAAM,CAAC;QAAE,OAAO,IAAI,CAAC;IAC9C,OAAO,QAAQ,CAAC,KAAK,CAAC,MAAO,CAAC,CAAC;AACjC,CAAC"}
@@ -0,0 +1,41 @@
1
+ /**
2
+ * Snapshot fingerprint — stagnation detection.
3
+ *
4
+ * Ported from src/snapshot-builder.ts. The idea: after every agent action,
5
+ * compute a stable hash of "what's on screen" (structured elements only —
6
+ * not pixels). If the fingerprint doesn't change across N consecutive
7
+ * actions, the agent is stuck doing the same thing.
8
+ *
9
+ * The orchestrator uses this to short-circuit infinite loops. A 2-iteration
10
+ * duplicate fingerprint + a verifier that says "not done" = abort, try a
11
+ * different layer (text-agent → vision-agent → retry).
12
+ */
13
+ import type { SnapshotElement } from './types';
14
+ /**
15
+ * Produce a deterministic short hash of the screen state.
16
+ *
17
+ * Order-insensitive (elements sorted before hash), position-quantized (to 8px
18
+ * buckets) so that sub-pixel jitter from OCR doesn't break the equality.
19
+ *
20
+ * Intentionally NOT based on pixel screenshots — that's what the verifier's
21
+ * pixel-diff signal handles. This is the a11y/OCR-level "same set of named
22
+ * buttons at roughly the same places" fingerprint.
23
+ */
24
+ export declare function fingerprint(elements: SnapshotElement[], activeTitle?: string): string;
25
+ /**
26
+ * A sliding history of recent fingerprints. Reports stagnation when the
27
+ * last `n` fingerprints are identical.
28
+ */
29
+ export declare class FingerprintHistory {
30
+ private readonly maxSize;
31
+ private history;
32
+ constructor(maxSize?: number);
33
+ /** Append a new fingerprint. */
34
+ push(fp: string): void;
35
+ /** Stagnant if the last N entries are all equal and ≥ 2. */
36
+ isStagnant(n?: number): boolean;
37
+ /** Reset after a successful action so the agent gets a fresh window. */
38
+ reset(): void;
39
+ /** Internal — for tests and telemetry. */
40
+ getHistory(): string[];
41
+ }
@@ -0,0 +1,123 @@
1
+ "use strict";
2
+ /**
3
+ * Snapshot fingerprint — stagnation detection.
4
+ *
5
+ * Ported from src/snapshot-builder.ts. The idea: after every agent action,
6
+ * compute a stable hash of "what's on screen" (structured elements only —
7
+ * not pixels). If the fingerprint doesn't change across N consecutive
8
+ * actions, the agent is stuck doing the same thing.
9
+ *
10
+ * The orchestrator uses this to short-circuit infinite loops. A 2-iteration
11
+ * duplicate fingerprint + a verifier that says "not done" = abort, try a
12
+ * different layer (text-agent → vision-agent → retry).
13
+ */
14
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
15
+ if (k2 === undefined) k2 = k;
16
+ var desc = Object.getOwnPropertyDescriptor(m, k);
17
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
18
+ desc = { enumerable: true, get: function() { return m[k]; } };
19
+ }
20
+ Object.defineProperty(o, k2, desc);
21
+ }) : (function(o, m, k, k2) {
22
+ if (k2 === undefined) k2 = k;
23
+ o[k2] = m[k];
24
+ }));
25
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
26
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
27
+ }) : function(o, v) {
28
+ o["default"] = v;
29
+ });
30
+ var __importStar = (this && this.__importStar) || (function () {
31
+ var ownKeys = function(o) {
32
+ ownKeys = Object.getOwnPropertyNames || function (o) {
33
+ var ar = [];
34
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
35
+ return ar;
36
+ };
37
+ return ownKeys(o);
38
+ };
39
+ return function (mod) {
40
+ if (mod && mod.__esModule) return mod;
41
+ var result = {};
42
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
43
+ __setModuleDefault(result, mod);
44
+ return result;
45
+ };
46
+ })();
47
+ Object.defineProperty(exports, "__esModule", { value: true });
48
+ exports.FingerprintHistory = void 0;
49
+ exports.fingerprint = fingerprint;
50
+ const crypto = __importStar(require("crypto"));
51
+ // NOTE on the SHA-1 below: these are NON-credential state checksums for
52
+ // stagnation detection — not password/credential storage. The digests are
53
+ // truncated, held only in-memory for the duration of one task run, and never
54
+ // persisted or transmitted. Secure fields are already excluded upstream
55
+ // (value === undefined). CodeQL's js/insufficient-password-hash flags the
56
+ // `e.value` → SHA-1 flow as a "password hash"; that is a false positive here
57
+ // (a KDF like bcrypt/scrypt would be the wrong tool for a per-frame checksum).
58
+ /**
59
+ * Produce a deterministic short hash of the screen state.
60
+ *
61
+ * Order-insensitive (elements sorted before hash), position-quantized (to 8px
62
+ * buckets) so that sub-pixel jitter from OCR doesn't break the equality.
63
+ *
64
+ * Intentionally NOT based on pixel screenshots — that's what the verifier's
65
+ * pixel-diff signal handles. This is the a11y/OCR-level "same set of named
66
+ * buttons at roughly the same places" fingerprint.
67
+ */
68
+ function fingerprint(elements, activeTitle) {
69
+ // Quantize coords to a grid to absorb OCR jitter.
70
+ const QUANT = 8;
71
+ const quant = (n) => Math.round(n / QUANT) * QUANT;
72
+ const tokens = elements.map(e => {
73
+ const cx = quant(e.x);
74
+ const cy = quant(e.y);
75
+ const role = e.role ?? e.source;
76
+ // Normalize name: trim + collapse whitespace + lowercase
77
+ const name = (e.name ?? '').trim().toLowerCase().replace(/\s+/g, ' ');
78
+ // Include the field VALUE (hashed short, never the raw text — it may be
79
+ // sensitive): typing changes value but not name/role/bounds, so a
80
+ // value-blind fingerprint made every successful type/fill look like "no
81
+ // observable change" and fed false stagnation nudges (audit 2026-06-10,
82
+ // finding D2). Secure fields carry value=undefined and stay excluded.
83
+ const val = e.value ? crypto.createHash('sha1').update(e.value).digest('hex').slice(0, 8) : '';
84
+ return `${role}|${name}|${cx}|${cy}|${val}`;
85
+ });
86
+ tokens.sort(); // order-insensitive
87
+ const payload = (activeTitle ?? '') + '\n' + tokens.join('\n');
88
+ return crypto.createHash('sha1').update(payload).digest('hex').slice(0, 16);
89
+ }
90
+ /**
91
+ * A sliding history of recent fingerprints. Reports stagnation when the
92
+ * last `n` fingerprints are identical.
93
+ */
94
+ class FingerprintHistory {
95
+ maxSize;
96
+ history = [];
97
+ constructor(maxSize = 8) {
98
+ this.maxSize = maxSize;
99
+ }
100
+ /** Append a new fingerprint. */
101
+ push(fp) {
102
+ this.history.push(fp);
103
+ if (this.history.length > this.maxSize)
104
+ this.history.shift();
105
+ }
106
+ /** Stagnant if the last N entries are all equal and ≥ 2. */
107
+ isStagnant(n = 2) {
108
+ if (this.history.length < n)
109
+ return false;
110
+ const tail = this.history.slice(-n);
111
+ return tail.every(fp => fp === tail[0]);
112
+ }
113
+ /** Reset after a successful action so the agent gets a fresh window. */
114
+ reset() {
115
+ this.history = [];
116
+ }
117
+ /** Internal — for tests and telemetry. */
118
+ getHistory() {
119
+ return [...this.history];
120
+ }
121
+ }
122
+ exports.FingerprintHistory = FingerprintHistory;
123
+ //# sourceMappingURL=fingerprint.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fingerprint.js","sourceRoot":"","sources":["../../../src/core/sense/fingerprint.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,70 @@
1
+ /**
2
+ * Rank-before-truncate for a11y snapshots.
3
+ *
4
+ * Problem: Paint's a11y tree had "Pencil" at index 20 (it was NOT truncated),
5
+ * but Explorer / Outlook / Teams can easily spew 200+ a11y nodes where the
6
+ * buttons the agent actually needs sit at indices 80–150. The previous
7
+ * `slice(0, 80)` strategy threw those overboard.
8
+ *
9
+ * This module ranks elements by how likely the agent is to act on them, then
10
+ * the snapshot renderer truncates from the bottom. No app-specific rules —
11
+ * the signals come from accessibility roles and bounding-box geometry,
12
+ * nothing encoded per-app.
13
+ *
14
+ * Signals (additive, all non-app-specific):
15
+ * + Interactive roles (Button, MenuItem, Hyperlink, Edit, ComboBox, Tab,
16
+ * CheckBox, RadioButton, ListItem, TreeItem) get a strong boost.
17
+ * + Named elements (non-empty `name`) beat anonymous ones.
18
+ * + Focused element gets a big boost.
19
+ * + Elements marked `interactive: true` get a small boost.
20
+ * + Smaller elements (typical for buttons / icons) slightly preferred
21
+ * over full-window panes / group containers.
22
+ * + Top-edge and right-edge toolbars get a modest boost (Paint palette,
23
+ * Office ribbon live there).
24
+ * - Containers (Pane, Group, Document, ScrollBar) get a penalty — they
25
+ * hold other interactive nodes but aren't themselves clickable.
26
+ * - Huge elements (> 80% of screen) get a penalty — usually the window
27
+ * body, not a target.
28
+ *
29
+ * The ranker is a pure function of the snapshot element list. It never
30
+ * consults app name / window title / anything app-specific. A new LOB app
31
+ * with exotic roles will rank cleanly because it obeys the same a11y
32
+ * contract every Windows/macOS/Linux UI toolkit does.
33
+ */
34
+ import type { SnapshotElement } from './types';
35
+ export interface RankOpts {
36
+ /** Physical screen width for "huge element" detection. */
37
+ screenWidth?: number;
38
+ /** Physical screen height for "huge element" detection. */
39
+ screenHeight?: number;
40
+ /** Active window processId — elements outside this process get penalized. */
41
+ focusProcessId?: number;
42
+ /** Explicitly-focused element coords, if the adapter reports one. */
43
+ focusPoint?: {
44
+ x: number;
45
+ y: number;
46
+ };
47
+ }
48
+ /**
49
+ * Score one element. Higher = more likely the agent wants to act on it.
50
+ * Pure: no I/O, no app-specific tables.
51
+ */
52
+ export declare function scoreElement(el: SnapshotElement, opts?: RankOpts): number;
53
+ /**
54
+ * Rank elements from most-likely-to-act-on to least. Stable: equal scores
55
+ * preserve document order (often the left-to-right, top-to-bottom order
56
+ * Windows UIA returns, which tends to match visual scan order).
57
+ *
58
+ * Does NOT truncate — callers decide the cap based on their token budget.
59
+ * The snapshot renderer typically calls rank(), then slices the top N.
60
+ */
61
+ export declare function rankElements(elements: SnapshotElement[], opts?: RankOpts): SnapshotElement[];
62
+ /**
63
+ * Debug-friendly: return the top-N with their scores. Used by the
64
+ * observability logger so the user can see WHY "Pencil" ranked 3rd when
65
+ * the tree had 200 elements.
66
+ */
67
+ export declare function rankWithScores(elements: SnapshotElement[], opts?: RankOpts): Array<{
68
+ el: SnapshotElement;
69
+ score: number;
70
+ }>;
@@ -0,0 +1,192 @@
1
+ "use strict";
2
+ /**
3
+ * Rank-before-truncate for a11y snapshots.
4
+ *
5
+ * Problem: Paint's a11y tree had "Pencil" at index 20 (it was NOT truncated),
6
+ * but Explorer / Outlook / Teams can easily spew 200+ a11y nodes where the
7
+ * buttons the agent actually needs sit at indices 80–150. The previous
8
+ * `slice(0, 80)` strategy threw those overboard.
9
+ *
10
+ * This module ranks elements by how likely the agent is to act on them, then
11
+ * the snapshot renderer truncates from the bottom. No app-specific rules —
12
+ * the signals come from accessibility roles and bounding-box geometry,
13
+ * nothing encoded per-app.
14
+ *
15
+ * Signals (additive, all non-app-specific):
16
+ * + Interactive roles (Button, MenuItem, Hyperlink, Edit, ComboBox, Tab,
17
+ * CheckBox, RadioButton, ListItem, TreeItem) get a strong boost.
18
+ * + Named elements (non-empty `name`) beat anonymous ones.
19
+ * + Focused element gets a big boost.
20
+ * + Elements marked `interactive: true` get a small boost.
21
+ * + Smaller elements (typical for buttons / icons) slightly preferred
22
+ * over full-window panes / group containers.
23
+ * + Top-edge and right-edge toolbars get a modest boost (Paint palette,
24
+ * Office ribbon live there).
25
+ * - Containers (Pane, Group, Document, ScrollBar) get a penalty — they
26
+ * hold other interactive nodes but aren't themselves clickable.
27
+ * - Huge elements (> 80% of screen) get a penalty — usually the window
28
+ * body, not a target.
29
+ *
30
+ * The ranker is a pure function of the snapshot element list. It never
31
+ * consults app name / window title / anything app-specific. A new LOB app
32
+ * with exotic roles will rank cleanly because it obeys the same a11y
33
+ * contract every Windows/macOS/Linux UI toolkit does.
34
+ */
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.scoreElement = scoreElement;
37
+ exports.rankElements = rankElements;
38
+ exports.rankWithScores = rankWithScores;
39
+ /**
40
+ * Score weights. Tuned to be monotonic: the sum for a typical interactive
41
+ * button exceeds the sum for a container pane by a healthy margin. Exact
42
+ * numbers matter less than the ordering.
43
+ */
44
+ const ROLE_BOOSTS = {
45
+ // ─── Clickable/commandable ────────────────────────────────
46
+ 'button': 40,
47
+ 'menuitem': 38,
48
+ 'hyperlink': 38,
49
+ 'link': 38,
50
+ 'tab': 32,
51
+ 'checkbox': 30,
52
+ 'radiobutton': 30,
53
+ 'splitbutton': 30,
54
+ 'togglebutton': 30,
55
+ 'listitem': 24,
56
+ 'treeitem': 24,
57
+ 'menubaritem': 30,
58
+ // ─── Editable ─────────────────────────────────────────────
59
+ 'edit': 35,
60
+ 'text': 18, // generic; raised only slightly
61
+ 'combobox': 32,
62
+ 'spinner': 26,
63
+ 'slider': 26,
64
+ 'datepicker': 26,
65
+ // ─── Informational but often targeted ─────────────────────
66
+ 'image': 6,
67
+ 'statictext': 5,
68
+ 'statusbar': 8,
69
+ // ─── Containers (penalized, but not eliminated) ───────────
70
+ 'pane': -12,
71
+ 'group': -8,
72
+ 'document': -10,
73
+ 'scrollbar': -20,
74
+ 'titlebar': -4,
75
+ 'menubar': 0,
76
+ 'toolbar': 6, // toolbars themselves aren't clicked, but they
77
+ // geographically concentrate buttons — keep them
78
+ // visible so the agent has orientation
79
+ 'window': -18,
80
+ };
81
+ /** Extra boost when the element sits along a toolbar edge (top/right). */
82
+ const TOOLBAR_EDGE_BOOST = 6;
83
+ /** Boost for an explicitly focused element. */
84
+ const FOCUSED_BOOST = 25;
85
+ /** Boost for having a readable name. */
86
+ const NAMED_BOOST = 10;
87
+ /** Boost for interactive flag (set by the platform adapter). */
88
+ const INTERACTIVE_FLAG_BOOST = 6;
89
+ /** Penalty for being >= 80% of the screen area. */
90
+ const HUGE_ELEMENT_PENALTY = -25;
91
+ /** Penalty for being 0 bounds (invisible). */
92
+ const ZERO_BOUNDS_PENALTY = -80;
93
+ /**
94
+ * Score one element. Higher = more likely the agent wants to act on it.
95
+ * Pure: no I/O, no app-specific tables.
96
+ */
97
+ function scoreElement(el, opts = {}) {
98
+ let score = 0;
99
+ // Role signal — the single biggest ranker.
100
+ const role = (el.role || '').toLowerCase().replace(/[^a-z]/g, '');
101
+ if (role && role in ROLE_BOOSTS)
102
+ score += ROLE_BOOSTS[role];
103
+ else if (role)
104
+ score += 4; // unknown role gets a small positive (don't zero-weight new a11y roles)
105
+ // Named elements beat anonymous.
106
+ const name = (el.name || '').trim();
107
+ if (name)
108
+ score += NAMED_BOOST;
109
+ // Longer readable names (up to ~30 chars) get a small additional weight.
110
+ if (name.length > 2)
111
+ score += Math.min(name.length, 20) * 0.15;
112
+ // Interactive flag from adapter.
113
+ if (el.interactive)
114
+ score += INTERACTIVE_FLAG_BOOST;
115
+ // A11y source beats OCR — a11y tree entries come with stable roles and
116
+ // names; OCR is often noisy text labels.
117
+ if (el.source === 'a11y')
118
+ score += 4;
119
+ // Geometric sanity:
120
+ const screenW = opts.screenWidth ?? 1920;
121
+ const screenH = opts.screenHeight ?? 1080;
122
+ const screenArea = screenW * screenH;
123
+ const elArea = Math.max(0, el.width) * Math.max(0, el.height);
124
+ if (el.width <= 0 || el.height <= 0) {
125
+ score += ZERO_BOUNDS_PENALTY;
126
+ }
127
+ else if (screenArea > 0 && elArea / screenArea > 0.8) {
128
+ score += HUGE_ELEMENT_PENALTY;
129
+ }
130
+ else {
131
+ // Smaller elements (typical of buttons) get a modest positive. Weighted
132
+ // so a 40×40 button scores +6, a 200×200 control scores ~+2, a big pane
133
+ // scores near 0.
134
+ const normalized = 1 - Math.min(1, elArea / (screenArea / 50));
135
+ score += normalized * 6;
136
+ }
137
+ // Toolbar-edge boost — elements near the top (y < 140) or right
138
+ // (x > screenW - 200) are often command buttons (Paint palette, Office
139
+ // ribbon, sidebar buttons). No app-specific code needed.
140
+ if (el.y < 140)
141
+ score += TOOLBAR_EDGE_BOOST;
142
+ else if (el.x > screenW - 200)
143
+ score += TOOLBAR_EDGE_BOOST * 0.7;
144
+ // Focused element wins big.
145
+ if (opts.focusPoint) {
146
+ const cx = el.x + el.width / 2;
147
+ const cy = el.y + el.height / 2;
148
+ const dx = cx - opts.focusPoint.x;
149
+ const dy = cy - opts.focusPoint.y;
150
+ const dist = Math.hypot(dx, dy);
151
+ // Within 40px — definitely focused.
152
+ if (dist < 40)
153
+ score += FOCUSED_BOOST;
154
+ // Within 200 — nearby / probably related.
155
+ else if (dist < 200)
156
+ score += FOCUSED_BOOST * 0.3;
157
+ }
158
+ // Prefer elements in the focused window's process.
159
+ if (opts.focusProcessId != null && el.processId != null && el.processId !== opts.focusProcessId) {
160
+ score -= 30;
161
+ }
162
+ return score;
163
+ }
164
+ /**
165
+ * Rank elements from most-likely-to-act-on to least. Stable: equal scores
166
+ * preserve document order (often the left-to-right, top-to-bottom order
167
+ * Windows UIA returns, which tends to match visual scan order).
168
+ *
169
+ * Does NOT truncate — callers decide the cap based on their token budget.
170
+ * The snapshot renderer typically calls rank(), then slices the top N.
171
+ */
172
+ function rankElements(elements, opts = {}) {
173
+ // Attach indices to preserve stable order on ties.
174
+ const scored = elements.map((el, i) => ({ el, i, s: scoreElement(el, opts) }));
175
+ scored.sort((a, b) => {
176
+ if (b.s !== a.s)
177
+ return b.s - a.s;
178
+ return a.i - b.i;
179
+ });
180
+ return scored.map(x => x.el);
181
+ }
182
+ /**
183
+ * Debug-friendly: return the top-N with their scores. Used by the
184
+ * observability logger so the user can see WHY "Pencil" ranked 3rd when
185
+ * the tree had 200 elements.
186
+ */
187
+ function rankWithScores(elements, opts = {}) {
188
+ return elements
189
+ .map(el => ({ el, score: scoreElement(el, opts) }))
190
+ .sort((a, b) => b.score - a.score);
191
+ }
192
+ //# sourceMappingURL=rank.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rank.js","sourceRoot":"","sources":["../../../src/core/sense/rank.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,40 @@
1
+ /**
2
+ * Layer C — reactive step discipline. After a consequential action, verify the
3
+ * agent-stated expected effect (hard) or a tolerant "did anything change" net
4
+ * (soft), so the agent never blindly proceeds on an action that didn't take.
5
+ * Pure over its inputs + PlatformAdapter reads (OS-agnostic, unit-testable).
6
+ * See docs/superpowers/specs/2026-06-07-ui-state-compiler-layer-c-design.md.
7
+ */
8
+ import type { PlatformAdapter } from '../../platform/types';
9
+ export interface ReactiveInput {
10
+ /** Raw `expect` arg from the tool call (assertions array), or undefined. */
11
+ expect: unknown;
12
+ /** The tool's own result text + success, to fold the note into. */
13
+ toolText: string;
14
+ toolSuccess: boolean;
15
+ /** Whether the tool is screen-changing (consequential). */
16
+ changesScreen: boolean;
17
+ /** Whether the loop observed a change after the action (fingerprint/pixel). */
18
+ observedChange: boolean;
19
+ adapter: PlatformAdapter;
20
+ /** Lazy OCR reader for ocr_contains assertions; omit when unavailable. */
21
+ ocrText?: () => Promise<string>;
22
+ /** Settle budget for hard checks (ms). Defaults to SETTLE_BUDGET_MS. */
23
+ settleMs?: number;
24
+ }
25
+ /**
26
+ * How long a failing hard check re-polls before declaring a DEVIATION. UIs
27
+ * are asynchronous: a recipient chip resolves via a directory lookup
28
+ * (0.5–3s), window titles update lazily after a save. Declaring DEVIATION
29
+ * off a single immediate check told the model to RETRY actions that had
30
+ * actually taken — a duplicate-send risk on Send/Submit (audit 2026-06-10,
31
+ * finding D1).
32
+ */
33
+ export declare const SETTLE_BUDGET_MS = 2000;
34
+ export declare const SETTLE_INTERVAL_MS = 250;
35
+ /** A modified result (success/text) to replace the tool's, or null = leave as-is. */
36
+ export interface ReactiveOutcome {
37
+ success: boolean;
38
+ text: string;
39
+ }
40
+ export declare function reactiveCheck(input: ReactiveInput): Promise<ReactiveOutcome | null>;