halo-agent 2.5.0 → 2.6.1
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.
- package/package.json +1 -1
- package/scanAccessibility.js +46 -1
package/package.json
CHANGED
package/scanAccessibility.js
CHANGED
|
@@ -76,6 +76,12 @@ async function injectMmid(page) {
|
|
|
76
76
|
'[role="option"]',
|
|
77
77
|
'[role="menuitem"]',
|
|
78
78
|
'button[type="submit"]',
|
|
79
|
+
// ATS toggle-button pairs (Ashby "Yes"/"No", some Greenhouse choice
|
|
80
|
+
// chips) are rendered as plain `<button>` elements without an explicit
|
|
81
|
+
// role attribute. Without this, the scan misses every required Yes/No
|
|
82
|
+
// question on Ashby and the planner silently leaves them blank.
|
|
83
|
+
// Downstream filters drop nav/close/submit buttons by label heuristic.
|
|
84
|
+
'button',
|
|
79
85
|
'a[href]',
|
|
80
86
|
].join(',');
|
|
81
87
|
const all = document.querySelectorAll(sel);
|
|
@@ -496,7 +502,7 @@ async function scanFrameDom(frame, frameUrl) {
|
|
|
496
502
|
const seen = new Set();
|
|
497
503
|
let n = Math.floor(Math.random() * 800000) + 200000; // high offset, no main-frame collision
|
|
498
504
|
|
|
499
|
-
const sel = 'input,textarea,select,[contenteditable="true"],[role="textbox"],[role="combobox"],[role="listbox"],[role="radio"],[role="checkbox"],[role="switch"],[role="button"],button[type="submit"]';
|
|
505
|
+
const sel = 'input,textarea,select,[contenteditable="true"],[role="textbox"],[role="combobox"],[role="listbox"],[role="radio"],[role="checkbox"],[role="switch"],[role="button"],button[type="submit"],button';
|
|
500
506
|
document.querySelectorAll(sel).forEach((el) => {
|
|
501
507
|
const tag = el.tagName.toLowerCase();
|
|
502
508
|
const type = (el.type || '').toLowerCase();
|
|
@@ -567,6 +573,7 @@ async function scanFrameDom(frame, frameUrl) {
|
|
|
567
573
|
return raw.map((f) => ({
|
|
568
574
|
mmid: f.mmid,
|
|
569
575
|
role: f.forceRole || normalizeRole(f),
|
|
576
|
+
tag: f.tag, // needed by main-frame filter to distinguish <button> from [role=button]
|
|
570
577
|
label: f.label || f.textContent || '',
|
|
571
578
|
description: '',
|
|
572
579
|
required: false,
|
|
@@ -651,6 +658,21 @@ async function scanAccessibility(page) {
|
|
|
651
658
|
if (f.frameUrl) {
|
|
652
659
|
const fl = (f.label || '').trim();
|
|
653
660
|
if (f.role === 'button' && (/^remove\s+\S/i.test(fl) || /^clear\s+selection/i.test(fl) || fl === '×' || fl === '✕' || fl === 'x')) continue;
|
|
661
|
+
// Apply the same nav-button filter for in-frame buttons.
|
|
662
|
+
if (f.role === 'button' && f.tag === 'button') {
|
|
663
|
+
const ll = fl.toLowerCase().trim();
|
|
664
|
+
const navWords = [
|
|
665
|
+
'back', 'cancel', 'close', 'menu', 'open menu', 'dismiss',
|
|
666
|
+
'submit', 'submit application', 'apply', 'apply now',
|
|
667
|
+
'sign in', 'sign up', 'log in', 'login', 'logout',
|
|
668
|
+
'next', 'previous', 'continue', 'edit', 'save',
|
|
669
|
+
'save and continue', 'save & continue',
|
|
670
|
+
'toggle theme', 'change theme', 'show password', 'hide password',
|
|
671
|
+
];
|
|
672
|
+
if (navWords.includes(ll)) continue;
|
|
673
|
+
if (f.inputType === 'submit') continue;
|
|
674
|
+
if (fl.length > 80) continue;
|
|
675
|
+
}
|
|
654
676
|
if (!fl && !['button', 'link'].includes(f.role)) continue;
|
|
655
677
|
out.push(f); // already in public shape, carries frameUrl
|
|
656
678
|
continue;
|
|
@@ -673,6 +695,29 @@ async function scanAccessibility(page) {
|
|
|
673
695
|
)) {
|
|
674
696
|
continue;
|
|
675
697
|
}
|
|
698
|
+
// Filter out navigation / submit / close buttons surfaced by the
|
|
699
|
+
// broader generic-button selector. Answer-choice buttons (Yes / No /
|
|
700
|
+
// short option text) stay — they're what powers Ashby's toggle pairs.
|
|
701
|
+
if (normalizeRole(f) === 'button' && f.tag === 'button') {
|
|
702
|
+
const ll = label.toLowerCase().trim();
|
|
703
|
+
// Drop common nav buttons by exact-ish label
|
|
704
|
+
const navWords = [
|
|
705
|
+
'back', 'cancel', 'close', 'menu', 'open menu', 'dismiss',
|
|
706
|
+
'submit', 'submit application', 'apply', 'apply now',
|
|
707
|
+
'sign in', 'sign up', 'log in', 'login', 'logout',
|
|
708
|
+
'next', 'previous', 'continue', // multi-step nav — filter; the form's own pagination handles
|
|
709
|
+
'edit', 'save', 'save and continue', 'save & continue',
|
|
710
|
+
'toggle theme', 'change theme', 'show password', 'hide password',
|
|
711
|
+
'view jd', 'view job', 'open application',
|
|
712
|
+
];
|
|
713
|
+
if (navWords.includes(ll)) continue;
|
|
714
|
+
// Drop submit-type buttons even without a matching label
|
|
715
|
+
if (f.inputType === 'submit') continue;
|
|
716
|
+
// Drop very long labels — answer choices are short. >80 chars is
|
|
717
|
+
// almost certainly help text, fineprint, or accidentally-captured
|
|
718
|
+
// descendant content.
|
|
719
|
+
if (label.length > 80) continue;
|
|
720
|
+
}
|
|
676
721
|
out.push({
|
|
677
722
|
mmid: f.mmid,
|
|
678
723
|
role: normalizeRole(f),
|