@cutleryapp/agent 1.0.31 → 1.0.32
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/dist/mcp-executor.js +55 -0
- package/package.json +1 -1
package/dist/mcp-executor.js
CHANGED
|
@@ -705,6 +705,57 @@ async function tryAIClick(page, selector) {
|
|
|
705
705
|
}
|
|
706
706
|
return false;
|
|
707
707
|
}
|
|
708
|
+
/** Fill an autocomplete/typeahead input: type value, wait for dropdown, click first matching option */
|
|
709
|
+
async function tryAutocomplete(page, labelOrSelector, value) {
|
|
710
|
+
const TIMEOUT = 4000;
|
|
711
|
+
const locators = [
|
|
712
|
+
page.getByLabel(new RegExp(labelOrSelector, 'i')),
|
|
713
|
+
page.getByPlaceholder(new RegExp(labelOrSelector, 'i')),
|
|
714
|
+
page.locator(labelOrSelector),
|
|
715
|
+
];
|
|
716
|
+
for (const loc of locators) {
|
|
717
|
+
try {
|
|
718
|
+
const input = loc.first();
|
|
719
|
+
await input.waitFor({ state: 'visible', timeout: TIMEOUT });
|
|
720
|
+
await input.click({ timeout: TIMEOUT });
|
|
721
|
+
await input.fill('', { timeout: TIMEOUT });
|
|
722
|
+
// Type slowly so the autocomplete can react
|
|
723
|
+
await input.type(value, { delay: 80 });
|
|
724
|
+
// Wait for dropdown options to appear
|
|
725
|
+
await page.waitForTimeout(600);
|
|
726
|
+
// Try common dropdown option selectors
|
|
727
|
+
const optionSelectors = [
|
|
728
|
+
`[class*="option"]:has-text("${value}")`,
|
|
729
|
+
`[class*="suggestion"]:has-text("${value}")`,
|
|
730
|
+
`[class*="item"]:has-text("${value}")`,
|
|
731
|
+
`[role="option"]:has-text("${value}")`,
|
|
732
|
+
`[role="listbox"] [class*="option"]`,
|
|
733
|
+
`[class*="menu"] [class*="option"]`,
|
|
734
|
+
`[class*="dropdown"] li`,
|
|
735
|
+
`ul[class*="auto"] li`,
|
|
736
|
+
`.react-select__option`,
|
|
737
|
+
`.autocomplete-item`,
|
|
738
|
+
];
|
|
739
|
+
for (const optSel of optionSelectors) {
|
|
740
|
+
try {
|
|
741
|
+
const opt = page.locator(optSel).first();
|
|
742
|
+
if (await opt.isVisible({ timeout: 800 })) {
|
|
743
|
+
await opt.click({ timeout: TIMEOUT });
|
|
744
|
+
console.log(` ✓ Autocomplete: typed "${value}", clicked option via "${optSel}"`);
|
|
745
|
+
return true;
|
|
746
|
+
}
|
|
747
|
+
}
|
|
748
|
+
catch { /* try next */ }
|
|
749
|
+
}
|
|
750
|
+
// Fallback: press Enter if a highlighted option exists
|
|
751
|
+
await page.keyboard.press('Enter');
|
|
752
|
+
await page.waitForTimeout(300);
|
|
753
|
+
return true;
|
|
754
|
+
}
|
|
755
|
+
catch { /* try next locator */ }
|
|
756
|
+
}
|
|
757
|
+
return false;
|
|
758
|
+
}
|
|
708
759
|
/** Try filling with multiple selector strategies */
|
|
709
760
|
async function tryAIFill(page, selector, value) {
|
|
710
761
|
const TIMEOUT = 5000;
|
|
@@ -904,6 +955,10 @@ async function tryFill(page, label, value) {
|
|
|
904
955
|
errors.push(e?.message?.split("\n")[0] || String(e));
|
|
905
956
|
}
|
|
906
957
|
}
|
|
958
|
+
// Autocomplete fallback — type + wait for dropdown + click option
|
|
959
|
+
const acSuccess = await tryAutocomplete(page, label, value);
|
|
960
|
+
if (acSuccess)
|
|
961
|
+
return;
|
|
907
962
|
// AI vision fallback
|
|
908
963
|
const aiSuccess = await aiFillFallback(page, label, value);
|
|
909
964
|
if (aiSuccess)
|