@qontinui/ui-bridge 0.1.1 → 0.3.0

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 (112) hide show
  1. package/dist/ai/index.d.mts +893 -0
  2. package/dist/ai/index.d.ts +893 -0
  3. package/dist/ai/index.js +3897 -0
  4. package/dist/ai/index.js.map +1 -0
  5. package/dist/ai/index.mjs +3839 -0
  6. package/dist/ai/index.mjs.map +1 -0
  7. package/dist/babel-plugin/index.js +515 -0
  8. package/dist/babel-plugin/index.js.map +1 -0
  9. package/dist/babel-plugin/index.mjs +499 -0
  10. package/dist/babel-plugin/index.mjs.map +1 -0
  11. package/dist/control/index.d.mts +5 -4
  12. package/dist/control/index.d.ts +5 -4
  13. package/dist/core/index.d.mts +115 -42
  14. package/dist/core/index.d.ts +115 -42
  15. package/dist/core/index.js +0 -983
  16. package/dist/core/index.js.map +1 -1
  17. package/dist/core/index.mjs +1 -972
  18. package/dist/core/index.mjs.map +1 -1
  19. package/dist/debug/index.d.mts +3 -3
  20. package/dist/debug/index.d.ts +3 -3
  21. package/dist/index.d.mts +8 -7
  22. package/dist/index.d.ts +8 -7
  23. package/dist/index.js +8249 -4163
  24. package/dist/index.js.map +1 -1
  25. package/dist/index.mjs +8193 -4152
  26. package/dist/index.mjs.map +1 -1
  27. package/dist/{metrics-QCnK0EFw.d.ts → metrics-BfiT_rhZ.d.ts} +2 -2
  28. package/dist/{metrics-BCG7z7Aq.d.mts → metrics-DTA2bwG7.d.mts} +2 -2
  29. package/dist/native/control/index.js +453 -0
  30. package/dist/native/control/index.js.map +1 -0
  31. package/dist/native/control/index.mjs +450 -0
  32. package/dist/native/control/index.mjs.map +1 -0
  33. package/dist/native/core/index.js +486 -0
  34. package/dist/native/core/index.js.map +1 -0
  35. package/dist/native/core/index.mjs +475 -0
  36. package/dist/native/core/index.mjs.map +1 -0
  37. package/dist/native/debug/index.js +451 -0
  38. package/dist/native/debug/index.js.map +1 -0
  39. package/dist/native/debug/index.mjs +449 -0
  40. package/dist/native/debug/index.mjs.map +1 -0
  41. package/dist/native/index.js +2274 -0
  42. package/dist/native/index.js.map +1 -0
  43. package/dist/native/index.mjs +2246 -0
  44. package/dist/native/index.mjs.map +1 -0
  45. package/dist/native/react/index.js +1401 -0
  46. package/dist/native/react/index.js.map +1 -0
  47. package/dist/native/react/index.mjs +1389 -0
  48. package/dist/native/react/index.mjs.map +1 -0
  49. package/dist/native/server/index.js +415 -0
  50. package/dist/native/server/index.js.map +1 -0
  51. package/dist/native/server/index.mjs +410 -0
  52. package/dist/native/server/index.mjs.map +1 -0
  53. package/dist/react/index.d.mts +20 -6
  54. package/dist/react/index.d.ts +20 -6
  55. package/dist/react/index.js +629 -14
  56. package/dist/react/index.js.map +1 -1
  57. package/dist/react/index.mjs +629 -14
  58. package/dist/react/index.mjs.map +1 -1
  59. package/dist/{registry-CT6BVVKr.d.mts → registry-BKLEm-yk.d.ts} +29 -14
  60. package/dist/{registry-D4mQ01B3.d.ts → registry-BmZgyCz8.d.mts} +29 -14
  61. package/dist/render-log/index.d.mts +1 -1
  62. package/dist/render-log/index.d.ts +1 -1
  63. package/dist/server/express.d.mts +36 -0
  64. package/dist/server/express.d.ts +36 -0
  65. package/dist/server/express.js +196 -0
  66. package/dist/server/express.js.map +1 -0
  67. package/dist/server/express.mjs +192 -0
  68. package/dist/server/express.mjs.map +1 -0
  69. package/dist/server/handlers.d.mts +93 -0
  70. package/dist/server/handlers.d.ts +93 -0
  71. package/dist/server/handlers.js +4278 -0
  72. package/dist/server/handlers.js.map +1 -0
  73. package/dist/server/handlers.mjs +4275 -0
  74. package/dist/server/handlers.mjs.map +1 -0
  75. package/dist/server/index.d.mts +10 -0
  76. package/dist/server/index.d.ts +10 -0
  77. package/dist/server/index.js +5352 -0
  78. package/dist/server/index.js.map +1 -0
  79. package/dist/server/index.mjs +5337 -0
  80. package/dist/server/index.mjs.map +1 -0
  81. package/dist/server/nextjs.d.mts +126 -0
  82. package/dist/server/nextjs.d.ts +126 -0
  83. package/dist/server/nextjs.js +287 -0
  84. package/dist/server/nextjs.js.map +1 -0
  85. package/dist/server/nextjs.mjs +282 -0
  86. package/dist/server/nextjs.mjs.map +1 -0
  87. package/dist/server/standalone.d.mts +6 -0
  88. package/dist/server/standalone.d.ts +6 -0
  89. package/dist/server/standalone.js +719 -0
  90. package/dist/server/standalone.js.map +1 -0
  91. package/dist/server/standalone.mjs +715 -0
  92. package/dist/server/standalone.mjs.map +1 -0
  93. package/dist/standalone-BURj8J3G.d.ts +212 -0
  94. package/dist/standalone-Dwmel29d.d.mts +212 -0
  95. package/dist/swc-plugin/index.d.mts +79 -0
  96. package/dist/swc-plugin/index.d.ts +79 -0
  97. package/dist/swc-plugin/index.js +15 -0
  98. package/dist/swc-plugin/index.js.map +1 -0
  99. package/dist/swc-plugin/index.mjs +9 -0
  100. package/dist/swc-plugin/index.mjs.map +1 -0
  101. package/dist/types-B5Q0GVo0.d.mts +646 -0
  102. package/dist/{types-DdJD9yw5.d.mts → types-B7J7noLK.d.mts} +1 -1
  103. package/dist/{types-BDkXy5si.d.ts → types-BkNRILUa.d.ts} +1 -1
  104. package/dist/types-CEQLnFMv.d.mts +156 -0
  105. package/dist/types-CHnlwiTK.d.ts +156 -0
  106. package/dist/types-DfPqwU-i.d.ts +646 -0
  107. package/dist/{types-BpvpStn3.d.mts → types-jKVgTI6_.d.mts} +364 -160
  108. package/dist/{types-BpvpStn3.d.ts → types-jKVgTI6_.d.ts} +364 -160
  109. package/package.json +111 -3
  110. package/swc-plugin-wasm/ui_bridge_swc_plugin.wasm +0 -0
  111. package/dist/websocket-client-B2LC9CYc.d.mts +0 -124
  112. package/dist/websocket-client-DupH0X7B.d.ts +0 -124
