auto-webmcp 0.3.0 → 0.3.1
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 +75 -25
- package/dist/auto-webmcp.cjs.js.map +2 -2
- package/dist/auto-webmcp.esm.js +75 -25
- 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 +14 -0
- package/dist/interceptor.d.ts.map +1 -1
- package/package.json +1 -1
package/dist/auto-webmcp.esm.js
CHANGED
|
@@ -484,17 +484,39 @@ function extractDefaultValue(control) {
|
|
|
484
484
|
}
|
|
485
485
|
return void 0;
|
|
486
486
|
}
|
|
487
|
+
function collectShadowControls(root, visited = /* @__PURE__ */ new Set()) {
|
|
488
|
+
if (visited.has(root))
|
|
489
|
+
return [];
|
|
490
|
+
visited.add(root);
|
|
491
|
+
const results = [];
|
|
492
|
+
for (const el of Array.from(root.querySelectorAll("*"))) {
|
|
493
|
+
if (el.shadowRoot) {
|
|
494
|
+
results.push(
|
|
495
|
+
...Array.from(
|
|
496
|
+
el.shadowRoot.querySelectorAll(
|
|
497
|
+
"input, textarea, select"
|
|
498
|
+
)
|
|
499
|
+
),
|
|
500
|
+
...collectShadowControls(el.shadowRoot, visited)
|
|
501
|
+
);
|
|
502
|
+
}
|
|
503
|
+
}
|
|
504
|
+
return results;
|
|
505
|
+
}
|
|
487
506
|
function buildSchema(form) {
|
|
488
507
|
const properties = {};
|
|
489
508
|
const required = [];
|
|
490
509
|
const fieldElements = /* @__PURE__ */ new Map();
|
|
491
510
|
const processedRadioGroups = /* @__PURE__ */ new Set();
|
|
492
511
|
const processedCheckboxGroups = /* @__PURE__ */ new Set();
|
|
493
|
-
const controls =
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
512
|
+
const controls = [
|
|
513
|
+
...Array.from(
|
|
514
|
+
form.querySelectorAll(
|
|
515
|
+
"input, textarea, select"
|
|
516
|
+
)
|
|
517
|
+
),
|
|
518
|
+
...collectShadowControls(form)
|
|
519
|
+
];
|
|
498
520
|
for (const control of controls) {
|
|
499
521
|
const name = control.name;
|
|
500
522
|
const fieldKey = name || resolveNativeControlFallbackKey(control);
|
|
@@ -672,9 +694,6 @@ function resolveAriaFieldKey(el) {
|
|
|
672
694
|
return null;
|
|
673
695
|
}
|
|
674
696
|
function inferAriaFieldTitle(el) {
|
|
675
|
-
const nativeTitle = el.getAttribute("toolparamtitle");
|
|
676
|
-
if (nativeTitle?.trim())
|
|
677
|
-
return nativeTitle.trim();
|
|
678
697
|
const htmlEl = el;
|
|
679
698
|
if (htmlEl.dataset?.["webmcpTitle"])
|
|
680
699
|
return htmlEl.dataset["webmcpTitle"];
|
|
@@ -713,9 +732,6 @@ function inferAriaFieldDescription(el) {
|
|
|
713
732
|
return "";
|
|
714
733
|
}
|
|
715
734
|
function inferFieldTitle(control) {
|
|
716
|
-
const nativeTitle = control.getAttribute("toolparamtitle");
|
|
717
|
-
if (nativeTitle?.trim())
|
|
718
|
-
return nativeTitle.trim();
|
|
719
735
|
if ("dataset" in control && control.dataset["webmcpTitle"]) {
|
|
720
736
|
return control.dataset["webmcpTitle"];
|
|
721
737
|
}
|
|
@@ -925,6 +941,9 @@ function buildExecuteHandler(form, config, toolName, metadata) {
|
|
|
925
941
|
return async (params) => {
|
|
926
942
|
pendingFillWarnings.set(form, []);
|
|
927
943
|
fillFormFields(form, params);
|
|
944
|
+
const missingNow = getMissingRequired(metadata, params);
|
|
945
|
+
if (missingNow.length > 0)
|
|
946
|
+
pendingWarnings.set(form, missingNow);
|
|
928
947
|
window.dispatchEvent(new CustomEvent("toolactivated", { detail: { toolName } }));
|
|
929
948
|
return new Promise((resolve, reject) => {
|
|
930
949
|
pendingExecutions.set(form, { resolve, reject });
|
|
@@ -951,9 +970,10 @@ function buildExecuteHandler(form, config, toolName, metadata) {
|
|
|
951
970
|
attachSubmitInterceptor(submitForm, toolName);
|
|
952
971
|
}
|
|
953
972
|
}
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
pendingWarnings.
|
|
973
|
+
if (submitForm !== form && pendingWarnings.has(form)) {
|
|
974
|
+
pendingWarnings.set(submitForm, pendingWarnings.get(form));
|
|
975
|
+
pendingWarnings.delete(form);
|
|
976
|
+
}
|
|
957
977
|
submitForm.requestSubmit();
|
|
958
978
|
} catch (err) {
|
|
959
979
|
reject(err instanceof Error ? err : new Error(String(err)));
|
|
@@ -975,17 +995,37 @@ function attachSubmitInterceptor(form, toolName) {
|
|
|
975
995
|
pendingExecutions.delete(form);
|
|
976
996
|
const formData = serializeFormData(form, lastParams.get(form), formFieldElements.get(form));
|
|
977
997
|
lastFilledSnapshot.delete(form);
|
|
978
|
-
const
|
|
998
|
+
const missingRequired = pendingWarnings.get(form) ?? [];
|
|
979
999
|
pendingWarnings.delete(form);
|
|
980
1000
|
const fillWarnings = pendingFillWarnings.get(form) ?? [];
|
|
981
1001
|
pendingFillWarnings.delete(form);
|
|
982
|
-
const
|
|
983
|
-
|
|
984
|
-
|
|
1002
|
+
const skippedFields = fillWarnings.filter((w) => w.type === "not_filled").map((w) => w.field);
|
|
1003
|
+
const structured = {
|
|
1004
|
+
status: missingRequired.length > 0 || skippedFields.length > 0 ? "partial" : "success",
|
|
1005
|
+
filled_fields: formData,
|
|
1006
|
+
skipped_fields: skippedFields,
|
|
1007
|
+
missing_required: missingRequired,
|
|
1008
|
+
warnings: [
|
|
1009
|
+
...missingRequired.map((f) => ({
|
|
1010
|
+
field: f,
|
|
1011
|
+
type: "missing_required",
|
|
1012
|
+
message: `required field "${f}" was not provided`
|
|
1013
|
+
})),
|
|
1014
|
+
...fillWarnings
|
|
1015
|
+
]
|
|
1016
|
+
};
|
|
1017
|
+
const allWarnMessages = [
|
|
1018
|
+
...missingRequired.length ? [`required fields were not filled: ${missingRequired.join(", ")}`] : [],
|
|
1019
|
+
...fillWarnings.map((w) => w.message)
|
|
985
1020
|
];
|
|
986
|
-
const warningText =
|
|
1021
|
+
const warningText = allWarnMessages.length ? ` Note: ${allWarnMessages.join("; ")}.` : "";
|
|
987
1022
|
const text = `Form submitted. Fields: ${JSON.stringify(formData)}${warningText}`;
|
|
988
|
-
const result = {
|
|
1023
|
+
const result = {
|
|
1024
|
+
content: [
|
|
1025
|
+
{ type: "text", text },
|
|
1026
|
+
{ type: "text", text: JSON.stringify(structured) }
|
|
1027
|
+
]
|
|
1028
|
+
};
|
|
989
1029
|
if (e.agentInvoked && typeof e.respondWith === "function") {
|
|
990
1030
|
e.preventDefault();
|
|
991
1031
|
e.respondWith(Promise.resolve(result));
|
|
@@ -1119,16 +1159,26 @@ function fillInput(input, form, key, value) {
|
|
|
1119
1159
|
const raw = String(value ?? "");
|
|
1120
1160
|
const num = Number(raw);
|
|
1121
1161
|
if (raw === "" || isNaN(num)) {
|
|
1122
|
-
pendingFillWarnings.get(form)?.push(
|
|
1162
|
+
pendingFillWarnings.get(form)?.push({
|
|
1163
|
+
field: key,
|
|
1164
|
+
type: "type_mismatch",
|
|
1165
|
+
message: `"${key}" expects a number, got: ${JSON.stringify(value)}`,
|
|
1166
|
+
original: value
|
|
1167
|
+
});
|
|
1123
1168
|
return;
|
|
1124
1169
|
}
|
|
1125
1170
|
const min = input.min !== "" ? parseFloat(input.min) : -Infinity;
|
|
1126
1171
|
const max = input.max !== "" ? parseFloat(input.max) : Infinity;
|
|
1127
1172
|
if (num < min || num > max) {
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1173
|
+
const clamped = Math.min(Math.max(num, min), max);
|
|
1174
|
+
pendingFillWarnings.get(form)?.push({
|
|
1175
|
+
field: key,
|
|
1176
|
+
type: "clamped",
|
|
1177
|
+
message: `"${key}" value ${num} is outside allowed range [${input.min || "?"}, ${input.max || "?"}], clamped to ${clamped}`,
|
|
1178
|
+
original: num,
|
|
1179
|
+
actual: clamped
|
|
1180
|
+
});
|
|
1181
|
+
input.value = String(clamped);
|
|
1132
1182
|
} else {
|
|
1133
1183
|
input.value = String(num);
|
|
1134
1184
|
}
|