auto-webmcp 0.2.6 → 0.2.7

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.
@@ -192,7 +192,7 @@ function buildStringSchema(input) {
192
192
  return prop;
193
193
  }
194
194
  function mapSelectElement(select) {
195
- const filtered = Array.from(select.options).filter((o) => o.value !== "");
195
+ const filtered = Array.from(select.options).filter((o) => o.value !== "" && !o.disabled);
196
196
  if (filtered.length === 0) {
197
197
  return { type: "string" };
198
198
  }
@@ -687,6 +687,7 @@ init_registry();
687
687
  var pendingExecutions = /* @__PURE__ */ new WeakMap();
688
688
  var lastParams = /* @__PURE__ */ new WeakMap();
689
689
  var formFieldElements = /* @__PURE__ */ new WeakMap();
690
+ var pendingWarnings = /* @__PURE__ */ new WeakMap();
690
691
  var _inputValueSetter = Object.getOwnPropertyDescriptor(HTMLInputElement.prototype, "value")?.set;
691
692
  var _textareaValueSetter = Object.getOwnPropertyDescriptor(HTMLTextAreaElement.prototype, "value")?.set;
692
693
  var _checkedSetter = Object.getOwnPropertyDescriptor(HTMLInputElement.prototype, "checked")?.set;
@@ -701,22 +702,36 @@ function buildExecuteHandler(form, config, toolName, metadata) {
701
702
  return new Promise((resolve, reject) => {
702
703
  pendingExecutions.set(form, { resolve, reject });
703
704
  if (config.autoSubmit || form.hasAttribute("toolautosubmit") || form.dataset["webmcpAutosubmit"] !== void 0) {
704
- setTimeout(() => {
705
- fillFormFields(form, params);
706
- let submitForm = form;
707
- if (!form.isConnected) {
708
- const liveBtn = document.querySelector(
709
- 'button[type="submit"]:not([disabled]), input[type="submit"]:not([disabled])'
710
- );
711
- const found = liveBtn?.closest("form");
712
- if (found) {
713
- submitForm = found;
714
- pendingExecutions.set(submitForm, { resolve, reject });
715
- attachSubmitInterceptor(submitForm, toolName);
705
+ waitForDomStable(form).then(async () => {
706
+ try {
707
+ fillFormFields(form, params);
708
+ for (let attempt = 0; attempt < 2; attempt++) {
709
+ const reset = getResetFields(form, params, formFieldElements.get(form));
710
+ if (reset.length === 0)
711
+ break;
712
+ fillFormFields(form, params);
713
+ await waitForDomStable(form, 400, 100);
716
714
  }
715
+ let submitForm = form;
716
+ if (!form.isConnected) {
717
+ const liveBtn = document.querySelector(
718
+ 'button[type="submit"]:not([disabled]), input[type="submit"]:not([disabled])'
719
+ );
720
+ const found = liveBtn?.closest("form");
721
+ if (found) {
722
+ submitForm = found;
723
+ pendingExecutions.set(submitForm, { resolve, reject });
724
+ attachSubmitInterceptor(submitForm, toolName);
725
+ }
726
+ }
727
+ const missing = getMissingRequired(metadata, params);
728
+ if (missing.length > 0)
729
+ pendingWarnings.set(submitForm, missing);
730
+ submitForm.requestSubmit();
731
+ } catch (err) {
732
+ reject(err instanceof Error ? err : new Error(String(err)));
717
733
  }
718
- submitForm.requestSubmit();
719
- }, 300);
734
+ });
720
735
  }
721
736
  });
722
737
  };
@@ -732,7 +747,10 @@ function attachSubmitInterceptor(form, toolName) {
732
747
  const { resolve } = pending;
733
748
  pendingExecutions.delete(form);
734
749
  const formData = serializeFormData(form, lastParams.get(form), formFieldElements.get(form));
735
- const text = `Form submitted. Fields: ${JSON.stringify(formData)}`;
750
+ const missing = pendingWarnings.get(form);
751
+ pendingWarnings.delete(form);
752
+ const warningText = missing?.length ? ` Note: required fields were not filled: ${missing.join(", ")}.` : "";
753
+ const text = `Form submitted. Fields: ${JSON.stringify(formData)}${warningText}`;
736
754
  const result = { content: [{ type: "text", text }] };
737
755
  if (e.agentInvoked && typeof e.respondWith === "function") {
738
756
  e.preventDefault();
@@ -938,6 +956,50 @@ function fillElement(el, value) {
938
956
  fillAriaField(el, value);
939
957
  }
940
958
  }
959
+ function waitForDomStable(form, maxMs = 800, debounceMs = 150) {
960
+ return new Promise((resolve) => {
961
+ let settled = false;
962
+ let debounceTimer = null;
963
+ const settle = () => {
964
+ if (settled)
965
+ return;
966
+ settled = true;
967
+ observer2.disconnect();
968
+ if (debounceTimer !== null)
969
+ clearTimeout(debounceTimer);
970
+ resolve();
971
+ };
972
+ const observer2 = new MutationObserver(() => {
973
+ if (debounceTimer !== null)
974
+ clearTimeout(debounceTimer);
975
+ debounceTimer = setTimeout(settle, debounceMs);
976
+ });
977
+ observer2.observe(form, { childList: true, subtree: true, attributes: true, characterData: true });
978
+ setTimeout(settle, maxMs);
979
+ debounceTimer = setTimeout(settle, debounceMs);
980
+ });
981
+ }
982
+ function getResetFields(form, params, fieldEls) {
983
+ const reset = [];
984
+ for (const [key, expected] of Object.entries(params)) {
985
+ const el = findNativeField(form, key) ?? (fieldEls?.get(key) ?? null);
986
+ if (!el)
987
+ continue;
988
+ if (el instanceof HTMLInputElement && el.type === "checkbox") {
989
+ if (el.checked !== Boolean(expected))
990
+ reset.push(key);
991
+ } else if (el instanceof HTMLInputElement || el instanceof HTMLTextAreaElement || el instanceof HTMLSelectElement) {
992
+ if (el.value !== String(expected ?? ""))
993
+ reset.push(key);
994
+ }
995
+ }
996
+ return reset;
997
+ }
998
+ function getMissingRequired(metadata, params) {
999
+ if (!metadata?.inputSchema?.required?.length)
1000
+ return [];
1001
+ return metadata.inputSchema.required.filter((fieldKey) => !(fieldKey in params));
1002
+ }
941
1003
 
942
1004
  // src/enhancer.ts
943
1005
  async function enrichMetadata(metadata, enhancer) {