@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,48 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.SETTLE_INTERVAL_MS = exports.SETTLE_BUDGET_MS = void 0;
4
+ exports.reactiveCheck = reactiveCheck;
5
+ const assertions_1 = require("../verify/assertions");
6
+ /**
7
+ * How long a failing hard check re-polls before declaring a DEVIATION. UIs
8
+ * are asynchronous: a recipient chip resolves via a directory lookup
9
+ * (0.5–3s), window titles update lazily after a save. Declaring DEVIATION
10
+ * off a single immediate check told the model to RETRY actions that had
11
+ * actually taken — a duplicate-send risk on Send/Submit (audit 2026-06-10,
12
+ * finding D1).
13
+ */
14
+ exports.SETTLE_BUDGET_MS = 2_000;
15
+ exports.SETTLE_INTERVAL_MS = 250;
16
+ async function reactiveCheck(input) {
17
+ const hasExpect = input.expect !== undefined && input.expect !== null;
18
+ if (hasExpect) {
19
+ const parsed = (0, assertions_1.parseAssertions)(input.expect);
20
+ if ('error' in parsed) {
21
+ return { success: false, text: `${input.toolText}\nexpect rejected: ${parsed.error}` };
22
+ }
23
+ // Poll until the assertions pass or the settle budget runs out — the UI
24
+ // is allowed to take a moment to manifest the effect before we call it
25
+ // a DEVIATION (which tells the model to retry a possibly-taken action).
26
+ const budget = input.settleMs ?? exports.SETTLE_BUDGET_MS;
27
+ const deadline = Date.now() + budget;
28
+ let report = await (0, assertions_1.checkAssertions)(parsed.assertions, { adapter: input.adapter, ocrText: input.ocrText });
29
+ while (!report.ok && Date.now() < deadline) {
30
+ await new Promise(r => setTimeout(r, exports.SETTLE_INTERVAL_MS));
31
+ report = await (0, assertions_1.checkAssertions)(parsed.assertions, { adapter: input.adapter, ocrText: input.ocrText });
32
+ }
33
+ if (report.ok) {
34
+ return { success: input.toolSuccess, text: `${input.toolText} — verified ${report.passed} check(s)` };
35
+ }
36
+ return {
37
+ success: false,
38
+ text: `${input.toolText}\nDEVIATION: ${report.failed}/${report.outcomes.length} expected check(s) failed (still failing after a ${Math.round(budget / 1000)}s settle window) — the action did not achieve its effect; adapt (re-find, retry, or a different approach) before continuing:\n${(0, assertions_1.renderReport)(report)}`,
39
+ };
40
+ }
41
+ // No expect: tolerant soft net — only for a SUCCESSFUL consequential action
42
+ // that produced no observable change. Never fails the action.
43
+ if (input.changesScreen && input.toolSuccess && !input.observedChange) {
44
+ return { success: true, text: `${input.toolText}\n⚠ no observable change — verify it took (pass \`expect\`) or try another approach.` };
45
+ }
46
+ return null;
47
+ }
48
+ //# sourceMappingURL=reactive-check.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"reactive-check.js","sourceRoot":"","sources":["../../../src/core/sense/reactive-check.ts"],"names":[],"mappings":";;;AAyCA,sCAkCC;AAnED,qDAAsF;AAmBtF;;;;;;;GAOG;AACU,QAAA,gBAAgB,GAAG,KAAK,CAAC;AACzB,QAAA,kBAAkB,GAAG,GAAG,CAAC;AAK/B,KAAK,UAAU,aAAa,CAAC,KAAoB;IACtD,MAAM,SAAS,GAAG,KAAK,CAAC,MAAM,KAAK,SAAS,IAAI,KAAK,CAAC,MAAM,KAAK,IAAI,CAAC;IAEtE,IAAI,SAAS,EAAE,CAAC;QACd,MAAM,MAAM,GAAG,IAAA,4BAAe,EAAC,KAAK,CAAC,MAAM,CAAC,CAAC;QAC7C,IAAI,OAAO,IAAI,MAAM,EAAE,CAAC;YACtB,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,GAAG,KAAK,CAAC,QAAQ,sBAAsB,MAAM,CAAC,KAAK,EAAE,EAAE,CAAC;QACzF,CAAC;QACD,wEAAwE;QACxE,uEAAuE;QACvE,wEAAwE;QACxE,MAAM,MAAM,GAAG,KAAK,CAAC,QAAQ,IAAI,wBAAgB,CAAC;QAClD,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,MAAM,CAAC;QACrC,IAAI,MAAM,GAAG,MAAM,IAAA,4BAAe,EAAC,MAAM,CAAC,UAAU,EAAE,EAAE,OAAO,EAAE,KAAK,CAAC,OAAO,EAAE,OAAO,EAAE,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC;QAC1G,OAAO,CAAC,MAAM,CAAC,EAAE,IAAI,IAAI,CAAC,GAAG,EAAE,GAAG,QAAQ,EAAE,CAAC;YAC3C,MAAM,IAAI,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,UAAU,CAAC,CAAC,EAAE,0BAAkB,CAAC,CAAC,CAAC;YAC1D,MAAM,GAAG,MAAM,IAAA,4BAAe,EAAC,MAAM,CAAC,UAAU,EAAE,EAAE,OAAO,EAAE,KAAK,CAAC,OAAO,EAAE,OAAO,EAAE,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC;QACxG,CAAC;QACD,IAAI,MAAM,CAAC,EAAE,EAAE,CAAC;YACd,OAAO,EAAE,OAAO,EAAE,KAAK,CAAC,WAAW,EAAE,IAAI,EAAE,GAAG,KAAK,CAAC,QAAQ,eAAe,MAAM,CAAC,MAAM,WAAW,EAAE,CAAC;QACxG,CAAC;QACD,OAAO;YACL,OAAO,EAAE,KAAK;YACd,IAAI,EAAE,GAAG,KAAK,CAAC,QAAQ,gBAAgB,MAAM,CAAC,MAAM,IAAI,MAAM,CAAC,QAAQ,CAAC,MAAM,oDAAoD,IAAI,CAAC,KAAK,CAAC,MAAM,GAAG,IAAI,CAAC,iIAAiI,IAAA,yBAAY,EAAC,MAAM,CAAC,EAAE;SACnT,CAAC;IACJ,CAAC;IAED,4EAA4E;IAC5E,8DAA8D;IAC9D,IAAI,KAAK,CAAC,aAAa,IAAI,KAAK,CAAC,WAAW,IAAI,CAAC,KAAK,CAAC,cAAc,EAAE,CAAC;QACtE,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,GAAG,KAAK,CAAC,QAAQ,sFAAsF,EAAE,CAAC;IAC1I,CAAC;IAED,OAAO,IAAI,CAAC;AACd,CAAC"}
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Snapshot builder — assembles a structured Snapshot from the PlatformAdapter.
3
+ *
4
+ * Blind-first scope: accessibility tree only. When a11y can describe the
5
+ * screen, the text-agent reads this and picks an action. When a11y can't
6
+ * (empty tree, canvas app, custom rendering), the text-agent emits
7
+ * `cannot_read` and the vision-agent takes over with real pixels.
8
+ *
9
+ * OCR fusion on top of a11y (merging OCR hits with a11y bounds into a single
10
+ * element list) is a cost-saving enhancement we can layer in later without
11
+ * changing the `Snapshot` contract.
12
+ */
13
+ import type { PlatformAdapter } from '../../platform/types';
14
+ import type { Snapshot } from './types';
15
+ /**
16
+ * Capture a structured snapshot. a11y-only for v0.8.1; OCR merge is a
17
+ * future enhancement.
18
+ */
19
+ export declare function captureSnapshot(adapter: PlatformAdapter): Promise<Snapshot>;
@@ -0,0 +1,100 @@
1
+ "use strict";
2
+ /**
3
+ * Snapshot builder — assembles a structured Snapshot from the PlatformAdapter.
4
+ *
5
+ * Blind-first scope: accessibility tree only. When a11y can describe the
6
+ * screen, the text-agent reads this and picks an action. When a11y can't
7
+ * (empty tree, canvas app, custom rendering), the text-agent emits
8
+ * `cannot_read` and the vision-agent takes over with real pixels.
9
+ *
10
+ * OCR fusion on top of a11y (merging OCR hits with a11y bounds into a single
11
+ * element list) is a cost-saving enhancement we can layer in later without
12
+ * changing the `Snapshot` contract.
13
+ */
14
+ Object.defineProperty(exports, "__esModule", { value: true });
15
+ exports.captureSnapshot = captureSnapshot;
16
+ const fingerprint_1 = require("./fingerprint");
17
+ function normPlatform(p) {
18
+ return p === 'darwin' ? 'macos' : p === 'win32' ? 'windows' : 'linux';
19
+ }
20
+ const SECURE_CONTROL_TYPES = new Set([
21
+ // Windows UIA (post "ControlType." strip) and macOS AX (post "AX" strip).
22
+ 'edit', 'passwordbox', 'securefield',
23
+ 'securetextfield', 'passwordfield',
24
+ ]);
25
+ function looksSecure(controlType, name, subrole) {
26
+ // AX subrole is the authoritative macOS signal (role is the generic
27
+ // "TextField"; the secureness is in subrole=AXSecureTextField). Strip any AX
28
+ // prefix before the set test so "SecureTextField" matches (audit 2026-06-11, M2).
29
+ if (subrole && /securetextfield/i.test(subrole))
30
+ return true;
31
+ if (!controlType && !name)
32
+ return false;
33
+ const tLower = (controlType ?? '').replace(/^ax/i, '').toLowerCase();
34
+ const nLower = (name ?? '').toLowerCase();
35
+ if (SECURE_CONTROL_TYPES.has(tLower))
36
+ return true;
37
+ if (/\b(password|passcode|pin|secret|token|api\s*key|credit\s*card|cvv|ssn)\b/.test(nLower))
38
+ return true;
39
+ return false;
40
+ }
41
+ /**
42
+ * Capture a structured snapshot. a11y-only for v0.8.1; OCR merge is a
43
+ * future enhancement.
44
+ */
45
+ async function captureSnapshot(adapter) {
46
+ const capturedAt = Date.now();
47
+ const platform = normPlatform(adapter.platform);
48
+ const sources = [];
49
+ let elements = [];
50
+ let activeWindow = undefined;
51
+ try {
52
+ const aw = await adapter.getActiveWindow();
53
+ if (aw) {
54
+ activeWindow = {
55
+ processId: aw.processId,
56
+ processName: aw.processName,
57
+ title: aw.title,
58
+ bounds: aw.bounds,
59
+ };
60
+ }
61
+ }
62
+ catch { /* active window optional */ }
63
+ try {
64
+ const tree = await adapter.getUiTree(activeWindow?.processId);
65
+ if (tree && tree.length > 0) {
66
+ sources.push('a11y');
67
+ elements = tree
68
+ .filter(el => el.bounds.width > 0 && el.bounds.height > 0)
69
+ .map(el => {
70
+ // Trust the adapter's explicit secure flag first (macOS AX subrole),
71
+ // then fall back to control-type/name/subrole heuristics.
72
+ const secure = el.secure === true || looksSecure(el.controlType, el.name, el.subrole);
73
+ return {
74
+ name: el.name ?? '',
75
+ role: el.controlType,
76
+ x: el.bounds.x,
77
+ y: el.bounds.y,
78
+ width: el.bounds.width,
79
+ height: el.bounds.height,
80
+ source: 'a11y',
81
+ interactive: el.enabled !== false,
82
+ value: secure ? undefined : el.value,
83
+ secure,
84
+ processId: activeWindow?.processId,
85
+ };
86
+ });
87
+ }
88
+ }
89
+ catch { /* a11y unavailable — snapshot stays empty */ }
90
+ const fp = (0, fingerprint_1.fingerprint)(elements, activeWindow?.title);
91
+ return {
92
+ platform,
93
+ activeWindow,
94
+ elements,
95
+ fingerprint: fp,
96
+ capturedAt,
97
+ sources,
98
+ };
99
+ }
100
+ //# sourceMappingURL=snapshot.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"snapshot.js","sourceRoot":"","sources":["../../../src/core/sense/snapshot.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;GAWG;;AAiCH,0CAyDC;AAtFD,+CAA4C;AAE5C,SAAS,YAAY,CAAC,CAA+B;IACnD,OAAO,CAAC,KAAK,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,KAAK,OAAO,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC;AACxE,CAAC;AAED,MAAM,oBAAoB,GAAG,IAAI,GAAG,CAAC;IACnC,0EAA0E;IAC1E,MAAM,EAAE,aAAa,EAAE,aAAa;IACpC,iBAAiB,EAAE,eAAe;CACnC,CAAC,CAAC;AAEH,SAAS,WAAW,CAAC,WAAoB,EAAE,IAAa,EAAE,OAAgB;IACxE,oEAAoE;IACpE,6EAA6E;IAC7E,kFAAkF;IAClF,IAAI,OAAO,IAAI,kBAAkB,CAAC,IAAI,CAAC,OAAO,CAAC;QAAE,OAAO,IAAI,CAAC;IAC7D,IAAI,CAAC,WAAW,IAAI,CAAC,IAAI;QAAE,OAAO,KAAK,CAAC;IACxC,MAAM,MAAM,GAAG,CAAC,WAAW,IAAI,EAAE,CAAC,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,WAAW,EAAE,CAAC;IACrE,MAAM,MAAM,GAAG,CAAC,IAAI,IAAI,EAAE,CAAC,CAAC,WAAW,EAAE,CAAC;IAC1C,IAAI,oBAAoB,CAAC,GAAG,CAAC,MAAM,CAAC;QAAE,OAAO,IAAI,CAAC;IAClD,IAAI,0EAA0E,CAAC,IAAI,CAAC,MAAM,CAAC;QAAE,OAAO,IAAI,CAAC;IACzG,OAAO,KAAK,CAAC;AACf,CAAC;AAED;;;GAGG;AACI,KAAK,UAAU,eAAe,CAAC,OAAwB;IAC5D,MAAM,UAAU,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;IAC9B,MAAM,QAAQ,GAAG,YAAY,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;IAChD,MAAM,OAAO,GAAkC,EAAE,CAAC;IAElD,IAAI,QAAQ,GAAsB,EAAE,CAAC;IACrC,IAAI,YAAY,GAAyC,SAAS,CAAC;IAEnE,IAAI,CAAC;QACH,MAAM,EAAE,GAAG,MAAM,OAAO,CAAC,eAAe,EAAE,CAAC;QAC3C,IAAI,EAAE,EAAE,CAAC;YACP,YAAY,GAAG;gBACb,SAAS,EAAE,EAAE,CAAC,SAAS;gBACvB,WAAW,EAAE,EAAE,CAAC,WAAW;gBAC3B,KAAK,EAAE,EAAE,CAAC,KAAK;gBACf,MAAM,EAAE,EAAE,CAAC,MAAM;aAClB,CAAC;QACJ,CAAC;IACH,CAAC;IAAC,MAAM,CAAC,CAAC,4BAA4B,CAAC,CAAC;IAExC,IAAI,CAAC;QACH,MAAM,IAAI,GAAG,MAAM,OAAO,CAAC,SAAS,CAAC,YAAY,EAAE,SAAS,CAAC,CAAC;QAC9D,IAAI,IAAI,IAAI,IAAI,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAC5B,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;YACrB,QAAQ,GAAG,IAAI;iBACZ,MAAM,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,MAAM,CAAC,KAAK,GAAG,CAAC,IAAI,EAAE,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC;iBACzD,GAAG,CAAC,EAAE,CAAC,EAAE;gBACR,qEAAqE;gBACrE,0DAA0D;gBAC1D,MAAM,MAAM,GAAG,EAAE,CAAC,MAAM,KAAK,IAAI,IAAI,WAAW,CAAC,EAAE,CAAC,WAAW,EAAE,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,OAAO,CAAC,CAAC;gBACtF,OAAO;oBACL,IAAI,EAAE,EAAE,CAAC,IAAI,IAAI,EAAE;oBACnB,IAAI,EAAE,EAAE,CAAC,WAAW;oBACpB,CAAC,EAAE,EAAE,CAAC,MAAM,CAAC,CAAC;oBACd,CAAC,EAAE,EAAE,CAAC,MAAM,CAAC,CAAC;oBACd,KAAK,EAAE,EAAE,CAAC,MAAM,CAAC,KAAK;oBACtB,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,MAAM;oBACxB,MAAM,EAAE,MAAe;oBACvB,WAAW,EAAE,EAAE,CAAC,OAAO,KAAK,KAAK;oBACjC,KAAK,EAAE,MAAM,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,KAAK;oBACpC,MAAM;oBACN,SAAS,EAAE,YAAY,EAAE,SAAS;iBACnC,CAAC;YACJ,CAAC,CAAC,CAAC;QACP,CAAC;IACH,CAAC;IAAC,MAAM,CAAC,CAAC,6CAA6C,CAAC,CAAC;IAEzD,MAAM,EAAE,GAAG,IAAA,yBAAW,EAAC,QAAQ,EAAE,YAAY,EAAE,KAAK,CAAC,CAAC;IAEtD,OAAO;QACL,QAAQ;QACR,YAAY;QACZ,QAAQ;QACR,WAAW,EAAE,EAAE;QACf,UAAU;QACV,OAAO;KACR,CAAC;AACJ,CAAC"}
@@ -0,0 +1,66 @@
1
+ /**
2
+ * Sense-layer shared types — Snapshot, SnapshotElement, Platform.
3
+ *
4
+ * These types are used by the snapshot builder, fingerprint, rank, and the
5
+ * agent-loop prompt renderer. Extracted here so they survive pipeline deletion.
6
+ */
7
+ export type Platform = 'windows' | 'macos' | 'linux';
8
+ /**
9
+ * A single element in the merged perception snapshot.
10
+ * Coordinates are in real screen pixels (after DPI scaling).
11
+ */
12
+ export interface SnapshotElement {
13
+ /** Human-readable label (a11y name or OCR text). */
14
+ name: string;
15
+ /** Accessibility role / control type when known. */
16
+ role?: string;
17
+ /** Top-left screen coords (after DPI scaling). */
18
+ x: number;
19
+ y: number;
20
+ width: number;
21
+ height: number;
22
+ /** Source of this element — preserved so agents can prefer a11y when available. */
23
+ source: 'a11y' | 'ocr' | 'cdp';
24
+ /** A11y-specific automation ID, if present. */
25
+ automationId?: string;
26
+ /** Whether the element accepts input (button, link, input). */
27
+ interactive?: boolean;
28
+ /** Whether the field is a password/secure field — redacted in `value`. */
29
+ secure?: boolean;
30
+ /** Current text value for inputs (redacted if `secure`). */
31
+ value?: string;
32
+ /** Process ID of the owning window. */
33
+ processId?: number;
34
+ }
35
+ /**
36
+ * A merged perception snapshot — one call, parallel OCR + a11y + optional CDP.
37
+ * Modeled on the per-turn perception snapshot; extended with fingerprint for
38
+ * stagnation detection.
39
+ */
40
+ export interface Snapshot {
41
+ /** Source platform. */
42
+ platform: Platform;
43
+ /** Active window when the snapshot was taken. */
44
+ activeWindow?: {
45
+ processId: number;
46
+ processName: string;
47
+ title: string;
48
+ bounds: {
49
+ x: number;
50
+ y: number;
51
+ width: number;
52
+ height: number;
53
+ };
54
+ };
55
+ /** All elements merged from a11y + OCR + CDP, de-duped by spatial overlap. */
56
+ elements: SnapshotElement[];
57
+ /**
58
+ * Stable fingerprint of the snapshot — same UI produces same string, used by
59
+ * the agent loop to detect "nothing changed, stop retrying the same action".
60
+ */
61
+ fingerprint: string;
62
+ /** Timestamp for staleness checks. */
63
+ capturedAt: number;
64
+ /** Which sources successfully contributed; empty sources fell back silently. */
65
+ sources: Array<'a11y' | 'ocr' | 'cdp'>;
66
+ }
@@ -0,0 +1,9 @@
1
+ "use strict";
2
+ /**
3
+ * Sense-layer shared types — Snapshot, SnapshotElement, Platform.
4
+ *
5
+ * These types are used by the snapshot builder, fingerprint, rank, and the
6
+ * agent-loop prompt renderer. Extracted here so they survive pipeline deletion.
7
+ */
8
+ Object.defineProperty(exports, "__esModule", { value: true });
9
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/core/sense/types.ts"],"names":[],"mappings":";AAAA;;;;;GAKG"}
@@ -0,0 +1,7 @@
1
+ import type { UIElement, UIMap } from './ui-map-types';
2
+ /**
3
+ * Two cross-turn anchors. `prevAnchors` is accepted for re-identification
4
+ * continuity (matched by role + normalized_text); with only two anchors this
5
+ * stays cheap and needs no element database.
6
+ */
7
+ export declare function computeAnchors(elements: UIElement[], _prevAnchors: UIMap['anchors'] | undefined): UIMap['anchors'];
@@ -0,0 +1,24 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.computeAnchors = computeAnchors;
4
+ const PRIMARY_VERBS = ['send', 'save', 'submit', 'ok', 'continue', 'next',
5
+ 'confirm', 'post', 'publish', 'done', 'apply'];
6
+ const toRef = (e) => ({
7
+ id: e.id, role: e.role, normalized_text: e.normalized_text
8
+ });
9
+ /**
10
+ * Two cross-turn anchors. `prevAnchors` is accepted for re-identification
11
+ * continuity (matched by role + normalized_text); with only two anchors this
12
+ * stays cheap and needs no element database.
13
+ */
14
+ function computeAnchors(elements, _prevAnchors) {
15
+ const focusedEl = elements.find(e => e.state?.focused);
16
+ const candidates = elements
17
+ .filter(e => e.clickable && PRIMARY_VERBS.includes(e.normalized_text ?? ''))
18
+ .sort((a, b) => b.confidence - a.confidence);
19
+ return {
20
+ focused: focusedEl ? toRef(focusedEl) : undefined,
21
+ primary_action_candidate: candidates[0] ? toRef(candidates[0]) : undefined,
22
+ };
23
+ }
24
+ //# sourceMappingURL=ui-map-anchors.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ui-map-anchors.js","sourceRoot":"","sources":["../../../src/core/sense/ui-map-anchors.ts"],"names":[],"mappings":";;AAaA,wCAYC;AAvBD,MAAM,aAAa,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,IAAI,EAAE,UAAU,EAAE,MAAM;IACvE,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,OAAO,CAAC,CAAC;AAEjD,MAAM,KAAK,GAAG,CAAC,CAAY,EAAc,EAAE,CAAC,CAAC;IAC3C,EAAE,EAAE,CAAC,CAAC,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,eAAe,EAAE,CAAC,CAAC,eAAe;CAAE,CAAC,CAAC;AAEhE;;;;GAIG;AACH,SAAgB,cAAc,CAC5B,QAAqB,EACrB,YAA0C;IAE1C,MAAM,SAAS,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC;IACvD,MAAM,UAAU,GAAG,QAAQ;SACxB,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,SAAS,IAAI,aAAa,CAAC,QAAQ,CAAC,CAAC,CAAC,eAAe,IAAI,EAAE,CAAC,CAAC;SAC3E,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,UAAU,GAAG,CAAC,CAAC,UAAU,CAAC,CAAC;IAC/C,OAAO;QACL,OAAO,EAAE,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,SAAS;QACjD,wBAAwB,EAAE,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS;KAC3E,CAAC;AACJ,CAAC"}
@@ -0,0 +1,5 @@
1
+ import type { SnapshotElement } from './types';
2
+ import type { OcrElement } from '../../platform/ocr-engine';
3
+ import type { UIElement } from './ui-map-types';
4
+ export declare function a11yToUI(se: SnapshotElement, id: string): UIElement;
5
+ export declare function ocrToUI(oe: OcrElement, id: string): UIElement;
@@ -0,0 +1,33 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.a11yToUI = a11yToUI;
4
+ exports.ocrToUI = ocrToUI;
5
+ const ui_map_normalize_1 = require("./ui-map-normalize");
6
+ // Confidence bases (see spec §3). a11y is structured/trustworthy; OCR is scaled
7
+ // by the recognizer's own score AND damped so a lone OCR hit never outranks a
8
+ // corroborated a11y element. 1-char OCR fragments are damped hard (stray-"O").
9
+ const A11Y_BASE = 0.85;
10
+ const OCR_SCALE = 0.6;
11
+ function a11yToUI(se, id) {
12
+ const role = (0, ui_map_normalize_1.normalizeRole)(se.role);
13
+ const caps = (0, ui_map_normalize_1.inferCapabilities)({ role, source: 'a11y', enabled: se.interactive });
14
+ return {
15
+ id, role, text: se.name, normalized_text: (0, ui_map_normalize_1.normText)(se.name),
16
+ bounds: [se.x, se.y, se.width, se.height],
17
+ confidence: A11Y_BASE, sources: ['a11y'], ...caps,
18
+ state: { enabled: se.interactive !== false, value: se.secure ? undefined : se.value },
19
+ };
20
+ }
21
+ function ocrToUI(oe, id) {
22
+ const role = 'text';
23
+ const caps = (0, ui_map_normalize_1.inferCapabilities)({ role, source: 'ocr', enabled: true });
24
+ // Single-char fragments are OCR noise — damp hard so they never win a match.
25
+ const lenDamp = oe.text.trim().length <= 1 ? 0.4 : 1;
26
+ const confidence = oe.confidence * OCR_SCALE * lenDamp;
27
+ return {
28
+ id, role, text: oe.text, normalized_text: (0, ui_map_normalize_1.normText)(oe.text),
29
+ bounds: [oe.x, oe.y, oe.width, oe.height],
30
+ confidence, sources: ['ocr'], ...caps,
31
+ };
32
+ }
33
+ //# sourceMappingURL=ui-map-elements.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ui-map-elements.js","sourceRoot":"","sources":["../../../src/core/sense/ui-map-elements.ts"],"names":[],"mappings":";;AAWA,4BASC;AAED,0BAWC;AA9BD,yDAAgF;AAEhF,gFAAgF;AAChF,8EAA8E;AAC9E,+EAA+E;AAC/E,MAAM,SAAS,GAAG,IAAI,CAAC;AACvB,MAAM,SAAS,GAAG,GAAG,CAAC;AAEtB,SAAgB,QAAQ,CAAC,EAAmB,EAAE,EAAU;IACtD,MAAM,IAAI,GAAG,IAAA,gCAAa,EAAC,EAAE,CAAC,IAAI,CAAC,CAAC;IACpC,MAAM,IAAI,GAAG,IAAA,oCAAiB,EAAC,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,EAAE,CAAC,WAAW,EAAE,CAAC,CAAC;IAClF,OAAO;QACL,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,EAAE,CAAC,IAAI,EAAE,eAAe,EAAE,IAAA,2BAAQ,EAAC,EAAE,CAAC,IAAI,CAAC;QAC3D,MAAM,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,MAAM,CAAC;QACzC,UAAU,EAAE,SAAS,EAAE,OAAO,EAAE,CAAC,MAAM,CAAC,EAAE,GAAG,IAAI;QACjD,KAAK,EAAE,EAAE,OAAO,EAAE,EAAE,CAAC,WAAW,KAAK,KAAK,EAAE,KAAK,EAAE,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,KAAK,EAAE;KACtF,CAAC;AACJ,CAAC;AAED,SAAgB,OAAO,CAAC,EAAc,EAAE,EAAU;IAChD,MAAM,IAAI,GAAG,MAAe,CAAC;IAC7B,MAAM,IAAI,GAAG,IAAA,oCAAiB,EAAC,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC;IACvE,6EAA6E;IAC7E,MAAM,OAAO,GAAG,EAAE,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,MAAM,IAAI,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;IACrD,MAAM,UAAU,GAAG,EAAE,CAAC,UAAU,GAAG,SAAS,GAAG,OAAO,CAAC;IACvD,OAAO;QACL,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,EAAE,CAAC,IAAI,EAAE,eAAe,EAAE,IAAA,2BAAQ,EAAC,EAAE,CAAC,IAAI,CAAC;QAC3D,MAAM,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,MAAM,CAAC;QACzC,UAAU,EAAE,OAAO,EAAE,CAAC,KAAK,CAAC,EAAE,GAAG,IAAI;KACtC,CAAC;AACJ,CAAC"}
@@ -0,0 +1,56 @@
1
+ /**
2
+ * Layer B — pure, deterministic semantic finders over a compiled UIMap.
3
+ * Turn an intent/purpose into the best el_NN. No LLM, no platform calls,
4
+ * no process.platform branching. See the Layer B design spec.
5
+ *
6
+ * BOUNDARY: ranks only elements the UIMap marks clickable/editable (a11y-exposed
7
+ * interactive elements, where the Part-2 ref-act chain is valid). OCR text is a
8
+ * label SOURCE only (Task 3), not an independent actionable candidate.
9
+ */
10
+ import type { UIElement, Role } from './ui-map-types';
11
+ export declare const MATCH_THRESHOLD = 0.4;
12
+ export declare const AMBIGUITY_MARGIN = 0.05;
13
+ export declare const MAX_CANDIDATES = 5;
14
+ export interface FindCandidate {
15
+ element_id: string;
16
+ label: string;
17
+ role: Role;
18
+ score: number;
19
+ confidence: number;
20
+ }
21
+ export type FindResult = {
22
+ status: 'ok';
23
+ snapshot_id: string;
24
+ best: FindCandidate;
25
+ candidates: FindCandidate[];
26
+ } | {
27
+ status: 'ambiguous';
28
+ snapshot_id: string;
29
+ reason: string;
30
+ candidates: FindCandidate[];
31
+ } | {
32
+ status: 'none';
33
+ snapshot_id: string;
34
+ reason: string;
35
+ candidates: FindCandidate[];
36
+ };
37
+ export interface ExpandedTerms {
38
+ /** The normalized intent literal and its tokens — exact match → score 1.0. */
39
+ literals: Set<string>;
40
+ /** Synonyms drawn from the table — synonym match → score 0.9. */
41
+ synonyms: Set<string>;
42
+ }
43
+ /** Expand an intent into literal + synonym sets. Keeps exact vs synonym distinct
44
+ * so that scoreLabel can assign different raw scores to each tier. */
45
+ export declare function expandTerms(intent: string, table: Record<string, string[]>): ExpandedTerms;
46
+ /** Raw 0..1 match of a label against the term sets (no confidence yet).
47
+ * Literal exact → 1.0; synonym exact / literal substring → 0.9; token overlap → ≤0.5. */
48
+ export declare function scoreLabel(label: string, { literals, synonyms }: ExpandedTerms, intentTokens: string[]): number;
49
+ /** Shared finder core. `labelOf` lets fields override with geometric association. */
50
+ export declare function runFinder(elements: UIElement[], snapshotId: string, intent: string, table: Record<string, string[]>, isCandidate: (e: UIElement) => boolean, labelOf: (e: UIElement, all: UIElement[]) => string): FindResult;
51
+ export declare function findActionButton(elements: UIElement[], snapshotId: string, intent: string): FindResult;
52
+ /** Find the descriptive label for an (unnamed) field by geometry: nearest text
53
+ * element to the LEFT (same row) preferred, else ABOVE (same column). a11y OR
54
+ * OCR sourced. Returns '' when none is within range. Pure geometry. */
55
+ export declare function associateLabel(field: UIElement, all: UIElement[]): string;
56
+ export declare function findInputField(elements: UIElement[], snapshotId: string, purpose: string): FindResult;
@@ -0,0 +1,153 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.MAX_CANDIDATES = exports.AMBIGUITY_MARGIN = exports.MATCH_THRESHOLD = void 0;
4
+ exports.expandTerms = expandTerms;
5
+ exports.scoreLabel = scoreLabel;
6
+ exports.runFinder = runFinder;
7
+ exports.findActionButton = findActionButton;
8
+ exports.associateLabel = associateLabel;
9
+ exports.findInputField = findInputField;
10
+ const ui_map_normalize_1 = require("./ui-map-normalize");
11
+ exports.MATCH_THRESHOLD = 0.4; // min score×confidence to count as a match
12
+ exports.AMBIGUITY_MARGIN = 0.05; // top-two closeness that forces 'ambiguous'
13
+ exports.MAX_CANDIDATES = 5;
14
+ /** Curated intent → synonym sets. Unknown intents fall back to literal/token match. */
15
+ const ACTION_SYNONYMS = {
16
+ submit: ['submit', 'send', 'ok', 'confirm', 'save', 'continue', 'next', 'post', 'publish', 'apply', 'done', 'go'],
17
+ cancel: ['cancel', 'close', 'dismiss', 'back', 'no'],
18
+ delete: ['delete', 'remove', 'trash', 'discard'],
19
+ search: ['search', 'find', 'go', 'query'],
20
+ login: ['login', 'log in', 'sign in', 'signin'],
21
+ open: ['open', 'launch', 'view'],
22
+ add: ['add', 'new', 'create', 'plus'],
23
+ };
24
+ /** Expand an intent into literal + synonym sets. Keeps exact vs synonym distinct
25
+ * so that scoreLabel can assign different raw scores to each tier. */
26
+ function expandTerms(intent, table) {
27
+ const lit = (0, ui_map_normalize_1.normText)(intent);
28
+ const literals = new Set([lit]);
29
+ lit.split(' ').filter(Boolean).forEach(t => literals.add(t));
30
+ literals.delete('');
31
+ const synonyms = new Set();
32
+ for (const [key, syns] of Object.entries(table)) {
33
+ if (key === lit || syns.includes(lit)) {
34
+ syns.forEach(s => {
35
+ if (!literals.has(s))
36
+ synonyms.add(s);
37
+ });
38
+ }
39
+ }
40
+ return { literals, synonyms };
41
+ }
42
+ /** Raw 0..1 match of a label against the term sets (no confidence yet).
43
+ * Literal exact → 1.0; synonym exact / literal substring → 0.9; token overlap → ≤0.5. */
44
+ function scoreLabel(label, { literals, synonyms }, intentTokens) {
45
+ const L = (0, ui_map_normalize_1.normText)(label);
46
+ if (!L)
47
+ return 0;
48
+ // Exact literal match (highest tier)
49
+ if (literals.has(L))
50
+ return 1.0;
51
+ const lTokens = L.split(' ').filter(Boolean);
52
+ const lSet = new Set(lTokens);
53
+ // Synonym exact match or literal term as whole word / substring in label
54
+ for (const t of synonyms) {
55
+ if (lSet.has(t))
56
+ return 0.9;
57
+ if (t.length > 2 && L.includes(t))
58
+ return 0.9;
59
+ }
60
+ for (const t of literals) {
61
+ if (lSet.has(t))
62
+ return 0.9; // intent token is a whole word in the label
63
+ if (t.length > 2 && L.includes(t))
64
+ return 0.9; // intent token is a substring of the label
65
+ }
66
+ const overlap = intentTokens.filter(t => lSet.has(t)).length;
67
+ return intentTokens.length > 0 ? 0.5 * (overlap / intentTokens.length) : 0;
68
+ }
69
+ /** Shared finder core. `labelOf` lets fields override with geometric association. */
70
+ function runFinder(elements, snapshotId, intent, table, isCandidate, labelOf) {
71
+ const terms = expandTerms(intent, table);
72
+ const intentTokens = (0, ui_map_normalize_1.normText)(intent).split(' ').filter(Boolean);
73
+ const scored = [];
74
+ for (const e of elements) {
75
+ if (!isCandidate(e))
76
+ continue;
77
+ const label = labelOf(e, elements);
78
+ const raw = scoreLabel(label, terms, intentTokens);
79
+ if (raw <= 0)
80
+ continue;
81
+ scored.push({ element_id: e.id, label, role: e.role, score: raw * e.confidence, confidence: e.confidence });
82
+ }
83
+ scored.sort((a, b) => b.score - a.score);
84
+ const candidates = scored.slice(0, exports.MAX_CANDIDATES);
85
+ const best = scored[0];
86
+ if (!best || best.score < exports.MATCH_THRESHOLD) {
87
+ return { status: 'none', snapshot_id: snapshotId, reason: 'no candidate cleared the match threshold', candidates };
88
+ }
89
+ const second = scored[1];
90
+ if (second && best.score - second.score < exports.AMBIGUITY_MARGIN) {
91
+ return { status: 'ambiguous', snapshot_id: snapshotId, reason: `top candidates within ${exports.AMBIGUITY_MARGIN} score margin`, candidates };
92
+ }
93
+ return { status: 'ok', snapshot_id: snapshotId, best, candidates };
94
+ }
95
+ function findActionButton(elements, snapshotId, intent) {
96
+ return runFinder(elements, snapshotId, intent, ACTION_SYNONYMS, e => e.clickable === true, e => e.normalized_text ?? '');
97
+ }
98
+ const MAX_LABEL_GAP_X = 240; // px: a left label's right edge to the field's left edge
99
+ const MAX_LABEL_GAP_Y = 64; // px: an above label's bottom edge to the field's top edge
100
+ const LABEL_ROLES = new Set(['text', 'link', 'unknown']);
101
+ /** Find the descriptive label for an (unnamed) field by geometry: nearest text
102
+ * element to the LEFT (same row) preferred, else ABOVE (same column). a11y OR
103
+ * OCR sourced. Returns '' when none is within range. Pure geometry. */
104
+ function associateLabel(field, all) {
105
+ const [fx, fy, fw, fh] = field.bounds;
106
+ let left = null;
107
+ let above = null;
108
+ for (const e of all) {
109
+ if (e.id === field.id || !LABEL_ROLES.has(e.role))
110
+ continue;
111
+ const label = e.normalized_text ?? '';
112
+ if (!label)
113
+ continue;
114
+ const [ex, ey, ew, eh] = e.bounds;
115
+ const eRight = ex + ew;
116
+ const eBottom = ey + eh;
117
+ const eCenterY = ey + eh / 2;
118
+ const eCenterX = ex + ew / 2;
119
+ // LEFT, same row: label's vertical center within the field's y-band, right edge just left of the field.
120
+ const sameRow = eCenterY >= fy && eCenterY <= fy + fh;
121
+ if (sameRow && eRight <= fx + 4) {
122
+ const gap = fx - eRight;
123
+ if (gap >= 0 && gap <= MAX_LABEL_GAP_X && (!left || gap < left.gap))
124
+ left = { gap, label };
125
+ }
126
+ // ABOVE, same column: label horizontally overlaps the field, bottom just above the field top.
127
+ const sameCol = eCenterX >= fx && eCenterX <= fx + fw;
128
+ if (sameCol && eBottom <= fy + 4) {
129
+ const gap = fy - eBottom;
130
+ if (gap >= 0 && gap <= MAX_LABEL_GAP_Y && (!above || gap < above.gap))
131
+ above = { gap, label };
132
+ }
133
+ }
134
+ return (left ?? above)?.label ?? '';
135
+ }
136
+ /** Curated field-purpose → synonym sets. */
137
+ const FIELD_SYNONYMS = {
138
+ recipient: ['to', 'recipient', 'email', 'address', 'send to'],
139
+ cc: ['cc', 'carbon copy'],
140
+ subject: ['subject', 'title', 're'],
141
+ body: ['body', 'message', 'content', 'compose', 'note'],
142
+ search: ['search', 'query', 'find', 'filter'],
143
+ password: ['password', 'pass', 'pwd'],
144
+ username: ['username', 'user', 'login', 'email'],
145
+ name: ['name', 'full name'],
146
+ };
147
+ function findInputField(elements, snapshotId, purpose) {
148
+ return runFinder(elements, snapshotId, purpose, FIELD_SYNONYMS, e => e.editable === true, (e, all) => {
149
+ const own = e.normalized_text ?? '';
150
+ return own !== '' ? own : associateLabel(e, all);
151
+ });
152
+ }
153
+ //# sourceMappingURL=ui-map-find.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ui-map-find.js","sourceRoot":"","sources":["../../../src/core/sense/ui-map-find.ts"],"names":[],"mappings":";;;AA0CA,kCAeC;AAID,gCAkBC;AAGD,8BA6BC;AAED,4CAIC;AAUD,wCA2BC;AAcD,wCAOC;AArKD,yDAA8C;AAEjC,QAAA,eAAe,GAAG,GAAG,CAAC,CAAG,2CAA2C;AACpE,QAAA,gBAAgB,GAAG,IAAI,CAAC,CAAC,4CAA4C;AACrE,QAAA,cAAc,GAAG,CAAC,CAAC;AAQhC,uFAAuF;AACvF,MAAM,eAAe,GAA6B;IAChD,MAAM,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,SAAS,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC;IACjH,MAAM,EAAE,CAAC,QAAQ,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,EAAE,IAAI,CAAC;IACpD,MAAM,EAAE,CAAC,QAAQ,EAAE,QAAQ,EAAE,OAAO,EAAE,SAAS,CAAC;IAChD,MAAM,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,CAAC;IACzC,KAAK,EAAE,CAAC,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,QAAQ,CAAC;IAC/C,IAAI,EAAE,CAAC,MAAM,EAAE,QAAQ,EAAE,MAAM,CAAC;IAChC,GAAG,EAAE,CAAC,KAAK,EAAE,KAAK,EAAE,QAAQ,EAAE,MAAM,CAAC;CACtC,CAAC;AASF;uEACuE;AACvE,SAAgB,WAAW,CAAC,MAAc,EAAE,KAA+B;IACzE,MAAM,GAAG,GAAG,IAAA,2BAAQ,EAAC,MAAM,CAAC,CAAC;IAC7B,MAAM,QAAQ,GAAG,IAAI,GAAG,CAAS,CAAC,GAAG,CAAC,CAAC,CAAC;IACxC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;IAC7D,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;IAEpB,MAAM,QAAQ,GAAG,IAAI,GAAG,EAAU,CAAC;IACnC,KAAK,MAAM,CAAC,GAAG,EAAE,IAAI,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;QAChD,IAAI,GAAG,KAAK,GAAG,IAAI,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;YACtC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE;gBACf,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC;oBAAE,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;YACxC,CAAC,CAAC,CAAC;QACL,CAAC;IACH,CAAC;IACD,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,CAAC;AAChC,CAAC;AAED;0FAC0F;AAC1F,SAAgB,UAAU,CAAC,KAAa,EAAE,EAAE,QAAQ,EAAE,QAAQ,EAAiB,EAAE,YAAsB;IACrG,MAAM,CAAC,GAAG,IAAA,2BAAQ,EAAC,KAAK,CAAC,CAAC;IAC1B,IAAI,CAAC,CAAC;QAAE,OAAO,CAAC,CAAC;IACjB,qCAAqC;IACrC,IAAI,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC;QAAE,OAAO,GAAG,CAAC;IAChC,MAAM,OAAO,GAAG,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;IAC7C,MAAM,IAAI,GAAG,IAAI,GAAG,CAAC,OAAO,CAAC,CAAC;IAC9B,yEAAyE;IACzE,KAAK,MAAM,CAAC,IAAI,QAAQ,EAAE,CAAC;QACzB,IAAI,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;YAAE,OAAO,GAAG,CAAC;QAC5B,IAAI,CAAC,CAAC,MAAM,GAAG,CAAC,IAAI,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC;YAAE,OAAO,GAAG,CAAC;IAChD,CAAC;IACD,KAAK,MAAM,CAAC,IAAI,QAAQ,EAAE,CAAC;QACzB,IAAI,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;YAAE,OAAO,GAAG,CAAC,CAA0B,4CAA4C;QAClG,IAAI,CAAC,CAAC,MAAM,GAAG,CAAC,IAAI,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC;YAAE,OAAO,GAAG,CAAC,CAAQ,2CAA2C;IACnG,CAAC;IACD,MAAM,OAAO,GAAG,YAAY,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC;IAC7D,OAAO,YAAY,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC,OAAO,GAAG,YAAY,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAC7E,CAAC;AAED,qFAAqF;AACrF,SAAgB,SAAS,CACvB,QAAqB,EACrB,UAAkB,EAClB,MAAc,EACd,KAA+B,EAC/B,WAAsC,EACtC,OAAmD;IAEnD,MAAM,KAAK,GAAG,WAAW,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;IACzC,MAAM,YAAY,GAAG,IAAA,2BAAQ,EAAC,MAAM,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;IACjE,MAAM,MAAM,GAAoB,EAAE,CAAC;IACnC,KAAK,MAAM,CAAC,IAAI,QAAQ,EAAE,CAAC;QACzB,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC;YAAE,SAAS;QAC9B,MAAM,KAAK,GAAG,OAAO,CAAC,CAAC,EAAE,QAAQ,CAAC,CAAC;QACnC,MAAM,GAAG,GAAG,UAAU,CAAC,KAAK,EAAE,KAAK,EAAE,YAAY,CAAC,CAAC;QACnD,IAAI,GAAG,IAAI,CAAC;YAAE,SAAS;QACvB,MAAM,CAAC,IAAI,CAAC,EAAE,UAAU,EAAE,CAAC,CAAC,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,GAAG,GAAG,CAAC,CAAC,UAAU,EAAE,UAAU,EAAE,CAAC,CAAC,UAAU,EAAE,CAAC,CAAC;IAC9G,CAAC;IACD,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC;IACzC,MAAM,UAAU,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,sBAAc,CAAC,CAAC;IACnD,MAAM,IAAI,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC;IACvB,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,KAAK,GAAG,uBAAe,EAAE,CAAC;QAC1C,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,EAAE,0CAA0C,EAAE,UAAU,EAAE,CAAC;IACrH,CAAC;IACD,MAAM,MAAM,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC;IACzB,IAAI,MAAM,IAAI,IAAI,CAAC,KAAK,GAAG,MAAM,CAAC,KAAK,GAAG,wBAAgB,EAAE,CAAC;QAC3D,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,EAAE,yBAAyB,wBAAgB,eAAe,EAAE,UAAU,EAAE,CAAC;IACxI,CAAC;IACD,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,WAAW,EAAE,UAAU,EAAE,IAAI,EAAE,UAAU,EAAE,CAAC;AACrE,CAAC;AAED,SAAgB,gBAAgB,CAAC,QAAqB,EAAE,UAAkB,EAAE,MAAc;IACxF,OAAO,SAAS,CAAC,QAAQ,EAAE,UAAU,EAAE,MAAM,EAAE,eAAe,EAC5D,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,SAAS,KAAK,IAAI,EACzB,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,eAAe,IAAI,EAAE,CAAC,CAAC;AAClC,CAAC;AAED,MAAM,eAAe,GAAG,GAAG,CAAC,CAAE,yDAAyD;AACvF,MAAM,eAAe,GAAG,EAAE,CAAC,CAAG,2DAA2D;AAEzF,MAAM,WAAW,GAAG,IAAI,GAAG,CAAO,CAAC,MAAM,EAAE,MAAM,EAAE,SAAS,CAAC,CAAC,CAAC;AAE/D;;wEAEwE;AACxE,SAAgB,cAAc,CAAC,KAAgB,EAAE,GAAgB;IAC/D,MAAM,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,CAAC,GAAG,KAAK,CAAC,MAAM,CAAC;IACtC,IAAI,IAAI,GAA0C,IAAI,CAAC;IACvD,IAAI,KAAK,GAA0C,IAAI,CAAC;IACxD,KAAK,MAAM,CAAC,IAAI,GAAG,EAAE,CAAC;QACpB,IAAI,CAAC,CAAC,EAAE,KAAK,KAAK,CAAC,EAAE,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC;YAAE,SAAS;QAC5D,MAAM,KAAK,GAAG,CAAC,CAAC,eAAe,IAAI,EAAE,CAAC;QACtC,IAAI,CAAC,KAAK;YAAE,SAAS;QACrB,MAAM,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC;QAClC,MAAM,MAAM,GAAG,EAAE,GAAG,EAAE,CAAC;QACvB,MAAM,OAAO,GAAG,EAAE,GAAG,EAAE,CAAC;QACxB,MAAM,QAAQ,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC;QAC7B,MAAM,QAAQ,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC;QAC7B,wGAAwG;QACxG,MAAM,OAAO,GAAG,QAAQ,IAAI,EAAE,IAAI,QAAQ,IAAI,EAAE,GAAG,EAAE,CAAC;QACtD,IAAI,OAAO,IAAI,MAAM,IAAI,EAAE,GAAG,CAAC,EAAE,CAAC;YAChC,MAAM,GAAG,GAAG,EAAE,GAAG,MAAM,CAAC;YACxB,IAAI,GAAG,IAAI,CAAC,IAAI,GAAG,IAAI,eAAe,IAAI,CAAC,CAAC,IAAI,IAAI,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC;gBAAE,IAAI,GAAG,EAAE,GAAG,EAAE,KAAK,EAAE,CAAC;QAC7F,CAAC;QACD,8FAA8F;QAC9F,MAAM,OAAO,GAAG,QAAQ,IAAI,EAAE,IAAI,QAAQ,IAAI,EAAE,GAAG,EAAE,CAAC;QACtD,IAAI,OAAO,IAAI,OAAO,IAAI,EAAE,GAAG,CAAC,EAAE,CAAC;YACjC,MAAM,GAAG,GAAG,EAAE,GAAG,OAAO,CAAC;YACzB,IAAI,GAAG,IAAI,CAAC,IAAI,GAAG,IAAI,eAAe,IAAI,CAAC,CAAC,KAAK,IAAI,GAAG,GAAG,KAAK,CAAC,GAAG,CAAC;gBAAE,KAAK,GAAG,EAAE,GAAG,EAAE,KAAK,EAAE,CAAC;QAChG,CAAC;IACH,CAAC;IACD,OAAO,CAAC,IAAI,IAAI,KAAK,CAAC,EAAE,KAAK,IAAI,EAAE,CAAC;AACtC,CAAC;AAED,4CAA4C;AAC5C,MAAM,cAAc,GAA6B;IAC/C,SAAS,EAAE,CAAC,IAAI,EAAE,WAAW,EAAE,OAAO,EAAE,SAAS,EAAE,SAAS,CAAC;IAC7D,EAAE,EAAE,CAAC,IAAI,EAAE,aAAa,CAAC;IACzB,OAAO,EAAE,CAAC,SAAS,EAAE,OAAO,EAAE,IAAI,CAAC;IACnC,IAAI,EAAE,CAAC,MAAM,EAAE,SAAS,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,CAAC;IACvD,MAAM,EAAE,CAAC,QAAQ,EAAE,OAAO,EAAE,MAAM,EAAE,QAAQ,CAAC;IAC7C,QAAQ,EAAE,CAAC,UAAU,EAAE,MAAM,EAAE,KAAK,CAAC;IACrC,QAAQ,EAAE,CAAC,UAAU,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,CAAC;IAChD,IAAI,EAAE,CAAC,MAAM,EAAE,WAAW,CAAC;CAC5B,CAAC;AAEF,SAAgB,cAAc,CAAC,QAAqB,EAAE,UAAkB,EAAE,OAAe;IACvF,OAAO,SAAS,CAAC,QAAQ,EAAE,UAAU,EAAE,OAAO,EAAE,cAAc,EAC5D,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,QAAQ,KAAK,IAAI,EACxB,CAAC,CAAC,EAAE,GAAG,EAAE,EAAE;QACT,MAAM,GAAG,GAAG,CAAC,CAAC,eAAe,IAAI,EAAE,CAAC;QACpC,OAAO,GAAG,KAAK,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,cAAc,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;IACnD,CAAC,CAAC,CAAC;AACP,CAAC"}
@@ -0,0 +1,4 @@
1
+ import type { UIElement } from './ui-map-types';
2
+ /** Merge same-place + same-text elements across sources; raise confidence per
3
+ * corroborating source; keep the stronger role/capabilities. */
4
+ export declare function fuse(elements: UIElement[]): UIElement[];
@@ -0,0 +1,44 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.fuse = fuse;
4
+ const ui_map_geom_1 = require("./ui-map-geom");
5
+ const AGREEMENT_BONUS = 0.15;
6
+ const OVERLAP_MIN = 0.5; // IoU threshold to treat two boxes as the same element
7
+ const ROLE_PRIORITY = ['button', 'input', 'link', 'checkbox', 'tab',
8
+ 'listitem', 'list', 'image', 'text', 'unknown'];
9
+ function betterRole(a, b) {
10
+ return ROLE_PRIORITY.indexOf(a) <= ROLE_PRIORITY.indexOf(b) ? a : b;
11
+ }
12
+ /** Merge same-place + same-text elements across sources; raise confidence per
13
+ * corroborating source; keep the stronger role/capabilities. */
14
+ function fuse(elements) {
15
+ const out = [];
16
+ // Running max of the ORIGINAL (un-bonused) confidence per merged cluster, so
17
+ // the agreement bonus is applied once against the base — idempotent for 3+
18
+ // sources (a11y+ocr+vision must give base+2·bonus, not a compounded value).
19
+ const baseConf = new Map();
20
+ for (const el of elements) {
21
+ const match = out.find(o => o.normalized_text === el.normalized_text &&
22
+ o.normalized_text !== '' &&
23
+ o.normalized_text !== undefined &&
24
+ (0, ui_map_geom_1.iou)(o.bounds, el.bounds) >= OVERLAP_MIN);
25
+ if (!match) {
26
+ const copy = { ...el, sources: [...el.sources] };
27
+ out.push(copy);
28
+ baseConf.set(copy, el.confidence);
29
+ continue;
30
+ }
31
+ const merged = Array.from(new Set([...match.sources, ...el.sources]));
32
+ match.sources = merged;
33
+ match.role = betterRole(match.role, el.role);
34
+ match.clickable = match.clickable || el.clickable;
35
+ match.editable = match.editable || el.editable;
36
+ match.actionable = match.actionable || el.actionable;
37
+ const base = Math.max(baseConf.get(match) ?? match.confidence, el.confidence);
38
+ baseConf.set(match, base);
39
+ match.confidence = Math.min(1, base + AGREEMENT_BONUS * (merged.length - 1));
40
+ match.state = { ...el.state, ...match.state };
41
+ }
42
+ return out;
43
+ }
44
+ //# sourceMappingURL=ui-map-fuse.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ui-map-fuse.js","sourceRoot":"","sources":["../../../src/core/sense/ui-map-fuse.ts"],"names":[],"mappings":";;AAcA,oBA8BC;AA3CD,+CAAoC;AAEpC,MAAM,eAAe,GAAG,IAAI,CAAC;AAC7B,MAAM,WAAW,GAAG,GAAG,CAAC,CAAQ,uDAAuD;AACvF,MAAM,aAAa,GAAW,CAAC,QAAQ,EAAE,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,KAAK;IACzE,UAAU,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,SAAS,CAAC,CAAC;AAElD,SAAS,UAAU,CAAC,CAAO,EAAE,CAAO;IAClC,OAAO,aAAa,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,aAAa,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACtE,CAAC;AAED;iEACiE;AACjE,SAAgB,IAAI,CAAC,QAAqB;IACxC,MAAM,GAAG,GAAgB,EAAE,CAAC;IAC5B,6EAA6E;IAC7E,2EAA2E;IAC3E,4EAA4E;IAC5E,MAAM,QAAQ,GAAG,IAAI,GAAG,EAAqB,CAAC;IAC9C,KAAK,MAAM,EAAE,IAAI,QAAQ,EAAE,CAAC;QAC1B,MAAM,KAAK,GAAG,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CACzB,CAAC,CAAC,eAAe,KAAK,EAAE,CAAC,eAAe;YACxC,CAAC,CAAC,eAAe,KAAK,EAAE;YACxB,CAAC,CAAC,eAAe,KAAK,SAAS;YAC/B,IAAA,iBAAG,EAAC,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,IAAI,WAAW,CAAC,CAAC;QAC3C,IAAI,CAAC,KAAK,EAAE,CAAC;YACX,MAAM,IAAI,GAAG,EAAE,GAAG,EAAE,EAAE,OAAO,EAAE,CAAC,GAAG,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC;YACjD,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YACf,QAAQ,CAAC,GAAG,CAAC,IAAI,EAAE,EAAE,CAAC,UAAU,CAAC,CAAC;YAClC,SAAS;QACX,CAAC;QACD,MAAM,MAAM,GAAa,KAAK,CAAC,IAAI,CAAC,IAAI,GAAG,CAAC,CAAC,GAAG,KAAK,CAAC,OAAO,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;QAChF,KAAK,CAAC,OAAO,GAAG,MAAM,CAAC;QACvB,KAAK,CAAC,IAAI,GAAG,UAAU,CAAC,KAAK,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,CAAC;QAC7C,KAAK,CAAC,SAAS,GAAG,KAAK,CAAC,SAAS,IAAI,EAAE,CAAC,SAAS,CAAC;QAClD,KAAK,CAAC,QAAQ,GAAG,KAAK,CAAC,QAAQ,IAAI,EAAE,CAAC,QAAQ,CAAC;QAC/C,KAAK,CAAC,UAAU,GAAG,KAAK,CAAC,UAAU,IAAI,EAAE,CAAC,UAAU,CAAC;QACrD,MAAM,IAAI,GAAG,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,KAAK,CAAC,UAAU,EAAE,EAAE,CAAC,UAAU,CAAC,CAAC;QAC9E,QAAQ,CAAC,GAAG,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC;QAC1B,KAAK,CAAC,UAAU,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,GAAG,eAAe,GAAG,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC;QAC7E,KAAK,CAAC,KAAK,GAAG,EAAE,GAAG,EAAE,CAAC,KAAK,EAAE,GAAG,KAAK,CAAC,KAAK,EAAE,CAAC;IAChD,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC"}
@@ -0,0 +1,3 @@
1
+ import type { Bounds } from './ui-map-types';
2
+ /** Intersection-over-union of two [x,y,w,h] screen-space boxes. 0 when disjoint. */
3
+ export declare function iou(a: Bounds, b: Bounds): number;