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/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,
|
|
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,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;AAsgBD;;;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
|
@@ -240,6 +240,11 @@ function mapSelectElement(select) {
|
|
|
240
240
|
return { type: "string" };
|
|
241
241
|
return { type: "string", enum: enumValues, oneOf };
|
|
242
242
|
}
|
|
243
|
+
function collectCheckboxEnum(form, name) {
|
|
244
|
+
return Array.from(
|
|
245
|
+
form.querySelectorAll(`input[type="checkbox"][name="${CSS.escape(name)}"]`)
|
|
246
|
+
).map((cb) => cb.value).filter((v) => v !== "" && v !== "on");
|
|
247
|
+
}
|
|
243
248
|
function collectRadioEnum(form, name) {
|
|
244
249
|
const radios = Array.from(
|
|
245
250
|
form.querySelectorAll(`input[type="radio"][name="${CSS.escape(name)}"]`)
|
|
@@ -426,6 +431,7 @@ function buildSchema(form) {
|
|
|
426
431
|
const required = [];
|
|
427
432
|
const fieldElements = /* @__PURE__ */ new Map();
|
|
428
433
|
const processedRadioGroups = /* @__PURE__ */ new Set();
|
|
434
|
+
const processedCheckboxGroups = /* @__PURE__ */ new Set();
|
|
429
435
|
const controls = Array.from(
|
|
430
436
|
form.querySelectorAll(
|
|
431
437
|
"input, textarea, select"
|
|
@@ -441,6 +447,11 @@ function buildSchema(form) {
|
|
|
441
447
|
continue;
|
|
442
448
|
processedRadioGroups.add(fieldKey);
|
|
443
449
|
}
|
|
450
|
+
if (control instanceof HTMLInputElement && control.type === "checkbox") {
|
|
451
|
+
if (processedCheckboxGroups.has(fieldKey))
|
|
452
|
+
continue;
|
|
453
|
+
processedCheckboxGroups.add(fieldKey);
|
|
454
|
+
}
|
|
444
455
|
const schemaProp = inputTypeToSchema(control);
|
|
445
456
|
if (!schemaProp)
|
|
446
457
|
continue;
|
|
@@ -456,6 +467,22 @@ function buildSchema(form) {
|
|
|
456
467
|
if (radioOneOf.length > 0)
|
|
457
468
|
schemaProp.oneOf = radioOneOf;
|
|
458
469
|
}
|
|
470
|
+
if (control instanceof HTMLInputElement && control.type === "checkbox") {
|
|
471
|
+
const checkboxValues = collectCheckboxEnum(form, fieldKey);
|
|
472
|
+
if (checkboxValues.length > 1) {
|
|
473
|
+
const arrayProp = {
|
|
474
|
+
type: "array",
|
|
475
|
+
items: { type: "string", enum: checkboxValues },
|
|
476
|
+
title: schemaProp.title
|
|
477
|
+
};
|
|
478
|
+
if (schemaProp.description)
|
|
479
|
+
arrayProp.description = schemaProp.description;
|
|
480
|
+
properties[fieldKey] = arrayProp;
|
|
481
|
+
if (control.required)
|
|
482
|
+
required.push(fieldKey);
|
|
483
|
+
continue;
|
|
484
|
+
}
|
|
485
|
+
}
|
|
459
486
|
properties[fieldKey] = schemaProp;
|
|
460
487
|
if (!name) {
|
|
461
488
|
fieldElements.set(fieldKey, control);
|
|
@@ -466,7 +493,7 @@ function buildSchema(form) {
|
|
|
466
493
|
}
|
|
467
494
|
const ariaControls = collectAriaControls(form);
|
|
468
495
|
const processedAriaRadioGroups = /* @__PURE__ */ new Set();
|
|
469
|
-
for (const { el, role, key } of ariaControls) {
|
|
496
|
+
for (const { el, role, key, enumValues, enumOneOf } of ariaControls) {
|
|
470
497
|
if (properties[key])
|
|
471
498
|
continue;
|
|
472
499
|
if (role === "radio") {
|
|
@@ -475,6 +502,11 @@ function buildSchema(form) {
|
|
|
475
502
|
processedAriaRadioGroups.add(key);
|
|
476
503
|
}
|
|
477
504
|
const schemaProp = ariaRoleToSchema(el, role);
|
|
505
|
+
if (enumValues && enumValues.length > 0) {
|
|
506
|
+
schemaProp.enum = enumValues;
|
|
507
|
+
if (enumOneOf && enumOneOf.length > 0)
|
|
508
|
+
schemaProp.oneOf = enumOneOf;
|
|
509
|
+
}
|
|
478
510
|
schemaProp.title = inferAriaFieldTitle(el);
|
|
479
511
|
const desc = inferAriaFieldDescription(el);
|
|
480
512
|
if (desc)
|
|
@@ -506,7 +538,7 @@ function resolveNativeControlFallbackKey(control) {
|
|
|
506
538
|
}
|
|
507
539
|
function collectAriaControls(form) {
|
|
508
540
|
const selector = ARIA_ROLES_TO_SCAN.map((r) => `[role="${r}"]`).join(", ");
|
|
509
|
-
const
|
|
541
|
+
const rawResults = [];
|
|
510
542
|
for (const el of Array.from(form.querySelectorAll(selector))) {
|
|
511
543
|
if (el instanceof HTMLInputElement || el instanceof HTMLTextAreaElement || el instanceof HTMLSelectElement)
|
|
512
544
|
continue;
|
|
@@ -516,9 +548,38 @@ function collectAriaControls(form) {
|
|
|
516
548
|
const key = resolveAriaFieldKey(el);
|
|
517
549
|
if (!key)
|
|
518
550
|
continue;
|
|
519
|
-
|
|
551
|
+
rawResults.push({ el, role, key });
|
|
552
|
+
}
|
|
553
|
+
const radioEntries = rawResults.filter((e) => e.role === "radio");
|
|
554
|
+
const nonRadioEntries = rawResults.filter((e) => e.role !== "radio");
|
|
555
|
+
const radioGroupMap = /* @__PURE__ */ new Map();
|
|
556
|
+
const ungroupedRadios = [];
|
|
557
|
+
for (const entry of radioEntries) {
|
|
558
|
+
const group = entry.el.closest('[role="radiogroup"]');
|
|
559
|
+
if (group) {
|
|
560
|
+
if (!radioGroupMap.has(group))
|
|
561
|
+
radioGroupMap.set(group, []);
|
|
562
|
+
radioGroupMap.get(group).push(entry.el);
|
|
563
|
+
} else {
|
|
564
|
+
ungroupedRadios.push(entry);
|
|
565
|
+
}
|
|
566
|
+
}
|
|
567
|
+
const groupedEntries = [];
|
|
568
|
+
for (const [group, members] of radioGroupMap) {
|
|
569
|
+
const groupKey = resolveAriaFieldKey(group);
|
|
570
|
+
if (!groupKey)
|
|
571
|
+
continue;
|
|
572
|
+
const enumValues = members.map((el) => (el.getAttribute("data-value") ?? el.getAttribute("aria-label") ?? el.textContent ?? "").trim()).filter(Boolean);
|
|
573
|
+
const enumOneOf = members.map((el) => {
|
|
574
|
+
const val = (el.getAttribute("data-value") ?? el.getAttribute("aria-label") ?? el.textContent ?? "").trim();
|
|
575
|
+
const title = (el.getAttribute("aria-label") ?? el.textContent ?? "").trim();
|
|
576
|
+
return { const: val, title: title || val };
|
|
577
|
+
}).filter((e) => e.const !== "");
|
|
578
|
+
if (enumValues.length > 0) {
|
|
579
|
+
groupedEntries.push({ el: group, role: "radio", key: groupKey, enumValues, enumOneOf });
|
|
580
|
+
}
|
|
520
581
|
}
|
|
521
|
-
return
|
|
582
|
+
return [...nonRadioEntries, ...groupedEntries, ...ungroupedRadios];
|
|
522
583
|
}
|
|
523
584
|
function resolveAriaFieldKey(el) {
|
|
524
585
|
const htmlEl = el;
|
|
@@ -714,6 +775,7 @@ function buildSchemaFromInputs(inputs) {
|
|
|
714
775
|
const required = [];
|
|
715
776
|
const fieldElements = /* @__PURE__ */ new Map();
|
|
716
777
|
const processedRadioGroups = /* @__PURE__ */ new Set();
|
|
778
|
+
const processedCheckboxGroups = /* @__PURE__ */ new Set();
|
|
717
779
|
for (const control of inputs) {
|
|
718
780
|
const name = control.name;
|
|
719
781
|
const fieldKey = name || resolveNativeControlFallbackKey(control);
|
|
@@ -724,6 +786,11 @@ function buildSchemaFromInputs(inputs) {
|
|
|
724
786
|
continue;
|
|
725
787
|
processedRadioGroups.add(fieldKey);
|
|
726
788
|
}
|
|
789
|
+
if (control instanceof HTMLInputElement && control.type === "checkbox") {
|
|
790
|
+
if (processedCheckboxGroups.has(fieldKey))
|
|
791
|
+
continue;
|
|
792
|
+
processedCheckboxGroups.add(fieldKey);
|
|
793
|
+
}
|
|
727
794
|
const schemaProp = inputTypeToSchema(control);
|
|
728
795
|
if (!schemaProp)
|
|
729
796
|
continue;
|
|
@@ -733,6 +800,22 @@ function buildSchemaFromInputs(inputs) {
|
|
|
733
800
|
const desc = inferFieldDescription(control);
|
|
734
801
|
if (desc)
|
|
735
802
|
schemaProp.description = desc;
|
|
803
|
+
if (control instanceof HTMLInputElement && control.type === "checkbox") {
|
|
804
|
+
const checkboxValues = inputs.filter((i) => i instanceof HTMLInputElement && i.type === "checkbox" && i.name === fieldKey).map((cb) => cb.value).filter((v) => v !== "" && v !== "on");
|
|
805
|
+
if (checkboxValues.length > 1) {
|
|
806
|
+
const arrayProp = {
|
|
807
|
+
type: "array",
|
|
808
|
+
items: { type: "string", enum: checkboxValues },
|
|
809
|
+
title: schemaProp.title
|
|
810
|
+
};
|
|
811
|
+
if (schemaProp.description)
|
|
812
|
+
arrayProp.description = schemaProp.description;
|
|
813
|
+
properties[fieldKey] = arrayProp;
|
|
814
|
+
if (control.required)
|
|
815
|
+
required.push(fieldKey);
|
|
816
|
+
continue;
|
|
817
|
+
}
|
|
818
|
+
}
|
|
736
819
|
properties[fieldKey] = schemaProp;
|
|
737
820
|
if (!name)
|
|
738
821
|
fieldElements.set(fieldKey, control);
|
|
@@ -750,6 +833,7 @@ var pendingExecutions = /* @__PURE__ */ new WeakMap();
|
|
|
750
833
|
var lastParams = /* @__PURE__ */ new WeakMap();
|
|
751
834
|
var formFieldElements = /* @__PURE__ */ new WeakMap();
|
|
752
835
|
var pendingWarnings = /* @__PURE__ */ new WeakMap();
|
|
836
|
+
var pendingFillWarnings = /* @__PURE__ */ new WeakMap();
|
|
753
837
|
var _inputValueSetter = Object.getOwnPropertyDescriptor(HTMLInputElement.prototype, "value")?.set;
|
|
754
838
|
var _textareaValueSetter = Object.getOwnPropertyDescriptor(HTMLTextAreaElement.prototype, "value")?.set;
|
|
755
839
|
var _checkedSetter = Object.getOwnPropertyDescriptor(HTMLInputElement.prototype, "checked")?.set;
|
|
@@ -759,6 +843,7 @@ function buildExecuteHandler(form, config, toolName, metadata) {
|
|
|
759
843
|
}
|
|
760
844
|
attachSubmitInterceptor(form, toolName);
|
|
761
845
|
return async (params) => {
|
|
846
|
+
pendingFillWarnings.set(form, []);
|
|
762
847
|
fillFormFields(form, params);
|
|
763
848
|
window.dispatchEvent(new CustomEvent("toolactivated", { detail: { toolName } }));
|
|
764
849
|
return new Promise((resolve, reject) => {
|
|
@@ -811,7 +896,13 @@ function attachSubmitInterceptor(form, toolName) {
|
|
|
811
896
|
const formData = serializeFormData(form, lastParams.get(form), formFieldElements.get(form));
|
|
812
897
|
const missing = pendingWarnings.get(form);
|
|
813
898
|
pendingWarnings.delete(form);
|
|
814
|
-
const
|
|
899
|
+
const fillWarnings = pendingFillWarnings.get(form) ?? [];
|
|
900
|
+
pendingFillWarnings.delete(form);
|
|
901
|
+
const allWarnings = [
|
|
902
|
+
...missing?.length ? [`required fields were not filled: ${missing.join(", ")}`] : [],
|
|
903
|
+
...fillWarnings
|
|
904
|
+
];
|
|
905
|
+
const warningText = allWarnings.length ? ` Note: ${allWarnings.join("; ")}.` : "";
|
|
815
906
|
const text = `Form submitted. Fields: ${JSON.stringify(formData)}${warningText}`;
|
|
816
907
|
const result = { content: [{ type: "text", text }] };
|
|
817
908
|
if (e.agentInvoked && typeof e.respondWith === "function") {
|
|
@@ -913,9 +1004,38 @@ function fillFormFields(form, params) {
|
|
|
913
1004
|
function fillInput(input, form, key, value) {
|
|
914
1005
|
const type = input.type.toLowerCase();
|
|
915
1006
|
if (type === "checkbox") {
|
|
1007
|
+
if (Array.isArray(value)) {
|
|
1008
|
+
const esc = CSS.escape(key);
|
|
1009
|
+
const allBoxes = form.querySelectorAll(`input[type="checkbox"][name="${esc}"]`);
|
|
1010
|
+
for (const box of allBoxes) {
|
|
1011
|
+
setReactChecked(box, value.map(String).includes(box.value));
|
|
1012
|
+
}
|
|
1013
|
+
return;
|
|
1014
|
+
}
|
|
916
1015
|
setReactChecked(input, Boolean(value));
|
|
917
1016
|
return;
|
|
918
1017
|
}
|
|
1018
|
+
if (type === "number" || type === "range") {
|
|
1019
|
+
const raw = String(value ?? "");
|
|
1020
|
+
const num = Number(raw);
|
|
1021
|
+
if (raw === "" || isNaN(num)) {
|
|
1022
|
+
pendingFillWarnings.get(form)?.push(`"${key}" expects a number, got: ${JSON.stringify(value)}`);
|
|
1023
|
+
return;
|
|
1024
|
+
}
|
|
1025
|
+
const min = input.min !== "" ? parseFloat(input.min) : -Infinity;
|
|
1026
|
+
const max = input.max !== "" ? parseFloat(input.max) : Infinity;
|
|
1027
|
+
if (num < min || num > max) {
|
|
1028
|
+
pendingFillWarnings.get(form)?.push(
|
|
1029
|
+
`"${key}" value ${num} is outside allowed range [${input.min || "?"}, ${input.max || "?"}]`
|
|
1030
|
+
);
|
|
1031
|
+
input.value = String(Math.min(Math.max(num, min), max));
|
|
1032
|
+
} else {
|
|
1033
|
+
input.value = String(num);
|
|
1034
|
+
}
|
|
1035
|
+
input.dispatchEvent(new InputEvent("input", { bubbles: true, cancelable: true, inputType: "insertText", data: String(num) }));
|
|
1036
|
+
input.dispatchEvent(new Event("change", { bubbles: true }));
|
|
1037
|
+
return;
|
|
1038
|
+
}
|
|
919
1039
|
if (type === "radio") {
|
|
920
1040
|
const esc = CSS.escape(key);
|
|
921
1041
|
const radios = form.querySelectorAll(
|
|
@@ -948,6 +1068,22 @@ function fillAriaField(el, value) {
|
|
|
948
1068
|
el.dispatchEvent(new MouseEvent("click", { bubbles: true }));
|
|
949
1069
|
return;
|
|
950
1070
|
}
|
|
1071
|
+
if (role === "radiogroup") {
|
|
1072
|
+
const radios = Array.from(el.querySelectorAll('[role="radio"]'));
|
|
1073
|
+
for (const radio of radios) {
|
|
1074
|
+
const val = (radio.getAttribute("data-value") ?? radio.getAttribute("aria-label") ?? radio.textContent ?? "").trim();
|
|
1075
|
+
if (val === String(value)) {
|
|
1076
|
+
radio.setAttribute("aria-checked", "true");
|
|
1077
|
+
radio.dispatchEvent(new MouseEvent("click", { bubbles: true }));
|
|
1078
|
+
for (const other of radios) {
|
|
1079
|
+
if (other !== radio)
|
|
1080
|
+
other.setAttribute("aria-checked", "false");
|
|
1081
|
+
}
|
|
1082
|
+
break;
|
|
1083
|
+
}
|
|
1084
|
+
}
|
|
1085
|
+
return;
|
|
1086
|
+
}
|
|
951
1087
|
const htmlEl = el;
|
|
952
1088
|
if (htmlEl.isContentEditable) {
|
|
953
1089
|
htmlEl.textContent = String(value ?? "");
|