auto-webmcp 0.2.8 → 0.2.9
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 +141 -5
- package/dist/auto-webmcp.cjs.js.map +2 -2
- package/dist/auto-webmcp.esm.js +141 -5
- package/dist/auto-webmcp.esm.js.map +2 -2
- 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 +6 -0
- package/dist/schema.d.ts.map +1 -1
- package/package.json +1 -1
package/dist/auto-webmcp.esm.js
CHANGED
|
@@ -221,6 +221,11 @@ function mapSelectElement(select) {
|
|
|
221
221
|
return { type: "string" };
|
|
222
222
|
return { type: "string", enum: enumValues, oneOf };
|
|
223
223
|
}
|
|
224
|
+
function collectCheckboxEnum(form, name) {
|
|
225
|
+
return Array.from(
|
|
226
|
+
form.querySelectorAll(`input[type="checkbox"][name="${CSS.escape(name)}"]`)
|
|
227
|
+
).map((cb) => cb.value).filter((v) => v !== "" && v !== "on");
|
|
228
|
+
}
|
|
224
229
|
function collectRadioEnum(form, name) {
|
|
225
230
|
const radios = Array.from(
|
|
226
231
|
form.querySelectorAll(`input[type="radio"][name="${CSS.escape(name)}"]`)
|
|
@@ -407,6 +412,7 @@ function buildSchema(form) {
|
|
|
407
412
|
const required = [];
|
|
408
413
|
const fieldElements = /* @__PURE__ */ new Map();
|
|
409
414
|
const processedRadioGroups = /* @__PURE__ */ new Set();
|
|
415
|
+
const processedCheckboxGroups = /* @__PURE__ */ new Set();
|
|
410
416
|
const controls = Array.from(
|
|
411
417
|
form.querySelectorAll(
|
|
412
418
|
"input, textarea, select"
|
|
@@ -422,6 +428,11 @@ function buildSchema(form) {
|
|
|
422
428
|
continue;
|
|
423
429
|
processedRadioGroups.add(fieldKey);
|
|
424
430
|
}
|
|
431
|
+
if (control instanceof HTMLInputElement && control.type === "checkbox") {
|
|
432
|
+
if (processedCheckboxGroups.has(fieldKey))
|
|
433
|
+
continue;
|
|
434
|
+
processedCheckboxGroups.add(fieldKey);
|
|
435
|
+
}
|
|
425
436
|
const schemaProp = inputTypeToSchema(control);
|
|
426
437
|
if (!schemaProp)
|
|
427
438
|
continue;
|
|
@@ -437,6 +448,22 @@ function buildSchema(form) {
|
|
|
437
448
|
if (radioOneOf.length > 0)
|
|
438
449
|
schemaProp.oneOf = radioOneOf;
|
|
439
450
|
}
|
|
451
|
+
if (control instanceof HTMLInputElement && control.type === "checkbox") {
|
|
452
|
+
const checkboxValues = collectCheckboxEnum(form, fieldKey);
|
|
453
|
+
if (checkboxValues.length > 1) {
|
|
454
|
+
const arrayProp = {
|
|
455
|
+
type: "array",
|
|
456
|
+
items: { type: "string", enum: checkboxValues },
|
|
457
|
+
title: schemaProp.title
|
|
458
|
+
};
|
|
459
|
+
if (schemaProp.description)
|
|
460
|
+
arrayProp.description = schemaProp.description;
|
|
461
|
+
properties[fieldKey] = arrayProp;
|
|
462
|
+
if (control.required)
|
|
463
|
+
required.push(fieldKey);
|
|
464
|
+
continue;
|
|
465
|
+
}
|
|
466
|
+
}
|
|
440
467
|
properties[fieldKey] = schemaProp;
|
|
441
468
|
if (!name) {
|
|
442
469
|
fieldElements.set(fieldKey, control);
|
|
@@ -447,7 +474,7 @@ function buildSchema(form) {
|
|
|
447
474
|
}
|
|
448
475
|
const ariaControls = collectAriaControls(form);
|
|
449
476
|
const processedAriaRadioGroups = /* @__PURE__ */ new Set();
|
|
450
|
-
for (const { el, role, key } of ariaControls) {
|
|
477
|
+
for (const { el, role, key, enumValues, enumOneOf } of ariaControls) {
|
|
451
478
|
if (properties[key])
|
|
452
479
|
continue;
|
|
453
480
|
if (role === "radio") {
|
|
@@ -456,6 +483,11 @@ function buildSchema(form) {
|
|
|
456
483
|
processedAriaRadioGroups.add(key);
|
|
457
484
|
}
|
|
458
485
|
const schemaProp = ariaRoleToSchema(el, role);
|
|
486
|
+
if (enumValues && enumValues.length > 0) {
|
|
487
|
+
schemaProp.enum = enumValues;
|
|
488
|
+
if (enumOneOf && enumOneOf.length > 0)
|
|
489
|
+
schemaProp.oneOf = enumOneOf;
|
|
490
|
+
}
|
|
459
491
|
schemaProp.title = inferAriaFieldTitle(el);
|
|
460
492
|
const desc = inferAriaFieldDescription(el);
|
|
461
493
|
if (desc)
|
|
@@ -487,7 +519,7 @@ function resolveNativeControlFallbackKey(control) {
|
|
|
487
519
|
}
|
|
488
520
|
function collectAriaControls(form) {
|
|
489
521
|
const selector = ARIA_ROLES_TO_SCAN.map((r) => `[role="${r}"]`).join(", ");
|
|
490
|
-
const
|
|
522
|
+
const rawResults = [];
|
|
491
523
|
for (const el of Array.from(form.querySelectorAll(selector))) {
|
|
492
524
|
if (el instanceof HTMLInputElement || el instanceof HTMLTextAreaElement || el instanceof HTMLSelectElement)
|
|
493
525
|
continue;
|
|
@@ -497,9 +529,38 @@ function collectAriaControls(form) {
|
|
|
497
529
|
const key = resolveAriaFieldKey(el);
|
|
498
530
|
if (!key)
|
|
499
531
|
continue;
|
|
500
|
-
|
|
532
|
+
rawResults.push({ el, role, key });
|
|
533
|
+
}
|
|
534
|
+
const radioEntries = rawResults.filter((e) => e.role === "radio");
|
|
535
|
+
const nonRadioEntries = rawResults.filter((e) => e.role !== "radio");
|
|
536
|
+
const radioGroupMap = /* @__PURE__ */ new Map();
|
|
537
|
+
const ungroupedRadios = [];
|
|
538
|
+
for (const entry of radioEntries) {
|
|
539
|
+
const group = entry.el.closest('[role="radiogroup"]');
|
|
540
|
+
if (group) {
|
|
541
|
+
if (!radioGroupMap.has(group))
|
|
542
|
+
radioGroupMap.set(group, []);
|
|
543
|
+
radioGroupMap.get(group).push(entry.el);
|
|
544
|
+
} else {
|
|
545
|
+
ungroupedRadios.push(entry);
|
|
546
|
+
}
|
|
547
|
+
}
|
|
548
|
+
const groupedEntries = [];
|
|
549
|
+
for (const [group, members] of radioGroupMap) {
|
|
550
|
+
const groupKey = resolveAriaFieldKey(group);
|
|
551
|
+
if (!groupKey)
|
|
552
|
+
continue;
|
|
553
|
+
const enumValues = members.map((el) => (el.getAttribute("data-value") ?? el.getAttribute("aria-label") ?? el.textContent ?? "").trim()).filter(Boolean);
|
|
554
|
+
const enumOneOf = members.map((el) => {
|
|
555
|
+
const val = (el.getAttribute("data-value") ?? el.getAttribute("aria-label") ?? el.textContent ?? "").trim();
|
|
556
|
+
const title = (el.getAttribute("aria-label") ?? el.textContent ?? "").trim();
|
|
557
|
+
return { const: val, title: title || val };
|
|
558
|
+
}).filter((e) => e.const !== "");
|
|
559
|
+
if (enumValues.length > 0) {
|
|
560
|
+
groupedEntries.push({ el: group, role: "radio", key: groupKey, enumValues, enumOneOf });
|
|
561
|
+
}
|
|
501
562
|
}
|
|
502
|
-
return
|
|
563
|
+
return [...nonRadioEntries, ...groupedEntries, ...ungroupedRadios];
|
|
503
564
|
}
|
|
504
565
|
function resolveAriaFieldKey(el) {
|
|
505
566
|
const htmlEl = el;
|
|
@@ -695,6 +756,7 @@ function buildSchemaFromInputs(inputs) {
|
|
|
695
756
|
const required = [];
|
|
696
757
|
const fieldElements = /* @__PURE__ */ new Map();
|
|
697
758
|
const processedRadioGroups = /* @__PURE__ */ new Set();
|
|
759
|
+
const processedCheckboxGroups = /* @__PURE__ */ new Set();
|
|
698
760
|
for (const control of inputs) {
|
|
699
761
|
const name = control.name;
|
|
700
762
|
const fieldKey = name || resolveNativeControlFallbackKey(control);
|
|
@@ -705,6 +767,11 @@ function buildSchemaFromInputs(inputs) {
|
|
|
705
767
|
continue;
|
|
706
768
|
processedRadioGroups.add(fieldKey);
|
|
707
769
|
}
|
|
770
|
+
if (control instanceof HTMLInputElement && control.type === "checkbox") {
|
|
771
|
+
if (processedCheckboxGroups.has(fieldKey))
|
|
772
|
+
continue;
|
|
773
|
+
processedCheckboxGroups.add(fieldKey);
|
|
774
|
+
}
|
|
708
775
|
const schemaProp = inputTypeToSchema(control);
|
|
709
776
|
if (!schemaProp)
|
|
710
777
|
continue;
|
|
@@ -714,6 +781,22 @@ function buildSchemaFromInputs(inputs) {
|
|
|
714
781
|
const desc = inferFieldDescription(control);
|
|
715
782
|
if (desc)
|
|
716
783
|
schemaProp.description = desc;
|
|
784
|
+
if (control instanceof HTMLInputElement && control.type === "checkbox") {
|
|
785
|
+
const checkboxValues = inputs.filter((i) => i instanceof HTMLInputElement && i.type === "checkbox" && i.name === fieldKey).map((cb) => cb.value).filter((v) => v !== "" && v !== "on");
|
|
786
|
+
if (checkboxValues.length > 1) {
|
|
787
|
+
const arrayProp = {
|
|
788
|
+
type: "array",
|
|
789
|
+
items: { type: "string", enum: checkboxValues },
|
|
790
|
+
title: schemaProp.title
|
|
791
|
+
};
|
|
792
|
+
if (schemaProp.description)
|
|
793
|
+
arrayProp.description = schemaProp.description;
|
|
794
|
+
properties[fieldKey] = arrayProp;
|
|
795
|
+
if (control.required)
|
|
796
|
+
required.push(fieldKey);
|
|
797
|
+
continue;
|
|
798
|
+
}
|
|
799
|
+
}
|
|
717
800
|
properties[fieldKey] = schemaProp;
|
|
718
801
|
if (!name)
|
|
719
802
|
fieldElements.set(fieldKey, control);
|
|
@@ -731,6 +814,7 @@ var pendingExecutions = /* @__PURE__ */ new WeakMap();
|
|
|
731
814
|
var lastParams = /* @__PURE__ */ new WeakMap();
|
|
732
815
|
var formFieldElements = /* @__PURE__ */ new WeakMap();
|
|
733
816
|
var pendingWarnings = /* @__PURE__ */ new WeakMap();
|
|
817
|
+
var pendingFillWarnings = /* @__PURE__ */ new WeakMap();
|
|
734
818
|
var _inputValueSetter = Object.getOwnPropertyDescriptor(HTMLInputElement.prototype, "value")?.set;
|
|
735
819
|
var _textareaValueSetter = Object.getOwnPropertyDescriptor(HTMLTextAreaElement.prototype, "value")?.set;
|
|
736
820
|
var _checkedSetter = Object.getOwnPropertyDescriptor(HTMLInputElement.prototype, "checked")?.set;
|
|
@@ -740,6 +824,7 @@ function buildExecuteHandler(form, config, toolName, metadata) {
|
|
|
740
824
|
}
|
|
741
825
|
attachSubmitInterceptor(form, toolName);
|
|
742
826
|
return async (params) => {
|
|
827
|
+
pendingFillWarnings.set(form, []);
|
|
743
828
|
fillFormFields(form, params);
|
|
744
829
|
window.dispatchEvent(new CustomEvent("toolactivated", { detail: { toolName } }));
|
|
745
830
|
return new Promise((resolve, reject) => {
|
|
@@ -792,7 +877,13 @@ function attachSubmitInterceptor(form, toolName) {
|
|
|
792
877
|
const formData = serializeFormData(form, lastParams.get(form), formFieldElements.get(form));
|
|
793
878
|
const missing = pendingWarnings.get(form);
|
|
794
879
|
pendingWarnings.delete(form);
|
|
795
|
-
const
|
|
880
|
+
const fillWarnings = pendingFillWarnings.get(form) ?? [];
|
|
881
|
+
pendingFillWarnings.delete(form);
|
|
882
|
+
const allWarnings = [
|
|
883
|
+
...missing?.length ? [`required fields were not filled: ${missing.join(", ")}`] : [],
|
|
884
|
+
...fillWarnings
|
|
885
|
+
];
|
|
886
|
+
const warningText = allWarnings.length ? ` Note: ${allWarnings.join("; ")}.` : "";
|
|
796
887
|
const text = `Form submitted. Fields: ${JSON.stringify(formData)}${warningText}`;
|
|
797
888
|
const result = { content: [{ type: "text", text }] };
|
|
798
889
|
if (e.agentInvoked && typeof e.respondWith === "function") {
|
|
@@ -894,9 +985,38 @@ function fillFormFields(form, params) {
|
|
|
894
985
|
function fillInput(input, form, key, value) {
|
|
895
986
|
const type = input.type.toLowerCase();
|
|
896
987
|
if (type === "checkbox") {
|
|
988
|
+
if (Array.isArray(value)) {
|
|
989
|
+
const esc = CSS.escape(key);
|
|
990
|
+
const allBoxes = form.querySelectorAll(`input[type="checkbox"][name="${esc}"]`);
|
|
991
|
+
for (const box of allBoxes) {
|
|
992
|
+
setReactChecked(box, value.map(String).includes(box.value));
|
|
993
|
+
}
|
|
994
|
+
return;
|
|
995
|
+
}
|
|
897
996
|
setReactChecked(input, Boolean(value));
|
|
898
997
|
return;
|
|
899
998
|
}
|
|
999
|
+
if (type === "number" || type === "range") {
|
|
1000
|
+
const raw = String(value ?? "");
|
|
1001
|
+
const num = Number(raw);
|
|
1002
|
+
if (raw === "" || isNaN(num)) {
|
|
1003
|
+
pendingFillWarnings.get(form)?.push(`"${key}" expects a number, got: ${JSON.stringify(value)}`);
|
|
1004
|
+
return;
|
|
1005
|
+
}
|
|
1006
|
+
const min = input.min !== "" ? parseFloat(input.min) : -Infinity;
|
|
1007
|
+
const max = input.max !== "" ? parseFloat(input.max) : Infinity;
|
|
1008
|
+
if (num < min || num > max) {
|
|
1009
|
+
pendingFillWarnings.get(form)?.push(
|
|
1010
|
+
`"${key}" value ${num} is outside allowed range [${input.min || "?"}, ${input.max || "?"}]`
|
|
1011
|
+
);
|
|
1012
|
+
input.value = String(Math.min(Math.max(num, min), max));
|
|
1013
|
+
} else {
|
|
1014
|
+
input.value = String(num);
|
|
1015
|
+
}
|
|
1016
|
+
input.dispatchEvent(new InputEvent("input", { bubbles: true, cancelable: true, inputType: "insertText", data: String(num) }));
|
|
1017
|
+
input.dispatchEvent(new Event("change", { bubbles: true }));
|
|
1018
|
+
return;
|
|
1019
|
+
}
|
|
900
1020
|
if (type === "radio") {
|
|
901
1021
|
const esc = CSS.escape(key);
|
|
902
1022
|
const radios = form.querySelectorAll(
|
|
@@ -929,6 +1049,22 @@ function fillAriaField(el, value) {
|
|
|
929
1049
|
el.dispatchEvent(new MouseEvent("click", { bubbles: true }));
|
|
930
1050
|
return;
|
|
931
1051
|
}
|
|
1052
|
+
if (role === "radiogroup") {
|
|
1053
|
+
const radios = Array.from(el.querySelectorAll('[role="radio"]'));
|
|
1054
|
+
for (const radio of radios) {
|
|
1055
|
+
const val = (radio.getAttribute("data-value") ?? radio.getAttribute("aria-label") ?? radio.textContent ?? "").trim();
|
|
1056
|
+
if (val === String(value)) {
|
|
1057
|
+
radio.setAttribute("aria-checked", "true");
|
|
1058
|
+
radio.dispatchEvent(new MouseEvent("click", { bubbles: true }));
|
|
1059
|
+
for (const other of radios) {
|
|
1060
|
+
if (other !== radio)
|
|
1061
|
+
other.setAttribute("aria-checked", "false");
|
|
1062
|
+
}
|
|
1063
|
+
break;
|
|
1064
|
+
}
|
|
1065
|
+
}
|
|
1066
|
+
return;
|
|
1067
|
+
}
|
|
932
1068
|
const htmlEl = el;
|
|
933
1069
|
if (htmlEl.isContentEditable) {
|
|
934
1070
|
htmlEl.textContent = String(value ?? "");
|