@@ -188,6 +188,376 @@ function findElementByIdentifier(identifier, root = document) {
188
188
  return null;
189
189
  }
190
190
 
191
+ // src/ai/fuzzy-matcher.ts
192
+ var DEFAULT_FUZZY_CONFIG = {
193
+ threshold: 0.7,
194
+ levenshteinWeight: 0.3,
195
+ jaroWinklerWeight: 0.4,
196
+ ngramWeight: 0.3,
197
+ ngramSize: 2,
198
+ caseSensitive: false,
199
+ ignoreWhitespace: true
200
+ };
201
+ function levenshteinDistance(s1, s2) {
202
+ const len1 = s1.length;
203
+ const len2 = s2.length;
204
+ const matrix = Array(len1 + 1).fill(null).map(() => Array(len2 + 1).fill(0));
205
+ for (let i = 0; i <= len1; i++) matrix[i][0] = i;
206
+ for (let j = 0; j <= len2; j++) matrix[0][j] = j;
207
+ for (let i = 1; i <= len1; i++) {
208
+ for (let j = 1; j <= len2; j++) {
209
+ const cost = s1[i - 1] === s2[j - 1] ? 0 : 1;
210
+ matrix[i][j] = Math.min(
211
+ matrix[i - 1][j] + 1,
212
+ // deletion
213
+ matrix[i][j - 1] + 1,
214
+ // insertion
215
+ matrix[i - 1][j - 1] + cost
216
+ // substitution
217
+ );
218
+ }
219
+ }
220
+ return matrix[len1][len2];
221
+ }
222
+ function levenshteinSimilarity(s1, s2) {
223
+ if (s1.length === 0 && s2.length === 0) return 1;
224
+ if (s1.length === 0 || s2.length === 0) return 0;
225
+ const distance = levenshteinDistance(s1, s2);
226
+ const maxLength = Math.max(s1.length, s2.length);
227
+ return 1 - distance / maxLength;
228
+ }
229
+ function jaroSimilarity(s1, s2) {
230
+ if (s1.length === 0 && s2.length === 0) return 1;
231
+ if (s1.length === 0 || s2.length === 0) return 0;
232
+ const matchDistance = Math.floor(Math.max(s1.length, s2.length) / 2) - 1;
233
+ const s1Matches = new Array(s1.length).fill(false);
234
+ const s2Matches = new Array(s2.length).fill(false);
235
+ let matches = 0;
236
+ let transpositions = 0;
237
+ for (let i = 0; i < s1.length; i++) {
238
+ const start = Math.max(0, i - matchDistance);
239
+ const end = Math.min(i + matchDistance + 1, s2.length);
240
+ for (let j = start; j < end; j++) {
241
+ if (s2Matches[j] || s1[i] !== s2[j]) continue;
242
+ s1Matches[i] = true;
243
+ s2Matches[j] = true;
244
+ matches++;
245
+ break;
246
+ }
247
+ }
248
+ if (matches === 0) return 0;
249
+ let k = 0;
250
+ for (let i = 0; i < s1.length; i++) {
251
+ if (!s1Matches[i]) continue;
252
+ while (!s2Matches[k]) k++;
253
+ if (s1[i] !== s2[k]) transpositions++;
254
+ k++;
255
+ }
256
+ return (matches / s1.length + matches / s2.length + (matches - transpositions / 2) / matches) / 3;
257
+ }
258
+ function jaroWinklerSimilarity(s1, s2, prefixScale = 0.1) {
259
+ const jaroSim = jaroSimilarity(s1, s2);
260
+ let prefixLength = 0;
261
+ const maxPrefix = Math.min(4, Math.min(s1.length, s2.length));
262
+ for (let i = 0; i < maxPrefix; i++) {
263
+ if (s1[i] === s2[i]) {
264
+ prefixLength++;
265
+ } else {
266
+ break;
267
+ }
268
+ }
269
+ return jaroSim + prefixLength * prefixScale * (1 - jaroSim);
270
+ }
271
+ function generateNgrams(s, n) {
272
+ const ngrams = /* @__PURE__ */ new Set();
273
+ if (s.length < n) {
274
+ ngrams.add(s);
275
+ return ngrams;
276
+ }
277
+ for (let i = 0; i <= s.length - n; i++) {
278
+ ngrams.add(s.substring(i, i + n));
279
+ }
280
+ return ngrams;
281
+ }
282
+ function ngramSimilarity(s1, s2, n = 2) {
283
+ if (s1.length === 0 && s2.length === 0) return 1;
284
+ if (s1.length === 0 || s2.length === 0) return 0;
285
+ const ngrams1 = generateNgrams(s1, n);
286
+ const ngrams2 = generateNgrams(s2, n);
287
+ let intersection = 0;
288
+ for (const ngram of ngrams1) {
289
+ if (ngrams2.has(ngram)) {
290
+ intersection++;
291
+ }
292
+ }
293
+ const union = ngrams1.size + ngrams2.size - intersection;
294
+ return union === 0 ? 0 : intersection / union;
295
+ }
296
+ function normalizeString(s, config = {}) {
297
+ let normalized = s;
298
+ if (!config.caseSensitive) {
299
+ normalized = normalized.toLowerCase();
300
+ }
301
+ if (config.ignoreWhitespace !== false) {
302
+ normalized = normalized.replace(/\s+/g, " ").trim();
303
+ }
304
+ return normalized;
305
+ }
306
+ function fuzzyMatch(source, target, config = {}) {
307
+ const finalConfig = { ...DEFAULT_FUZZY_CONFIG, ...config };
308
+ const normalizedSource = normalizeString(source, finalConfig);
309
+ const normalizedTarget = normalizeString(target, finalConfig);
310
+ const levenshteinScore = levenshteinSimilarity(normalizedSource, normalizedTarget);
311
+ const jaroWinklerScore = jaroWinklerSimilarity(normalizedSource, normalizedTarget);
312
+ const ngramScore = ngramSimilarity(normalizedSource, normalizedTarget, finalConfig.ngramSize);
313
+ const similarity = levenshteinScore * finalConfig.levenshteinWeight + jaroWinklerScore * finalConfig.jaroWinklerWeight + ngramScore * finalConfig.ngramWeight;
314
+ return {
315
+ similarity,
316
+ isMatch: similarity >= finalConfig.threshold,
317
+ scores: {
318
+ levenshtein: levenshteinScore,
319
+ jaroWinkler: jaroWinklerScore,
320
+ ngram: ngramScore
321
+ },
322
+ normalizedSource,
323
+ normalizedTarget
324
+ };
325
+ }
326
+ function tokenize(s) {
327
+ return s.replace(/([a-z])([A-Z])/g, "$1 $2").replace(/[_-]/g, " ").replace(/\s+/g, " ").trim().toLowerCase().split(" ").filter((token) => token.length > 0);
328
+ }
329
+
330
+ // src/ai/alias-generator.ts
331
+ var DEFAULT_ALIAS_CONFIG = {
332
+ includeText: true,
333
+ includeAriaLabel: true,
334
+ includePlaceholder: true,
335
+ includeTitle: true,
336
+ includeSynonyms: true,
337
+ maxAliases: 20,
338
+ minLength: 2,
339
+ maxLength: 50
340
+ };
341
+ var SYNONYMS = {
342
+ // Submit-related
343
+ submit: ["send", "go", "confirm", "ok", "apply", "save", "done", "finish"],
344
+ send: ["submit", "deliver", "post"],
345
+ save: ["submit", "store", "keep", "apply"],
346
+ cancel: ["close", "dismiss", "abort", "back", "exit", "quit", "nevermind"],
347
+ close: ["cancel", "dismiss", "exit", "x"],
348
+ delete: ["remove", "trash", "erase", "clear", "destroy"],
349
+ remove: ["delete", "clear", "discard"],
350
+ edit: ["modify", "change", "update", "alter"],
351
+ update: ["edit", "modify", "save", "refresh"],
352
+ add: ["create", "new", "plus", "insert"],
353
+ create: ["add", "new", "make"],
354
+ search: ["find", "lookup", "query", "filter"],
355
+ find: ["search", "locate", "lookup"],
356
+ login: ["signin", "sign in", "log in", "authenticate", "enter"],
357
+ logout: ["signout", "sign out", "log out", "exit"],
358
+ register: ["signup", "sign up", "join", "create account"],
359
+ next: ["continue", "forward", "proceed", "advance"],
360
+ previous: ["back", "backward", "return", "prior"],
361
+ back: ["previous", "return", "backward"],
362
+ start: ["begin", "launch", "initiate", "run", "execute"],
363
+ stop: ["end", "halt", "pause", "terminate"],
364
+ enable: ["activate", "turn on", "switch on"],
365
+ disable: ["deactivate", "turn off", "switch off"],
366
+ show: ["display", "reveal", "view", "open"],
367
+ hide: ["conceal", "collapse", "close"],
368
+ expand: ["open", "show", "unfold", "reveal"],
369
+ collapse: ["close", "hide", "fold", "minimize"],
370
+ yes: ["ok", "confirm", "agree", "accept"],
371
+ no: ["cancel", "decline", "reject", "deny"],
372
+ help: ["support", "assistance", "info", "information", "faq"],
373
+ settings: ["preferences", "options", "config", "configuration"],
374
+ profile: ["account", "user", "me"],
375
+ download: ["export", "save", "get"],
376
+ upload: ["import", "load", "attach"],
377
+ refresh: ["reload", "update", "sync"],
378
+ copy: ["duplicate", "clone"],
379
+ paste: ["insert"],
380
+ select: ["choose", "pick"],
381
+ toggle: ["switch", "flip"],
382
+ // Form fields
383
+ email: ["e-mail", "mail"],
384
+ password: ["pass", "pwd", "secret"],
385
+ username: ["user", "login", "account", "name"],
386
+ firstname: ["first name", "given name", "forename"],
387
+ lastname: ["last name", "surname", "family name"],
388
+ fullname: ["full name", "name", "complete name"],
389
+ phone: ["telephone", "tel", "mobile", "cell"],
390
+ address: ["location", "street"],
391
+ city: ["town"],
392
+ country: ["nation"],
393
+ zip: ["zipcode", "postal", "postal code", "postcode"],
394
+ // Navigation
395
+ home: ["main", "start", "dashboard"],
396
+ menu: ["navigation", "nav"],
397
+ sidebar: ["side bar", "side panel", "side menu"]
398
+ };
399
+ var ELEMENT_ACTION_WORDS = {
400
+ button: ["button", "btn", "click"],
401
+ input: ["input", "field", "textbox", "box"],
402
+ textarea: ["textarea", "text area", "text field", "multiline"],
403
+ select: ["select", "dropdown", "combo", "picker", "chooser"],
404
+ checkbox: ["checkbox", "check", "tick"],
405
+ radio: ["radio", "option", "choice"],
406
+ link: ["link", "anchor", "href"],
407
+ form: ["form"],
408
+ menu: ["menu"],
409
+ menuitem: ["menu item", "option"],
410
+ tab: ["tab"],
411
+ dialog: ["dialog", "modal", "popup"],
412
+ switch: ["switch", "toggle"],
413
+ slider: ["slider", "range"]
414
+ };
415
+ function normalizeAlias(text) {
416
+ return text.toLowerCase().replace(/[^\w\s]/g, " ").replace(/\s+/g, " ").trim();
417
+ }
418
+ function extractWords(text) {
419
+ const tokens = tokenize(text);
420
+ return tokens.filter((t) => t.length >= 2);
421
+ }
422
+ function generateTextAliases(text, config) {
423
+ if (!text || !config.includeText) return [];
424
+ const aliases = [];
425
+ const normalized = normalizeAlias(text);
426
+ if (normalized.length >= config.minLength && normalized.length <= config.maxLength) {
427
+ aliases.push(normalized);
428
+ }
429
+ const words = extractWords(text);
430
+ for (const word of words) {
431
+ if (word.length >= config.minLength) {
432
+ aliases.push(word);
433
+ }
434
+ }
435
+ if (words.length >= 2 && words.length <= 4) {
436
+ const twoWords = words.slice(0, 2).join(" ");
437
+ if (twoWords.length <= config.maxLength) {
438
+ aliases.push(twoWords);
439
+ }
440
+ if (words.length > 2) {
441
+ const lastTwo = words.slice(-2).join(" ");
442
+ if (lastTwo.length <= config.maxLength) {
443
+ aliases.push(lastTwo);
444
+ }
445
+ }
446
+ }
447
+ return aliases;
448
+ }
449
+ function generateSynonyms(aliases, config) {
450
+ if (!config.includeSynonyms) return [];
451
+ const synonyms = [];
452
+ for (const alias of aliases) {
453
+ const words = alias.toLowerCase().split(/\s+/);
454
+ for (const word of words) {
455
+ if (SYNONYMS[word]) {
456
+ for (const synonym of SYNONYMS[word]) {
457
+ const newAlias = alias.toLowerCase().replace(word, synonym);
458
+ if (newAlias !== alias.toLowerCase()) {
459
+ synonyms.push(newAlias);
460
+ }
461
+ if (synonym.length >= config.minLength) {
462
+ synonyms.push(synonym);
463
+ }
464
+ }
465
+ }
466
+ }
467
+ }
468
+ return synonyms;
469
+ }
470
+ function generateTypeAliases(elementType) {
471
+ const type = elementType.toLowerCase();
472
+ return ELEMENT_ACTION_WORDS[type] || [type];
473
+ }
474
+ function generateAliases(input, config = {}) {
475
+ const finalConfig = { ...DEFAULT_ALIAS_CONFIG, ...config };
476
+ const aliasSet = /* @__PURE__ */ new Set();
477
+ const addAlias = (alias) => {
478
+ const normalized = normalizeAlias(alias);
479
+ if (normalized.length >= finalConfig.minLength && normalized.length <= finalConfig.maxLength) {
480
+ aliasSet.add(normalized);
481
+ }
482
+ };
483
+ const addAliases = (aliases2) => {
484
+ for (const alias of aliases2) {
485
+ addAlias(alias);
486
+ }
487
+ };
488
+ if (finalConfig.includeText && input.textContent) {
489
+ addAliases(generateTextAliases(input.textContent, finalConfig));
490
+ }
491
+ if (finalConfig.includeAriaLabel && input.ariaLabel) {
492
+ addAliases(generateTextAliases(input.ariaLabel, finalConfig));
493
+ }
494
+ if (finalConfig.includeAriaLabel && input.ariaLabelledBy) {
495
+ addAliases(generateTextAliases(input.ariaLabelledBy, finalConfig));
496
+ }
497
+ if (finalConfig.includePlaceholder && input.placeholder) {
498
+ addAliases(generateTextAliases(input.placeholder, finalConfig));
499
+ }
500
+ if (finalConfig.includeTitle && input.title) {
501
+ addAliases(generateTextAliases(input.title, finalConfig));
502
+ }
503
+ if (input.labelText) {
504
+ addAliases(generateTextAliases(input.labelText, finalConfig));
505
+ }
506
+ if (input.id) {
507
+ addAliases(extractWords(input.id));
508
+ }
509
+ if (input.name) {
510
+ addAliases(extractWords(input.name));
511
+ }
512
+ if (input.value && (input.elementType === "button" || input.inputType === "submit" || input.inputType === "button")) {
513
+ addAliases(generateTextAliases(input.value, finalConfig));
514
+ }
515
+ if (input.elementType) {
516
+ addAliases(generateTypeAliases(input.elementType));
517
+ }
518
+ if (input.inputType) {
519
+ addAlias(input.inputType);
520
+ if (input.inputType === "email") {
521
+ addAliases(["email", "e-mail", "email address"]);
522
+ } else if (input.inputType === "password") {
523
+ addAliases(["password", "pass", "pwd"]);
524
+ } else if (input.inputType === "tel") {
525
+ addAliases(["phone", "telephone", "mobile"]);
526
+ } else if (input.inputType === "url") {
527
+ addAliases(["url", "website", "link", "address"]);
528
+ } else if (input.inputType === "search") {
529
+ addAliases(["search", "find", "query"]);
530
+ }
531
+ }
532
+ if (finalConfig.includeSynonyms) {
533
+ const currentAliases = Array.from(aliasSet);
534
+ addAliases(generateSynonyms(currentAliases, finalConfig));
535
+ }
536
+ let aliases = Array.from(aliasSet);
537
+ aliases.sort((a, b) => a.length - b.length);
538
+ if (aliases.length > finalConfig.maxAliases) {
539
+ aliases = aliases.slice(0, finalConfig.maxAliases);
540
+ }
541
+ return aliases;
542
+ }
543
+ function generateDescription(input) {
544
+ const parts = [];
545
+ let name = input.ariaLabel || input.labelText || input.textContent || input.placeholder || input.title || input.id || input.name;
546
+ if (name) {
547
+ name = name.trim();
548
+ if (name.length > 30) {
549
+ name = name.substring(0, 27) + "...";
550
+ }
551
+ parts.push(`"${name}"`);
552
+ }
553
+ const typeWords = ELEMENT_ACTION_WORDS[input.elementType || ""] || [input.elementType || "element"];
554
+ parts.push(typeWords[0]);
555
+ if (input.inputType && input.inputType !== "text") {
556
+ parts.push(`(${input.inputType})`);
557
+ }
558
+ return parts.join(" ");
559
+ }
560
+
191
561
  // src/core/registry.ts
