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.
@@ -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 = Array.from(
494
- form.querySelectorAll(
495
- "input, textarea, select"
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
- const missing = getMissingRequired(metadata, params);
955
- if (missing.length > 0)
956
- pendingWarnings.set(submitForm, missing);
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 missing = pendingWarnings.get(form);
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 allWarnings = [
983
- ...missing?.length ? [`required fields were not filled: ${missing.join(", ")}`] : [],
984
- ...fillWarnings
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 = allWarnings.length ? ` Note: ${allWarnings.join("; ")}.` : "";
1021
+ const warningText = allWarnMessages.length ? ` Note: ${allWarnMessages.join("; ")}.` : "";
987
1022
  const text = `Form submitted. Fields: ${JSON.stringify(formData)}${warningText}`;
988
- const result = { content: [{ type: "text", text }] };
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(`"${key}" expects a number, got: ${JSON.stringify(value)}`);
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
- pendingFillWarnings.get(form)?.push(
1129
- `"${key}" value ${num} is outside allowed range [${input.min || "?"}, ${input.max || "?"}]`
1130
- );
1131
- input.value = String(Math.min(Math.max(num, min), max));
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
  }