auto-webmcp 0.2.6 → 0.2.8
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.map +1 -1
- package/dist/auto-webmcp.cjs.js +144 -20
- package/dist/auto-webmcp.cjs.js.map +3 -3
- package/dist/auto-webmcp.esm.js +144 -20
- package/dist/auto-webmcp.esm.js.map +3 -3
- package/dist/auto-webmcp.iife.js +2 -2
- package/dist/auto-webmcp.iife.js.map +3 -3
- package/dist/interceptor.d.ts.map +1 -1
- package/dist/schema.d.ts +1 -0
- package/dist/schema.d.ts.map +1 -1
- package/package.json +1 -1
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,EAA8H,MAAM,aAAa,CAAC;AACrK,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAE3C,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,UAAU,CAAC;IACxB,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,CAMxF;
|
|
1
|
+
{"version":3,"file":"analyzer.d.ts","sourceRoot":"","sources":["../src/analyzer.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,UAAU,EAA8H,MAAM,aAAa,CAAC;AACrK,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAE3C,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,UAAU,CAAC;IACxB,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,CAMxF;AAgcD;;;GAGG;AACH,wBAAgB,uBAAuB,CACrC,SAAS,EAAE,OAAO,EAClB,MAAM,EAAE,KAAK,CAAC,gBAAgB,GAAG,mBAAmB,GAAG,iBAAiB,CAAC,EACzE,SAAS,EAAE,iBAAiB,GAAG,gBAAgB,GAAG,IAAI,GACrD,YAAY,CAKd"}
|
package/dist/auto-webmcp.cjs.js
CHANGED
|
@@ -189,15 +189,55 @@ function buildStringSchema(input) {
|
|
|
189
189
|
prop.maxLength = input.maxLength;
|
|
190
190
|
if (input.pattern)
|
|
191
191
|
prop.pattern = input.pattern;
|
|
192
|
+
const listId = input.getAttribute("list");
|
|
193
|
+
if (listId) {
|
|
194
|
+
const datalist = input.ownerDocument.getElementById(listId);
|
|
195
|
+
if (datalist instanceof HTMLDataListElement) {
|
|
196
|
+
const options = Array.from(datalist.options).filter(
|
|
197
|
+
(o) => !o.disabled && o.value.trim() !== ""
|
|
198
|
+
);
|
|
199
|
+
if (options.length > 0) {
|
|
200
|
+
prop.enum = options.map((o) => o.value.trim());
|
|
201
|
+
prop.oneOf = options.map((o) => ({
|
|
202
|
+
const: o.value.trim(),
|
|
203
|
+
title: o.textContent?.trim() || o.value.trim()
|
|
204
|
+
}));
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
}
|
|
192
208
|
return prop;
|
|
193
209
|
}
|
|
194
210
|
function mapSelectElement(select) {
|
|
195
|
-
const
|
|
196
|
-
|
|
197
|
-
|
|
211
|
+
const enumValues = [];
|
|
212
|
+
const oneOf = [];
|
|
213
|
+
for (const child of Array.from(select.children)) {
|
|
214
|
+
if (child instanceof HTMLOptGroupElement) {
|
|
215
|
+
if (child.disabled)
|
|
216
|
+
continue;
|
|
217
|
+
const groupLabel = child.label?.trim() ?? "";
|
|
218
|
+
for (const opt of Array.from(child.children)) {
|
|
219
|
+
if (!(opt instanceof HTMLOptionElement))
|
|
220
|
+
continue;
|
|
221
|
+
if (opt.disabled || opt.value === "")
|
|
222
|
+
continue;
|
|
223
|
+
enumValues.push(opt.value);
|
|
224
|
+
const entry = {
|
|
225
|
+
const: opt.value,
|
|
226
|
+
title: opt.text.trim() || opt.value
|
|
227
|
+
};
|
|
228
|
+
if (groupLabel)
|
|
229
|
+
entry.group = groupLabel;
|
|
230
|
+
oneOf.push(entry);
|
|
231
|
+
}
|
|
232
|
+
} else if (child instanceof HTMLOptionElement) {
|
|
233
|
+
if (child.disabled || child.value === "")
|
|
234
|
+
continue;
|
|
235
|
+
enumValues.push(child.value);
|
|
236
|
+
oneOf.push({ const: child.value, title: child.text.trim() || child.value });
|
|
237
|
+
}
|
|
198
238
|
}
|
|
199
|
-
|
|
200
|
-
|
|
239
|
+
if (enumValues.length === 0)
|
|
240
|
+
return { type: "string" };
|
|
201
241
|
return { type: "string", enum: enumValues, oneOf };
|
|
202
242
|
}
|
|
203
243
|
function collectRadioEnum(form, name) {
|
|
@@ -404,6 +444,8 @@ function buildSchema(form) {
|
|
|
404
444
|
const schemaProp = inputTypeToSchema(control);
|
|
405
445
|
if (!schemaProp)
|
|
406
446
|
continue;
|
|
447
|
+
if (!isControlVisible(control))
|
|
448
|
+
continue;
|
|
407
449
|
schemaProp.title = inferFieldTitle(control);
|
|
408
450
|
const desc = inferFieldDescription(control);
|
|
409
451
|
if (desc)
|
|
@@ -597,6 +639,24 @@ function labelTextWithoutNested(label) {
|
|
|
597
639
|
function humanizeName(raw) {
|
|
598
640
|
return raw.replace(/[-_]/g, " ").replace(/([a-z])([A-Z])/g, "$1 $2").trim().replace(/\b\w/g, (c) => c.toUpperCase());
|
|
599
641
|
}
|
|
642
|
+
function isControlVisible(el) {
|
|
643
|
+
const style = window.getComputedStyle(el);
|
|
644
|
+
if (style.display === "none")
|
|
645
|
+
return false;
|
|
646
|
+
if (style.visibility === "hidden")
|
|
647
|
+
return false;
|
|
648
|
+
if (el.offsetParent === null && style.position !== "fixed")
|
|
649
|
+
return false;
|
|
650
|
+
let node = el;
|
|
651
|
+
while (node && node !== document.body) {
|
|
652
|
+
if (node.getAttribute("aria-hidden") === "true")
|
|
653
|
+
return false;
|
|
654
|
+
node = node.parentElement;
|
|
655
|
+
}
|
|
656
|
+
if (el.closest("fieldset")?.disabled)
|
|
657
|
+
return false;
|
|
658
|
+
return true;
|
|
659
|
+
}
|
|
600
660
|
function analyzeOrphanInputGroup(container, inputs, submitBtn) {
|
|
601
661
|
const name = inferOrphanToolName(container, submitBtn);
|
|
602
662
|
const description = inferOrphanToolDescription(container);
|
|
@@ -667,6 +727,8 @@ function buildSchemaFromInputs(inputs) {
|
|
|
667
727
|
const schemaProp = inputTypeToSchema(control);
|
|
668
728
|
if (!schemaProp)
|
|
669
729
|
continue;
|
|
730
|
+
if (!isControlVisible(control))
|
|
731
|
+
continue;
|
|
670
732
|
schemaProp.title = inferFieldTitle(control);
|
|
671
733
|
const desc = inferFieldDescription(control);
|
|
672
734
|
if (desc)
|
|
@@ -687,6 +749,7 @@ init_registry();
|
|
|
687
749
|
var pendingExecutions = /* @__PURE__ */ new WeakMap();
|
|
688
750
|
var lastParams = /* @__PURE__ */ new WeakMap();
|
|
689
751
|
var formFieldElements = /* @__PURE__ */ new WeakMap();
|
|
752
|
+
var pendingWarnings = /* @__PURE__ */ new WeakMap();
|
|
690
753
|
var _inputValueSetter = Object.getOwnPropertyDescriptor(HTMLInputElement.prototype, "value")?.set;
|
|
691
754
|
var _textareaValueSetter = Object.getOwnPropertyDescriptor(HTMLTextAreaElement.prototype, "value")?.set;
|
|
692
755
|
var _checkedSetter = Object.getOwnPropertyDescriptor(HTMLInputElement.prototype, "checked")?.set;
|
|
@@ -701,22 +764,36 @@ function buildExecuteHandler(form, config, toolName, metadata) {
|
|
|
701
764
|
return new Promise((resolve, reject) => {
|
|
702
765
|
pendingExecutions.set(form, { resolve, reject });
|
|
703
766
|
if (config.autoSubmit || form.hasAttribute("toolautosubmit") || form.dataset["webmcpAutosubmit"] !== void 0) {
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
submitForm = found;
|
|
714
|
-
pendingExecutions.set(submitForm, { resolve, reject });
|
|
715
|
-
attachSubmitInterceptor(submitForm, toolName);
|
|
767
|
+
waitForDomStable(form).then(async () => {
|
|
768
|
+
try {
|
|
769
|
+
fillFormFields(form, params);
|
|
770
|
+
for (let attempt = 0; attempt < 2; attempt++) {
|
|
771
|
+
const reset = getResetFields(form, params, formFieldElements.get(form));
|
|
772
|
+
if (reset.length === 0)
|
|
773
|
+
break;
|
|
774
|
+
fillFormFields(form, params);
|
|
775
|
+
await waitForDomStable(form, 400, 100);
|
|
716
776
|
}
|
|
777
|
+
let submitForm = form;
|
|
778
|
+
if (!form.isConnected) {
|
|
779
|
+
const liveBtn = document.querySelector(
|
|
780
|
+
'button[type="submit"]:not([disabled]), input[type="submit"]:not([disabled])'
|
|
781
|
+
);
|
|
782
|
+
const found = liveBtn?.closest("form");
|
|
783
|
+
if (found) {
|
|
784
|
+
submitForm = found;
|
|
785
|
+
pendingExecutions.set(submitForm, { resolve, reject });
|
|
786
|
+
attachSubmitInterceptor(submitForm, toolName);
|
|
787
|
+
}
|
|
788
|
+
}
|
|
789
|
+
const missing = getMissingRequired(metadata, params);
|
|
790
|
+
if (missing.length > 0)
|
|
791
|
+
pendingWarnings.set(submitForm, missing);
|
|
792
|
+
submitForm.requestSubmit();
|
|
793
|
+
} catch (err) {
|
|
794
|
+
reject(err instanceof Error ? err : new Error(String(err)));
|
|
717
795
|
}
|
|
718
|
-
|
|
719
|
-
}, 300);
|
|
796
|
+
});
|
|
720
797
|
}
|
|
721
798
|
});
|
|
722
799
|
};
|
|
@@ -732,7 +809,10 @@ function attachSubmitInterceptor(form, toolName) {
|
|
|
732
809
|
const { resolve } = pending;
|
|
733
810
|
pendingExecutions.delete(form);
|
|
734
811
|
const formData = serializeFormData(form, lastParams.get(form), formFieldElements.get(form));
|
|
735
|
-
const
|
|
812
|
+
const missing = pendingWarnings.get(form);
|
|
813
|
+
pendingWarnings.delete(form);
|
|
814
|
+
const warningText = missing?.length ? ` Note: required fields were not filled: ${missing.join(", ")}.` : "";
|
|
815
|
+
const text = `Form submitted. Fields: ${JSON.stringify(formData)}${warningText}`;
|
|
736
816
|
const result = { content: [{ type: "text", text }] };
|
|
737
817
|
if (e.agentInvoked && typeof e.respondWith === "function") {
|
|
738
818
|
e.preventDefault();
|
|
@@ -938,6 +1018,50 @@ function fillElement(el, value) {
|
|
|
938
1018
|
fillAriaField(el, value);
|
|
939
1019
|
}
|
|
940
1020
|
}
|
|
1021
|
+
function waitForDomStable(form, maxMs = 800, debounceMs = 150) {
|
|
1022
|
+
return new Promise((resolve) => {
|
|
1023
|
+
let settled = false;
|
|
1024
|
+
let debounceTimer = null;
|
|
1025
|
+
const settle = () => {
|
|
1026
|
+
if (settled)
|
|
1027
|
+
return;
|
|
1028
|
+
settled = true;
|
|
1029
|
+
observer2.disconnect();
|
|
1030
|
+
if (debounceTimer !== null)
|
|
1031
|
+
clearTimeout(debounceTimer);
|
|
1032
|
+
resolve();
|
|
1033
|
+
};
|
|
1034
|
+
const observer2 = new MutationObserver(() => {
|
|
1035
|
+
if (debounceTimer !== null)
|
|
1036
|
+
clearTimeout(debounceTimer);
|
|
1037
|
+
debounceTimer = setTimeout(settle, debounceMs);
|
|
1038
|
+
});
|
|
1039
|
+
observer2.observe(form, { childList: true, subtree: true, attributes: true, characterData: true });
|
|
1040
|
+
setTimeout(settle, maxMs);
|
|
1041
|
+
debounceTimer = setTimeout(settle, debounceMs);
|
|
1042
|
+
});
|
|
1043
|
+
}
|
|
1044
|
+
function getResetFields(form, params, fieldEls) {
|
|
1045
|
+
const reset = [];
|
|
1046
|
+
for (const [key, expected] of Object.entries(params)) {
|
|
1047
|
+
const el = findNativeField(form, key) ?? (fieldEls?.get(key) ?? null);
|
|
1048
|
+
if (!el)
|
|
1049
|
+
continue;
|
|
1050
|
+
if (el instanceof HTMLInputElement && el.type === "checkbox") {
|
|
1051
|
+
if (el.checked !== Boolean(expected))
|
|
1052
|
+
reset.push(key);
|
|
1053
|
+
} else if (el instanceof HTMLInputElement || el instanceof HTMLTextAreaElement || el instanceof HTMLSelectElement) {
|
|
1054
|
+
if (el.value !== String(expected ?? ""))
|
|
1055
|
+
reset.push(key);
|
|
1056
|
+
}
|
|
1057
|
+
}
|
|
1058
|
+
return reset;
|
|
1059
|
+
}
|
|
1060
|
+
function getMissingRequired(metadata, params) {
|
|
1061
|
+
if (!metadata?.inputSchema?.required?.length)
|
|
1062
|
+
return [];
|
|
1063
|
+
return metadata.inputSchema.required.filter((fieldKey) => !(fieldKey in params));
|
|
1064
|
+
}
|
|
941
1065
|
|
|
942
1066
|
// src/enhancer.ts
|
|
943
1067
|
async function enrichMetadata(metadata, enhancer) {
|