auto-webmcp 0.3.5 → 0.3.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.
@@ -1 +1 @@
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,eAAe;IAC9B,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,aAAa,CAAC,EAAE,OAAO,CAAC;CACzB;AAED,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,UAAU,CAAC;IACxB,WAAW,CAAC,EAAE,eAAe,CAAC;IAC9B,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,CAOxF;AAipBD;;;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"}
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,eAAe;IAC9B,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,aAAa,CAAC,EAAE,OAAO,CAAC;CACzB;AAED,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,UAAU,CAAC;IACxB,WAAW,CAAC,EAAE,eAAe,CAAC;IAC9B,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,CAOxF;AAipBD;;;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,CAMd"}
@@ -630,7 +630,7 @@ function buildSchema(form) {
630
630
  required.push(key);
631
631
  }
632
632
  }
633
- return { schema: { type: "object", properties, required }, fieldElements };
633
+ return { schema: { "$schema": "https://json-schema.org/draft/2020-12/schema", type: "object", properties, required }, fieldElements };
634
634
  }
635
635
  function resolveNativeControlFallbackKey(control) {
636
636
  const el = control;
@@ -835,7 +835,24 @@ function analyzeOrphanInputGroup(container, inputs, submitBtn) {
835
835
  const name = inferOrphanToolName(container, submitBtn);
836
836
  const description = inferOrphanToolDescription(container);
837
837
  const { schema: inputSchema, fieldElements } = buildSchemaFromInputs(inputs);
838
- return { name, description, inputSchema, fieldElements };
838
+ const annotations = inferOrphanAnnotations(submitBtn);
839
+ return { name, description, inputSchema, annotations, fieldElements };
840
+ }
841
+ function inferOrphanAnnotations(submitBtn) {
842
+ const annotations = {};
843
+ const submitText = submitBtn instanceof HTMLInputElement ? submitBtn.value.trim() : submitBtn?.textContent?.trim() ?? "";
844
+ if (READONLY_BUTTON_PATTERNS.test(submitText)) {
845
+ annotations.readOnlyHint = true;
846
+ annotations.idempotentHint = true;
847
+ }
848
+ if (DESTRUCTIVE_BUTTON_PATTERNS.test(submitText)) {
849
+ annotations.destructiveHint = true;
850
+ }
851
+ if (annotations.readOnlyHint !== true) {
852
+ annotations.openWorldHint = true;
853
+ }
854
+ const hasNonDefault = annotations.readOnlyHint === true || annotations.destructiveHint === true || annotations.idempotentHint === true || annotations.openWorldHint === false;
855
+ return hasNonDefault ? annotations : {};
839
856
  }
840
857
  function inferOrphanToolName(container, submitBtn) {
841
858
  if (submitBtn) {
@@ -890,8 +907,8 @@ function buildSchemaFromInputs(inputs) {
890
907
  const processedRadioGroups = /* @__PURE__ */ new Set();
891
908
  const processedCheckboxGroups = /* @__PURE__ */ new Set();
892
909
  for (const control of inputs) {
893
- const name = control.name;
894
- const fieldKey = name || resolveNativeControlFallbackKey(control);
910
+ const rawName = control.name;
911
+ const fieldKey = (rawName ? sanitizeName(rawName) : null) || resolveNativeControlFallbackKey(control);
895
912
  if (!fieldKey)
896
913
  continue;
897
914
  if (control instanceof HTMLInputElement && control.type === "radio") {
@@ -930,12 +947,12 @@ function buildSchemaFromInputs(inputs) {
930
947
  }
931
948
  }
932
949
  properties[fieldKey] = schemaProp;
933
- if (!name)
950
+ if (!rawName)
934
951
  fieldElements.set(fieldKey, control);
935
952
  if (control.required)
936
953
  required.push(fieldKey);
937
954
  }
938
- return { schema: { type: "object", properties, required }, fieldElements };
955
+ return { schema: { "$schema": "https://json-schema.org/draft/2020-12/schema", type: "object", properties, required }, fieldElements };
939
956
  }
940
957
 
941
958
  // src/discovery.ts
@@ -1555,6 +1572,7 @@ async function scanOrphanInputs(config) {
1555
1572
  if (!isWebMCPSupported())
1556
1573
  return;
1557
1574
  const SUBMIT_BTN_SELECTOR = '[type="submit"]:not([disabled]), button:not([type]):not([disabled])';
1575
+ const SUBMIT_BTN_GROUPING_SELECTOR = '[type="submit"], button:not([type])';
1558
1576
  const SUBMIT_TEXT_RE = /subscribe|submit|sign[\s-]?up|send|join|go|search/i;
1559
1577
  const orphanInputs = Array.from(
1560
1578
  document.querySelectorAll(
@@ -1574,7 +1592,7 @@ async function scanOrphanInputs(config) {
1574
1592
  let container = input.parentElement;
1575
1593
  let foundContainer = input.parentElement ?? document.body;
1576
1594
  while (container && container !== document.body) {
1577
- const hasSubmitBtn = container.querySelector(SUBMIT_BTN_SELECTOR) !== null || Array.from(container.querySelectorAll("button")).some(
1595
+ const hasSubmitBtn = container.querySelector(SUBMIT_BTN_GROUPING_SELECTOR) !== null || Array.from(container.querySelectorAll("button")).some(
1578
1596
  (b) => SUBMIT_TEXT_RE.test(b.textContent ?? "")
1579
1597
  );
1580
1598
  if (hasSubmitBtn) {
@@ -1622,15 +1640,42 @@ async function scanOrphanInputs(config) {
1622
1640
  }
1623
1641
  }
1624
1642
  window.dispatchEvent(new CustomEvent("toolactivated", { detail: { toolName } }));
1625
- return { content: [{ type: "text", text: "Fields filled. Ready to submit." }] };
1643
+ if (!config.autoSubmit) {
1644
+ return { content: [{ type: "text", text: "Fields filled. Ready to submit." }] };
1645
+ }
1646
+ let btn = null;
1647
+ const deadline = Date.now() + 2e3;
1648
+ while (Date.now() < deadline) {
1649
+ const candidates = Array.from(
1650
+ container.querySelectorAll(SUBMIT_BTN_SELECTOR)
1651
+ ).filter((b) => {
1652
+ const r = b.getBoundingClientRect();
1653
+ return r.width > 0 && r.height > 0;
1654
+ });
1655
+ const last = candidates[candidates.length - 1] ?? null;
1656
+ if (last) {
1657
+ btn = last;
1658
+ break;
1659
+ }
1660
+ await new Promise((r) => setTimeout(r, 100));
1661
+ }
1662
+ if (!btn) {
1663
+ return { content: [{ type: "text", text: "Fields filled but the submit button is still disabled. The page may require additional input before submitting." }] };
1664
+ }
1665
+ btn.click();
1666
+ return { content: [{ type: "text", text: "Fields filled and form submitted." }] };
1626
1667
  };
1627
1668
  try {
1628
- await navigator.modelContext.registerTool({
1669
+ const toolDef = {
1629
1670
  name: metadata.name,
1630
1671
  description: metadata.description,
1631
1672
  inputSchema: metadata.inputSchema,
1632
1673
  execute
1633
- });
1674
+ };
1675
+ if (metadata.annotations && Object.keys(metadata.annotations).length > 0) {
1676
+ toolDef.annotations = metadata.annotations;
1677
+ }
1678
+ await navigator.modelContext.registerTool(toolDef);
1634
1679
  if (config.debug) {
1635
1680
  console.debug(`[auto-webmcp] Orphan tool registered: ${metadata.name}`, metadata);
1636
1681
  }