auto-webmcp 0.3.8 → 0.3.10
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/analyzer.d.ts +1 -1
- package/dist/analyzer.d.ts.map +1 -1
- package/dist/auto-webmcp.cjs.js +77 -15
- package/dist/auto-webmcp.cjs.js.map +3 -3
- package/dist/auto-webmcp.esm.js +77 -15
- package/dist/auto-webmcp.esm.js.map +3 -3
- package/dist/auto-webmcp.iife.js +1 -1
- package/dist/auto-webmcp.iife.js.map +3 -3
- package/dist/discovery.d.ts.map +1 -1
- package/dist/interceptor.d.ts.map +1 -1
- package/package.json +1 -1
package/dist/analyzer.d.ts
CHANGED
|
@@ -25,5 +25,5 @@ export declare function analyzeForm(form: HTMLFormElement, override?: FormOverri
|
|
|
25
25
|
* Derive ToolMetadata from a group of form controls that are NOT inside a <form>.
|
|
26
26
|
* Used by discovery.ts's orphan-input scanner for pages like newsletter landing pages.
|
|
27
27
|
*/
|
|
28
|
-
export declare function analyzeOrphanInputGroup(container: Element, inputs: Array<HTMLInputElement | HTMLTextAreaElement | HTMLSelectElement>, submitBtn: HTMLButtonElement | HTMLInputElement | null): ToolMetadata;
|
|
28
|
+
export declare function analyzeOrphanInputGroup(container: Element, inputs: Array<HTMLInputElement | HTMLTextAreaElement | HTMLSelectElement | HTMLElement>, submitBtn: HTMLButtonElement | HTMLInputElement | null): ToolMetadata;
|
|
29
29
|
//# sourceMappingURL=analyzer.d.ts.map
|
package/dist/analyzer.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"analyzer.d.ts","sourceRoot":"","sources":["../src/analyzer.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,UAAU,EAAmJ,MAAM,aAAa,CAAC;AAC1L,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAE3C,MAAM,WAAW,eAAe;IAC9B,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,aAAa,CAAC,EAAE,OAAO,CAAC;CACzB;AAED,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,UAAU,CAAC;IACxB,WAAW,CAAC,EAAE,eAAe,CAAC;IAC9B,6FAA6F;IAC7F,aAAa,CAAC,EAAE,GAAG,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACtC;AAKD,iDAAiD;AACjD,wBAAgB,cAAc,IAAI,IAAI,CAErC;AAED,gDAAgD;AAChD,wBAAgB,WAAW,CAAC,IAAI,EAAE,eAAe,EAAE,QAAQ,CAAC,EAAE,YAAY,GAAG,YAAY,CAOxF;
|
|
1
|
+
{"version":3,"file":"analyzer.d.ts","sourceRoot":"","sources":["../src/analyzer.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,UAAU,EAAmJ,MAAM,aAAa,CAAC;AAC1L,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAE3C,MAAM,WAAW,eAAe;IAC9B,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,aAAa,CAAC,EAAE,OAAO,CAAC;CACzB;AAED,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,UAAU,CAAC;IACxB,WAAW,CAAC,EAAE,eAAe,CAAC;IAC9B,6FAA6F;IAC7F,aAAa,CAAC,EAAE,GAAG,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACtC;AAKD,iDAAiD;AACjD,wBAAgB,cAAc,IAAI,IAAI,CAErC;AAED,gDAAgD;AAChD,wBAAgB,WAAW,CAAC,IAAI,EAAE,eAAe,EAAE,QAAQ,CAAC,EAAE,YAAY,GAAG,YAAY,CAOxF;AAiqBD;;;GAGG;AACH,wBAAgB,uBAAuB,CACrC,SAAS,EAAE,OAAO,EAClB,MAAM,EAAE,KAAK,CAAC,gBAAgB,GAAG,mBAAmB,GAAG,iBAAiB,GAAG,WAAW,CAAC,EACvF,SAAS,EAAE,iBAAiB,GAAG,gBAAgB,GAAG,IAAI,GACrD,YAAY,CAMd"}
|
package/dist/auto-webmcp.cjs.js
CHANGED
|
@@ -650,6 +650,19 @@ function resolveNativeControlFallbackKey(control) {
|
|
|
650
650
|
}
|
|
651
651
|
return null;
|
|
652
652
|
}
|
|
653
|
+
function resolveAriaElementKey(el) {
|
|
654
|
+
if (el.dataset["webmcpName"])
|
|
655
|
+
return sanitizeName(el.dataset["webmcpName"]);
|
|
656
|
+
if (el.id && !AUTO_GENERATED_ID_RE.test(el.id))
|
|
657
|
+
return sanitizeName(el.id);
|
|
658
|
+
const label = el.getAttribute("aria-label");
|
|
659
|
+
if (label)
|
|
660
|
+
return sanitizeName(label);
|
|
661
|
+
const placeholder = el.getAttribute("placeholder");
|
|
662
|
+
if (placeholder)
|
|
663
|
+
return sanitizeName(placeholder);
|
|
664
|
+
return null;
|
|
665
|
+
}
|
|
653
666
|
function collectAriaControls(form) {
|
|
654
667
|
const selector = ARIA_ROLES_TO_SCAN.map((r) => `[role="${r}"]`).join(", ");
|
|
655
668
|
const rawResults = [];
|
|
@@ -908,6 +921,22 @@ function buildSchemaFromInputs(inputs) {
|
|
|
908
921
|
const processedRadioGroups = /* @__PURE__ */ new Set();
|
|
909
922
|
const processedCheckboxGroups = /* @__PURE__ */ new Set();
|
|
910
923
|
for (const control of inputs) {
|
|
924
|
+
if (!(control instanceof HTMLInputElement) && !(control instanceof HTMLTextAreaElement) && !(control instanceof HTMLSelectElement)) {
|
|
925
|
+
const fieldKey2 = resolveAriaElementKey(control);
|
|
926
|
+
if (!fieldKey2)
|
|
927
|
+
continue;
|
|
928
|
+
if (!isControlVisible(control))
|
|
929
|
+
continue;
|
|
930
|
+
const prop = { type: "string" };
|
|
931
|
+
prop.title = control.getAttribute("aria-label") ?? fieldKey2;
|
|
932
|
+
const desc2 = control.getAttribute("aria-description") ?? control.getAttribute("aria-describedby") ? null : null;
|
|
933
|
+
if (desc2)
|
|
934
|
+
prop.description = desc2;
|
|
935
|
+
properties[fieldKey2] = prop;
|
|
936
|
+
fieldElements.set(fieldKey2, control);
|
|
937
|
+
required.push(fieldKey2);
|
|
938
|
+
continue;
|
|
939
|
+
}
|
|
911
940
|
const rawName = control.name;
|
|
912
941
|
const fieldKey = (rawName ? sanitizeName(rawName) : null) || resolveNativeControlFallbackKey(control);
|
|
913
942
|
if (!fieldKey)
|
|
@@ -1303,10 +1332,17 @@ function fillAriaField(el, value) {
|
|
|
1303
1332
|
}
|
|
1304
1333
|
const htmlEl = el;
|
|
1305
1334
|
if (htmlEl.isContentEditable) {
|
|
1306
|
-
htmlEl.
|
|
1335
|
+
htmlEl.focus();
|
|
1336
|
+
const range = document.createRange();
|
|
1337
|
+
range.selectNodeContents(htmlEl);
|
|
1338
|
+
const sel = window.getSelection();
|
|
1339
|
+
sel?.removeAllRanges();
|
|
1340
|
+
sel?.addRange(range);
|
|
1341
|
+
document.execCommand("insertText", false, String(value ?? ""));
|
|
1342
|
+
} else {
|
|
1343
|
+
el.dispatchEvent(new Event("input", { bubbles: true }));
|
|
1344
|
+
el.dispatchEvent(new Event("change", { bubbles: true }));
|
|
1307
1345
|
}
|
|
1308
|
-
el.dispatchEvent(new Event("input", { bubbles: true }));
|
|
1309
|
-
el.dispatchEvent(new Event("change", { bubbles: true }));
|
|
1310
1346
|
}
|
|
1311
1347
|
function serializeFormData(form, params, fieldEls) {
|
|
1312
1348
|
const result = {};
|
|
@@ -1459,6 +1495,11 @@ async function registerForm(form, config) {
|
|
|
1459
1495
|
await registerFormTool(form, metadata, execute);
|
|
1460
1496
|
registeredForms.add(form);
|
|
1461
1497
|
registeredFormCount++;
|
|
1498
|
+
const formSubmitBtn = form.querySelector(
|
|
1499
|
+
'[type="submit"], button[data-variant="primary"], button:not([type])'
|
|
1500
|
+
) ?? null;
|
|
1501
|
+
const pendingBtns = window["__pendingSubmitBtns"] ??= {};
|
|
1502
|
+
pendingBtns[metadata.name] = formSubmitBtn;
|
|
1462
1503
|
if (config.debug) {
|
|
1463
1504
|
console.log(`[auto-webmcp] Registered: ${metadata.name}`, metadata);
|
|
1464
1505
|
}
|
|
@@ -1572,12 +1613,12 @@ var ORPHAN_EXCLUDED_TYPES = /* @__PURE__ */ new Set([
|
|
|
1572
1613
|
async function scanOrphanInputs(config) {
|
|
1573
1614
|
if (!isWebMCPSupported())
|
|
1574
1615
|
return;
|
|
1575
|
-
const SUBMIT_BTN_SELECTOR = '[type="submit"]:not([disabled]), button
|
|
1576
|
-
const SUBMIT_BTN_GROUPING_SELECTOR = '[type="submit"]';
|
|
1577
|
-
const SUBMIT_TEXT_RE = /subscribe|submit|sign[\s-]?up|send|join|go|search/i;
|
|
1616
|
+
const SUBMIT_BTN_SELECTOR = '[type="submit"]:not([disabled]), button[data-variant="primary"]:not([disabled])';
|
|
1617
|
+
const SUBMIT_BTN_GROUPING_SELECTOR = '[type="submit"], button[data-variant="primary"]';
|
|
1618
|
+
const SUBMIT_TEXT_RE = /subscribe|submit|sign[\s-]?up|send|join|go|search|post|tweet|publish/i;
|
|
1578
1619
|
const orphanInputs = Array.from(
|
|
1579
1620
|
document.querySelectorAll(
|
|
1580
|
-
|
|
1621
|
+
'input:not(form input), textarea:not(form textarea), select:not(form select), [role="textbox"]:not(form [role="textbox"]):not(input):not(textarea), [role="searchbox"]:not(form [role="searchbox"]):not(input):not(textarea), [contenteditable="true"]:not(form [contenteditable="true"]):not(input):not(textarea)'
|
|
1581
1622
|
)
|
|
1582
1623
|
).filter((el) => {
|
|
1583
1624
|
if (el instanceof HTMLInputElement && ORPHAN_EXCLUDED_TYPES.has(el.type.toLowerCase())) {
|
|
@@ -1622,11 +1663,25 @@ async function scanOrphanInputs(config) {
|
|
|
1622
1663
|
return r.width > 0 && r.height > 0;
|
|
1623
1664
|
});
|
|
1624
1665
|
let submitBtn = allCandidates[allCandidates.length - 1] ?? null;
|
|
1625
|
-
|
|
1626
|
-
|
|
1627
|
-
|
|
1628
|
-
|
|
1629
|
-
|
|
1666
|
+
if (!submitBtn) {
|
|
1667
|
+
const disabledCandidates = Array.from(
|
|
1668
|
+
container.querySelectorAll(SUBMIT_BTN_GROUPING_SELECTOR)
|
|
1669
|
+
).filter((b) => {
|
|
1670
|
+
const r = b.getBoundingClientRect();
|
|
1671
|
+
return r.width > 0 && r.height > 0 && b.disabled;
|
|
1672
|
+
});
|
|
1673
|
+
submitBtn = disabledCandidates[disabledCandidates.length - 1] ?? null;
|
|
1674
|
+
if (submitBtn)
|
|
1675
|
+
console.log(`[auto-webmcp] orphan: using disabled submit button as reference: "${submitBtn.textContent?.trim()}"`);
|
|
1676
|
+
}
|
|
1677
|
+
if (!submitBtn) {
|
|
1678
|
+
const containerBtns = Array.from(container.querySelectorAll("button")).filter((b) => {
|
|
1679
|
+
const r = b.getBoundingClientRect();
|
|
1680
|
+
return r.width > 0 && r.height > 0 && !b.disabled && SUBMIT_TEXT_RE.test(b.textContent ?? "");
|
|
1681
|
+
});
|
|
1682
|
+
submitBtn = containerBtns[containerBtns.length - 1] ?? null;
|
|
1683
|
+
if (submitBtn)
|
|
1684
|
+
console.log(`[auto-webmcp] orphan: using text-matched button in container: "${submitBtn.textContent?.trim()}"`);
|
|
1630
1685
|
}
|
|
1631
1686
|
if (!submitBtn) {
|
|
1632
1687
|
const pageBtns = Array.from(document.querySelectorAll("button")).filter(
|
|
@@ -1647,15 +1702,19 @@ async function scanOrphanInputs(config) {
|
|
|
1647
1702
|
const AUTO_ID_RE = /^_r_[0-9a-z]+_$/i;
|
|
1648
1703
|
for (const el of inputs) {
|
|
1649
1704
|
const id = el.id && !AUTO_ID_RE.test(el.id) ? el.id : null;
|
|
1650
|
-
const key = el.name || el.dataset["webmcpName"] || id || el.getAttribute("aria-label") ||
|
|
1705
|
+
const key = el.name || el.getAttribute("name") || el.dataset["webmcpName"] || id || el.getAttribute("aria-label") || el.getAttribute("placeholder") || null;
|
|
1651
1706
|
const safeKey = key ? key.toLowerCase().replace(/[^a-z0-9]+/g, "_").replace(/^_+|_+$/g, "").slice(0, 64) : null;
|
|
1652
1707
|
const matched = !!(safeKey && schemaProps[safeKey]);
|
|
1653
|
-
console.log(`[auto-webmcp] orphan: field (name="${el.name}" id="${el.id}") rawKey="${key}" safeKey="${safeKey}" matched=${matched}`);
|
|
1708
|
+
console.log(`[auto-webmcp] orphan: field (name="${el.name ?? ""}" id="${el.id}") rawKey="${key}" safeKey="${safeKey}" matched=${matched}`);
|
|
1654
1709
|
if (matched) {
|
|
1655
1710
|
inputPairs.push({ key: safeKey, el });
|
|
1656
1711
|
}
|
|
1657
1712
|
}
|
|
1658
1713
|
console.log(`[auto-webmcp] orphan: ${inputPairs.length}/${inputs.length} input(s) mapped to schema keys`);
|
|
1714
|
+
if (inputPairs.length === 0) {
|
|
1715
|
+
console.log(`[auto-webmcp] orphan: skipping group "${metadata.name}" \u2014 no inputs mapped to schema keys`);
|
|
1716
|
+
continue;
|
|
1717
|
+
}
|
|
1659
1718
|
const toolName = metadata.name;
|
|
1660
1719
|
const execute = async (params) => {
|
|
1661
1720
|
console.log(`[auto-webmcp] orphan execute: tool="${toolName}" params=`, params);
|
|
@@ -1670,7 +1729,8 @@ async function scanOrphanInputs(config) {
|
|
|
1670
1729
|
}
|
|
1671
1730
|
}
|
|
1672
1731
|
window.dispatchEvent(new CustomEvent("toolactivated", { detail: { toolName } }));
|
|
1673
|
-
|
|
1732
|
+
const shouldAutoSubmit = config.autoSubmit || !!submitBtn?.hasAttribute("toolautosubmit") || submitBtn instanceof HTMLElement && submitBtn.dataset["webmcpAutosubmit"] !== void 0 || container.hasAttribute("toolautosubmit") || container instanceof HTMLElement && container.dataset["webmcpAutosubmit"] !== void 0;
|
|
1733
|
+
if (!shouldAutoSubmit) {
|
|
1674
1734
|
console.log(`[auto-webmcp] orphan execute: autoSubmit=false, returning without clicking submit`);
|
|
1675
1735
|
return { content: [{ type: "text", text: "Fields filled. Ready to submit." }] };
|
|
1676
1736
|
}
|
|
@@ -1710,6 +1770,8 @@ async function scanOrphanInputs(config) {
|
|
|
1710
1770
|
toolDef.annotations = metadata.annotations;
|
|
1711
1771
|
}
|
|
1712
1772
|
await navigator.modelContext.registerTool(toolDef);
|
|
1773
|
+
const pendingBtns = window["__pendingSubmitBtns"] ??= {};
|
|
1774
|
+
pendingBtns[metadata.name] = submitBtn;
|
|
1713
1775
|
if (config.debug) {
|
|
1714
1776
|
console.log(`[auto-webmcp] Orphan tool registered: ${metadata.name}`, metadata);
|
|
1715
1777
|
}
|