192
562
  function getElementState(element) {
193
563
  const rect = element.getBoundingClientRect();
@@ -386,9 +756,13 @@ var UIBridgeRegistry = class {
386
756
  registerElement(id, element, options = {}) {
387
757
  const type = options.type ?? inferElementType(element);
388
758
  const actions = options.actions ?? inferActions(type);
389
- element.setAttribute("data-ui-id", id);
759
+ const existingUiId = element.getAttribute("data-ui-id");
760
+ const actualId = existingUiId || id;
761
+ if (!existingUiId) {
762
+ element.setAttribute("data-ui-id", actualId);
763
+ }
390
764
  const registered = {
391
- id,
765
+ id: actualId,
392
766
  element,
393
767
  type,
394
768
  label: options.label,
@@ -399,8 +773,8 @@ var UIBridgeRegistry = class {
399
773
  registeredAt: Date.now(),
400
774
  mounted: true
401
775
  };
402
- this.elements.set(id, registered);
403
- this.emit("element:registered", { id, type, label: options.label });
776
+ this.elements.set(actualId, registered);
777
+ this.emit("element:registered", { id: actualId, type, label: options.label });
404
778
  return registered;
405
779
  }
406
780
  /**
@@ -440,6 +814,209 @@ var UIBridgeRegistry = class {
440
814
  }
441
815
  return void 0;
442
816
  }
817
+ /**
818
+ * Search for elements using AI search criteria
819
+ */
820
+ searchElements(criteria) {
821
+ const results = [];
822
+ const threshold = criteria.fuzzyThreshold ?? 0.7;
823
+ for (const element of this.elements.values()) {
824
+ if (!element.mounted) continue;
825
+ const state = element.getState();
826
+ if (!criteria.fuzzy && !state.visible) continue;
827
+ const aliases = element.aliases ?? this.generateElementAliases(element);
828
+ const textContent = state.textContent?.trim() || "";
829
+ const label = element.label || "";
830
+ let maxScore = 0;
831
+ const matchReasons = [];
832
+ const scores = {};
833
+ if (criteria.text) {
834
+ if (textContent.toLowerCase() === criteria.text.toLowerCase() || label.toLowerCase() === criteria.text.toLowerCase()) {
835
+ maxScore = 1;
836
+ matchReasons.push("exact text match");
837
+ scores.text = 1;
838
+ } else if (criteria.fuzzy !== false) {
839
+ const textResult = fuzzyMatch(criteria.text, textContent, { threshold });
840
+ const labelResult = fuzzyMatch(criteria.text, label, { threshold });
841
+ const bestResult = textResult.similarity > labelResult.similarity ? textResult : labelResult;
842
+ if (bestResult.isMatch) {
843
+ scores.text = bestResult.similarity;
844
+ if (bestResult.similarity > maxScore) {
845
+ maxScore = bestResult.similarity;
846
+ matchReasons.push(`text similarity: ${(bestResult.similarity * 100).toFixed(0)}%`);
847
+ }
848
+ }
849
+ }
850
+ }
851
+ if (criteria.textContains) {
852
+ if (textContent.toLowerCase().includes(criteria.textContains.toLowerCase()) || label.toLowerCase().includes(criteria.textContains.toLowerCase())) {
853
+ const containsScore = 0.85;
854
+ scores.text = Math.max(scores.text ?? 0, containsScore);
855
+ if (containsScore > maxScore) {
856
+ maxScore = containsScore;
857
+ matchReasons.push("text contains");
858
+ }
859
+ }
860
+ }
861
+ if (criteria.accessibleName) {
862
+ const ariaLabel = element.element.getAttribute("aria-label") || "";
863
+ const accessibleName = ariaLabel || label || textContent;
864
+ if (accessibleName.toLowerCase() === criteria.accessibleName.toLowerCase()) {
865
+ scores.accessibility = 1;
866
+ if (1 > maxScore) {
867
+ maxScore = 1;
868
+ matchReasons.push("accessible name match");
869
+ }
870
+ } else if (criteria.fuzzy !== false) {
871
+ const result = fuzzyMatch(criteria.accessibleName, accessibleName, { threshold });
872
+ if (result.isMatch) {
873
+ scores.accessibility = result.similarity;
874
+ if (result.similarity > maxScore) {
875
+ maxScore = result.similarity;
876
+ matchReasons.push(`accessible name similarity: ${(result.similarity * 100).toFixed(0)}%`);
877
+ }
878
+ }
879
+ }
880
+ }
881
+ if (criteria.role) {
882
+ const role = element.element.getAttribute("role") || this.inferRole(element.type);
883
+ if (role?.toLowerCase() === criteria.role.toLowerCase()) {
884
+ scores.role = 1;
885
+ if (1 > maxScore) {
886
+ maxScore = 1;
887
+ matchReasons.push(`role: ${criteria.role}`);
888
+ }
889
+ }
890
+ }
891
+ if (criteria.type) {
892
+ if (element.type === criteria.type) {
893
+ const typeScore = 0.9;
894
+ scores.role = Math.max(scores.role ?? 0, typeScore);
895
+ if (typeScore > maxScore) {
896
+ maxScore = typeScore;
897
+ matchReasons.push(`type: ${criteria.type}`);
898
+ }
899
+ }
900
+ }
901
+ for (const alias of aliases) {
902
+ const searchText = criteria.text || criteria.textContains || criteria.accessibleName;
903
+ if (searchText) {
904
+ if (alias.toLowerCase() === searchText.toLowerCase()) {
905
+ scores.fuzzy = 1;
906
+ if (1 > maxScore) {
907
+ maxScore = 1;
908
+ matchReasons.push(`alias: "${alias}"`);
909
+ }
910
+ } else if (criteria.fuzzy !== false) {
911
+ const result = fuzzyMatch(searchText, alias, { threshold });
912
+ if (result.isMatch && result.similarity > (scores.fuzzy ?? 0)) {
913
+ scores.fuzzy = result.similarity;
914
+ if (result.similarity > maxScore) {
915
+ maxScore = result.similarity;
916
+ matchReasons.push(`fuzzy alias: "${alias}"`);
917
+ }
918
+ }
919
+ }
920
+ }
921
+ }
922
+ if (maxScore >= threshold) {
923
+ const aiElement = {
924
+ id: element.id,
925
+ type: element.type,
926
+ label: element.label,
927
+ tagName: element.element.tagName.toLowerCase(),
928
+ role: element.element.getAttribute("role") || void 0,
929
+ accessibleName: element.element.getAttribute("aria-label") || element.label,
930
+ actions: element.actions,
931
+ state,
932
+ registered: true,
933
+ description: element.description || generateDescription({
934
+ textContent,
935
+ ariaLabel: element.element.getAttribute("aria-label"),
936
+ elementType: element.type,
937
+ id: element.id,
938
+ labelText: element.label
939
+ }),
940
+ aliases,
941
+ purpose: element.purpose,
942
+ suggestedActions: [],
943
+ semanticType: element.semanticType
944
+ };
945
+ results.push({
946
+ element: aiElement,
947
+ confidence: maxScore,
948
+ matchReasons,
949
+ scores
950
+ });
951
+ }
952
+ }
953
+ results.sort((a, b) => b.confidence - a.confidence);
954
+ return results;
955
+ }
956
+ /**
957
+ * Find element by visible text
958
+ */
959
+ findByText(text, fuzzy = true) {
960
+ const results = this.searchElements({ text, fuzzy, fuzzyThreshold: fuzzy ? 0.7 : 1 });
961
+ if (results.length > 0) {
962
+ return this.elements.get(results[0].element.id);
963
+ }
964
+ return void 0;
965
+ }
966
+ /**
967
+ * Find element by accessible name
968
+ */
969
+ findByAccessibleName(name) {
970
+ const results = this.searchElements({ accessibleName: name, fuzzy: true });
971
+ if (results.length > 0) {
972
+ return this.elements.get(results[0].element.id);
973
+ }
974
+ return void 0;
975
+ }
976
+ /**
977
+ * Generate aliases for an element
978
+ */
979
+ generateElementAliases(element) {
980
+ const state = element.getState();
981
+ return generateAliases({
982
+ textContent: state.textContent,
983
+ ariaLabel: element.element.getAttribute("aria-label"),
984
+ placeholder: element.element.getAttribute("placeholder"),
985
+ title: element.element.getAttribute("title"),
986
+ elementType: element.type,
987
+ tagName: element.element.tagName.toLowerCase(),
988
+ id: element.id,
989
+ labelText: element.label
990
+ });
991
+ }
992
+ /**
993
+ * Infer ARIA role from element type
994
+ */
995
+ inferRole(type) {
996
+ const roleMap = {
997
+ button: "button",
998
+ input: "textbox",
999
+ select: "combobox",
1000
+ checkbox: "checkbox",
1001
+ radio: "radio",
1002
+ link: "link",
1003
+ form: void 0,
1004
+ textarea: "textbox",
1005
+ menu: "menu",
1006
+ menuitem: "menuitem",
1007
+ tab: "tab",
1008
+ dialog: "dialog",
1009
+ custom: void 0,
1010
+ switch: "switch",
1011
+ slider: "slider",
1012
+ combobox: "combobox",
1013
+ listbox: "listbox",
1014
+ option: "option",
1015
+ textbox: "textbox",
1016
+ generic: void 0
1017
+ };
1018
+ return roleMap[type];
1019
+ }
443
1020
  /**
444
1021
  * Register a component
445
1022
  */
@@ -456,7 +1033,9 @@ var UIBridgeRegistry = class {
456
1033
  })) ?? [],
457
1034
  elementIds: options.elementIds,
458
1035
  registeredAt: Date.now(),
459
- mounted: true
1036
+ mounted: true,
1037
+ getState: options.getState,
1038
+ getComputed: options.getComputed
460
1039
  };
461
1040
  this.components.set(id, registered);
462
1041
  this.emit("component:registered", { id, name: options.name });
@@ -487,6 +1066,20 @@ var UIBridgeRegistry = class {
487
1066
  getAllComponents() {
488
1067
  return Array.from(this.components.values());
489
1068
  }
1069
+ /**
1070
+ * Get the current state and computed properties of a component
1071
+ */
1072
+ getComponentState(id) {
1073
+ const component = this.components.get(id);
1074
+ if (!component || !component.mounted) {
1075
+ return null;
1076
+ }
1077
+ return {
1078
+ state: component.getState?.() ?? {},
1079
+ computed: component.getComputed?.() ?? {},
1080
+ timestamp: Date.now()
1081
+ };
1082
+ }
490
1083
  /**
491
1084
  * Register a workflow
492
1085
  */
@@ -3259,11 +3852,31 @@ function useUIComponent(options) {
3259
3852
  const registeredRef = useRef(false);
3260
3853
  const actionsRef = useRef(options.actions || []);
3261
3854
  const elementIdsRef = useRef(options.elementIds || []);
3855
+ const stateRef = useRef(options.state);
3856
+ const computedRef = useRef(options.computed);
3262
3857
  const { id, name, description, autoRegister = true } = options;
3263
3858
  useEffect(() => {
3264
3859
  actionsRef.current = options.actions || [];
3265
3860
  elementIdsRef.current = options.elementIds || [];
3266
- }, [options.actions, options.elementIds]);
3861
+ stateRef.current = options.state;
3862
+ computedRef.current = options.computed;
3863
+ }, [options.actions, options.elementIds, options.state, options.computed]);
3864
+ const createGetComputed = useCallback(() => {
3865
+ return () => {
3866
+ const computed = computedRef.current;
3867
+ if (!computed) return {};
3868
+ const result = {};
3869
+ for (const [key, def] of Object.entries(computed)) {
3870
+ try {
3871
+ const getter = typeof def === "function" ? def : def.getter;
3872
+ result[key] = getter();
3873
+ } catch {
3874
+ result[key] = void 0;
3875
+ }
3876
+ }
3877
+ return result;
3878
+ };
3879
+ }, []);
3267
3880
  const register = useCallback(() => {
3268
3881
  if (!bridge || registeredRef.current) return;
3269
3882
  bridge.registry.registerComponent(id, {
@@ -3275,10 +3888,12 @@ function useUIComponent(options) {
3275
3888
  description: a.description,
3276
3889
  handler: a.handler
3277
3890
  })),
3278
- elementIds: elementIdsRef.current
3891
+ elementIds: elementIdsRef.current,
3892
+ getState: stateRef.current,
3893
+ getComputed: createGetComputed()
3279
3894
  });
3280
3895
  registeredRef.current = true;
3281
- }, [bridge, id, name, description]);
3896
+ }, [bridge, id, name, description, createGetComputed]);
3282
3897
  const unregister = useCallback(() => {
3283
3898
  if (!bridge || !registeredRef.current) return;
3284
3899
  bridge.registry.unregisterComponent(id);
@@ -4134,24 +4749,24 @@ function useAutoRegister(options = {}) {
4134
4749
  const type = inferElementType2(element);
4135
4750
  const actions = inferActions2(type);
4136
4751
  const label = getAccessibleLabel(element);
4137
- bridge.registry.registerElement(uniqueId, element, {
4752
+ const registered = bridge.registry.registerElement(uniqueId, element, {
4138
4753
  type,
4139
4754
  actions,
4140
4755
  label
4141
4756
  });
4142
- registeredElementsRef.current.set(element, uniqueId);
4143
- onRegister?.(uniqueId, element);
4757
+ registeredElementsRef.current.set(element, registered.id);
4758
+ onRegister?.(registered.id, element);
4144
4759
  } else {
4145
4760
  const type = inferElementType2(element);
4146
4761
  const actions = inferActions2(type);
4147
4762
  const label = getAccessibleLabel(element);
4148
- bridge.registry.registerElement(id, element, {
4763
+ const registered = bridge.registry.registerElement(id, element, {
4149
4764
  type,
4150
4765
  actions,
4151
4766
  label
4152
4767
  });
4153
- registeredElementsRef.current.set(element, id);
4154
- onRegister?.(id, element);
4768
+ registeredElementsRef.current.set(element, registered.id);
4769
+ onRegister?.(registered.id, element);
4155
4770
  }
4156
4771
  },
4157
4772
  [bridge, idStrategy, customGenerateId, onRegister]