auto-webmcp 0.1.1 → 0.2.0

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/README.md CHANGED
@@ -4,8 +4,8 @@
4
4
 
5
5
  Drop in one script tag (or one `import`) and every `<form>` on your page is
6
6
  instantly registered as a structured tool that in-browser AI agents can
7
- discover and use via Google Chrome's
8
- [WebMCP proposal](https://github.com/nicktindall/mcp-browser).
7
+ discover and use via Chrome's
8
+ [WebMCP](https://developer.chrome.com/blog/webmcp-epp) early preview.
9
9
 
10
10
  ---
11
11
 
@@ -1 +1 @@
1
- {"version":3,"file":"analyzer.d.ts","sourceRoot":"","sources":["../src/analyzer.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,UAAU,EAA2D,MAAM,aAAa,CAAC;AAClG,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;CACzB;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"}
1
+ {"version":3,"file":"analyzer.d.ts","sourceRoot":"","sources":["../src/analyzer.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,UAAU,EAA8E,MAAM,aAAa,CAAC;AACrH,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;CACzB;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"}
@@ -169,14 +169,13 @@ function buildStringSchema(input) {
169
169
  return prop;
170
170
  }
171
171
  function mapSelectElement(select) {
172
- const options = Array.from(select.options).filter((o) => o.value !== "").map((o) => o.value);
173
- if (options.length === 0) {
172
+ const filtered = Array.from(select.options).filter((o) => o.value !== "");
173
+ if (filtered.length === 0) {
174
174
  return { type: "string" };
175
175
  }
176
- return {
177
- type: "string",
178
- enum: options
179
- };
176
+ const enumValues = filtered.map((o) => o.value);
177
+ const oneOf = filtered.map((o) => ({ const: o.value, title: o.text.trim() || o.value }));
178
+ return { type: "string", enum: enumValues, oneOf };
180
179
  }
181
180
  function collectRadioEnum(form, name) {
182
181
  const radios = Array.from(
@@ -184,6 +183,34 @@ function collectRadioEnum(form, name) {
184
183
  );
185
184
  return radios.map((r) => r.value).filter((v) => v !== "");
186
185
  }
186
+ function collectRadioOneOf(form, name) {
187
+ const radios = Array.from(
188
+ form.querySelectorAll(`input[type="radio"][name="${CSS.escape(name)}"]`)
189
+ ).filter((r) => r.value !== "");
190
+ return radios.map((r) => {
191
+ const title = getRadioLabelText(r);
192
+ return { const: r.value, title: title || r.value };
193
+ });
194
+ }
195
+ function getRadioLabelText(radio) {
196
+ const parent = radio.closest("label");
197
+ if (parent) {
198
+ const clone = parent.cloneNode(true);
199
+ clone.querySelectorAll("input, select, textarea, button").forEach((el) => el.remove());
200
+ const text = clone.textContent?.trim() ?? "";
201
+ if (text)
202
+ return text;
203
+ }
204
+ if (radio.id) {
205
+ const label = document.querySelector(`label[for="${CSS.escape(radio.id)}"]`);
206
+ if (label) {
207
+ const text = label.textContent?.trim() ?? "";
208
+ if (text)
209
+ return text;
210
+ }
211
+ }
212
+ return "";
213
+ }
187
214
 
188
215
  // src/analyzer.ts
189
216
  var formIndex = 0;
@@ -194,6 +221,9 @@ function analyzeForm(form, override) {
194
221
  return { name, description, inputSchema };
195
222
  }
196
223
  function inferToolName(form) {
224
+ const nativeName = form.getAttribute("toolname");
225
+ if (nativeName)
226
+ return sanitizeName(nativeName);
197
227
  const explicit = form.dataset["webmcpName"];
198
228
  if (explicit)
199
229
  return sanitizeName(explicit);
@@ -257,6 +287,9 @@ function getLastPathSegment(url) {
257
287
  }
258
288
  }
259
289
  function inferToolDescription(form) {
290
+ const nativeDesc = form.getAttribute("tooldescription");
291
+ if (nativeDesc)
292
+ return nativeDesc.trim();
260
293
  const explicit = form.dataset["webmcpDescription"];
261
294
  if (explicit)
262
295
  return explicit.trim();
@@ -309,6 +342,9 @@ function buildSchema(form) {
309
342
  schemaProp.description = desc;
310
343
  if (control instanceof HTMLInputElement && control.type === "radio") {
311
344
  schemaProp.enum = collectRadioEnum(form, name);
345
+ const radioOneOf = collectRadioOneOf(form, name);
346
+ if (radioOneOf.length > 0)
347
+ schemaProp.oneOf = radioOneOf;
312
348
  }
313
349
  properties[name] = schemaProp;
314
350
  if (control.required) {
@@ -331,6 +367,9 @@ function inferFieldTitle(control) {
331
367
  return "";
332
368
  }
333
369
  function inferFieldDescription(control) {
370
+ const nativeParamDesc = control.getAttribute("toolparamdescription");
371
+ if (nativeParamDesc)
372
+ return nativeParamDesc.trim();
334
373
  const el = control;
335
374
  if (el.dataset["webmcpDescription"])
336
375
  return el.dataset["webmcpDescription"];
@@ -381,19 +420,20 @@ init_registry();
381
420
 
382
421
  // src/interceptor.ts
383
422
  var pendingExecutions = /* @__PURE__ */ new WeakMap();
384
- function buildExecuteHandler(form, config) {
385
- attachSubmitInterceptor(form);
423
+ function buildExecuteHandler(form, config, toolName) {
424
+ attachSubmitInterceptor(form, toolName);
386
425
  return async (params) => {
387
426
  fillFormFields(form, params);
427
+ window.dispatchEvent(new CustomEvent("toolactivated", { detail: { toolName } }));
388
428
  return new Promise((resolve, reject) => {
389
429
  pendingExecutions.set(form, { resolve, reject });
390
- if (config.autoSubmit || form.dataset["webmcpAutosubmit"] !== void 0) {
430
+ if (config.autoSubmit || form.hasAttribute("toolautosubmit") || form.dataset["webmcpAutosubmit"] !== void 0) {
391
431
  form.requestSubmit();
392
432
  }
393
433
  });
394
434
  };
395
435
  }
396
- function attachSubmitInterceptor(form) {
436
+ function attachSubmitInterceptor(form, toolName) {
397
437
  if (form["__awmcp_intercepted"])
398
438
  return;
399
439
  form["__awmcp_intercepted"] = true;
@@ -404,19 +444,16 @@ function attachSubmitInterceptor(form) {
404
444
  const { resolve } = pending;
405
445
  pendingExecutions.delete(form);
406
446
  const formData = serializeFormData(form);
447
+ const text = JSON.stringify(formData);
448
+ const result = { content: [{ type: "text", text }] };
407
449
  if (e.agentInvoked && typeof e.respondWith === "function") {
408
450
  e.preventDefault();
409
- e.respondWith(
410
- Promise.resolve({
411
- success: true,
412
- data: formData
413
- })
414
- );
415
- resolve({ success: true, data: formData });
416
- } else {
417
- const targetUrl = resolveFormAction(form);
418
- resolve({ success: true, data: formData, url: targetUrl });
451
+ e.respondWith(Promise.resolve(result));
419
452
  }
453
+ resolve(result);
454
+ });
455
+ form.addEventListener("reset", () => {
456
+ window.dispatchEvent(new CustomEvent("toolcancel", { detail: { toolName } }));
420
457
  });
421
458
  }
422
459
  function fillFormFields(form, params) {
@@ -481,15 +518,6 @@ function serializeFormData(form) {
481
518
  }
482
519
  return result;
483
520
  }
484
- function resolveFormAction(form) {
485
- if (form.action) {
486
- try {
487
- return new URL(form.action, window.location.href).href;
488
- } catch {
489
- }
490
- }
491
- return window.location.href;
492
- }
493
521
 
494
522
  // src/enhancer.ts
495
523
  async function enrichMetadata(metadata, enhancer) {
@@ -566,8 +594,6 @@ function emit(type, form, toolName) {
566
594
  );
567
595
  }
568
596
  function isExcluded(form, config) {
569
- if (form.hasAttribute("toolname"))
570
- return true;
571
597
  if (form.dataset["noWebmcp"] !== void 0)
572
598
  return true;
573
599
  for (const selector of config.exclude) {
@@ -598,7 +624,10 @@ async function registerForm(form, config) {
598
624
  console.debug(`[auto-webmcp] Enriching: ${metadata.name}\u2026`);
599
625
  metadata = await enrichMetadata(metadata, config.enhance);
600
626
  }
601
- const execute = buildExecuteHandler(form, config);
627
+ if (config.debug) {
628
+ warnToolQuality(metadata.name, metadata.description);
629
+ }
630
+ const execute = buildExecuteHandler(form, config, metadata.name);
602
631
  await registerFormTool(form, metadata, execute);
603
632
  if (config.debug) {
604
633
  console.debug(`[auto-webmcp] Registered: ${metadata.name}`, metadata);
@@ -662,6 +691,17 @@ async function scanForms(config) {
662
691
  const forms = Array.from(document.querySelectorAll("form"));
663
692
  await Promise.all(forms.map((form) => registerForm(form, config)));
664
693
  }
694
+ function warnToolQuality(name, description) {
695
+ if (/^form_\d+$|^submit$|^form$/.test(name)) {
696
+ console.warn(`[auto-webmcp] Tool "${name}" has a generic name. Consider adding a toolname or data-webmcp-name attribute.`);
697
+ }
698
+ if (!description || description === "Submit form") {
699
+ console.warn(`[auto-webmcp] Tool "${name}" has no meaningful description.`);
700
+ }
701
+ if (/don'?t|do not|never|avoid|not for/i.test(description)) {
702
+ console.warn(`[auto-webmcp] Tool "${name}" description contains negative instructions. Per spec best practices, prefer positive descriptions.`);
703
+ }
704
+ }
665
705
  async function startDiscovery(config) {
666
706
  if (document.readyState === "loading") {
667
707
  await new Promise(
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../src/registry.ts", "../src/index.ts", "../src/config.ts", "../src/schema.ts", "../src/analyzer.ts", "../src/discovery.ts", "../src/interceptor.ts", "../src/enhancer.ts"],
4
- "sourcesContent": ["/**\n * registry.ts \u2014 Wrapper around navigator.modelContext WebMCP Imperative API\n */\n\nimport { ToolMetadata } from './analyzer.js';\n\n// ---------------------------------------------------------------------------\n// WebMCP type declarations (not yet in TypeScript DOM lib)\n// ---------------------------------------------------------------------------\n\nexport interface WebMCPTool {\n name: string;\n description: string;\n inputSchema: object;\n execute: (params: Record<string, unknown>) => Promise<unknown>;\n}\n\ndeclare global {\n interface Navigator {\n modelContext?: {\n registerTool(tool: WebMCPTool): Promise<void>;\n unregisterTool(name: string): Promise<void>;\n };\n }\n}\n\n// ---------------------------------------------------------------------------\n// Registry\n// ---------------------------------------------------------------------------\n\n/** Tracks registered tools: form element \u2192 tool name */\nconst registeredTools = new Map<HTMLFormElement, string>();\n\n/** True if the browser supports navigator.modelContext */\nexport function isWebMCPSupported(): boolean {\n return typeof navigator !== 'undefined' && typeof navigator.modelContext !== 'undefined';\n}\n\n/**\n * Register a form as a WebMCP tool.\n * Silently no-ops if WebMCP is not supported.\n */\nexport async function registerFormTool(\n form: HTMLFormElement,\n metadata: ToolMetadata,\n execute: (params: Record<string, unknown>) => Promise<unknown>,\n): Promise<void> {\n if (!isWebMCPSupported()) return;\n\n // Unregister any previously-registered tool for this same form element\n const existing = registeredTools.get(form);\n if (existing) {\n await unregisterFormTool(form);\n }\n\n await navigator.modelContext!.registerTool({\n name: metadata.name,\n description: metadata.description,\n inputSchema: metadata.inputSchema,\n execute,\n });\n\n registeredTools.set(form, metadata.name);\n}\n\n/**\n * Unregister the WebMCP tool associated with a form element.\n * Silently no-ops if not registered or WebMCP not supported.\n */\nexport async function unregisterFormTool(form: HTMLFormElement): Promise<void> {\n if (!isWebMCPSupported()) return;\n\n const name = registeredTools.get(form);\n if (!name) return;\n\n try {\n await navigator.modelContext!.unregisterTool(name);\n } catch {\n // Tool may have already been removed \u2014 ignore\n }\n\n registeredTools.delete(form);\n}\n\n/** Get the registered tool name for a form, if any */\nexport function getRegisteredToolName(form: HTMLFormElement): string | undefined {\n return registeredTools.get(form);\n}\n\n/** Return a snapshot of all currently registered form\u2192name pairs */\nexport function getAllRegisteredTools(): Array<{ form: HTMLFormElement; name: string }> {\n return Array.from(registeredTools.entries()).map(([form, name]) => ({ form, name }));\n}\n\n/** Unregister all tools (e.g. on teardown) */\nexport async function unregisterAll(): Promise<void> {\n const entries = Array.from(registeredTools.entries());\n await Promise.all(entries.map(([form]) => unregisterFormTool(form)));\n}\n", "/**\n * index.ts \u2014 Entry point & public API for auto-webmcp\n *\n * Zero-config drop-in:\n * <script src=\"auto-webmcp.iife.js\"></script>\n *\n * ESM usage:\n * import { autoWebMCP } from 'auto-webmcp';\n * autoWebMCP({ exclude: ['#login-form'] });\n */\n\nimport { AutoWebMCPConfig, resolveConfig } from './config.js';\nimport { startDiscovery, stopDiscovery } from './discovery.js';\nimport { unregisterAll, getAllRegisteredTools, isWebMCPSupported } from './registry.js';\n\nexport type { AutoWebMCPConfig } from './config.js';\nexport type { ToolMetadata } from './analyzer.js';\nexport type { JsonSchema, JsonSchemaProperty } from './schema.js';\n\nexport interface AutoWebMCPHandle {\n /** Stop observing and unregister all tools */\n destroy: () => Promise<void>;\n /** Return all currently registered tools */\n getTools: () => Array<{ form: HTMLFormElement; name: string }>;\n /** True if running in a WebMCP-capable browser */\n isSupported: boolean;\n}\n\n/**\n * Initialize auto-webmcp.\n *\n * @param config \u2014 Optional configuration (all fields optional)\n * @returns A handle to inspect or tear down the instance\n */\nexport async function autoWebMCP(config?: AutoWebMCPConfig): Promise<AutoWebMCPHandle> {\n const resolved = resolveConfig(config);\n\n if (resolved.debug) {\n console.debug('[auto-webmcp] Initializing', {\n webmcpSupported: isWebMCPSupported(),\n config: resolved,\n });\n }\n\n await startDiscovery(resolved);\n\n return {\n destroy: async () => {\n stopDiscovery();\n await unregisterAll();\n },\n getTools: getAllRegisteredTools,\n isSupported: isWebMCPSupported(),\n };\n}\n\n// ---------------------------------------------------------------------------\n// Auto-init for IIFE / script-tag usage\n// ---------------------------------------------------------------------------\n\n// When loaded as a <script> tag, auto-initialize with zero config.\n// Users can prevent this by setting window.__AUTO_WEBMCP_NO_AUTOINIT = true\n// before the script loads.\n\nif (\n typeof window !== 'undefined' &&\n !(window as unknown as Record<string, unknown>)['__AUTO_WEBMCP_NO_AUTOINIT']\n) {\n void autoWebMCP();\n}\n", "/**\n * config.ts \u2014 User configuration merging & defaults\n */\n\nexport interface EnhancerConfig {\n provider: 'gemini' | 'claude';\n apiKey: string;\n model?: string;\n}\n\nexport interface FormOverride {\n name?: string;\n description?: string;\n}\n\nexport interface AutoWebMCPConfig {\n /**\n * CSS selectors for forms to skip. E.g. ['#login-form', '[data-no-webmcp]']\n */\n exclude?: string[];\n\n /**\n * If true, agent-invoked forms are auto-submitted without human confirmation.\n * Default: false\n */\n autoSubmit?: boolean;\n\n /**\n * Optional AI enrichment for richer tool descriptions.\n */\n enhance?: EnhancerConfig;\n\n /**\n * Per-form name/description overrides keyed by CSS selector.\n */\n overrides?: Record<string, FormOverride>;\n\n /**\n * Log registered tools to console on init. Default: false\n */\n debug?: boolean;\n}\n\nexport interface ResolvedConfig {\n exclude: string[];\n autoSubmit: boolean;\n enhance: EnhancerConfig | null;\n overrides: Record<string, FormOverride>;\n debug: boolean;\n}\n\nexport function resolveConfig(userConfig?: AutoWebMCPConfig): ResolvedConfig {\n return {\n exclude: userConfig?.exclude ?? [],\n autoSubmit: userConfig?.autoSubmit ?? false,\n enhance: userConfig?.enhance ?? null,\n overrides: userConfig?.overrides ?? {},\n debug: userConfig?.debug ?? false,\n };\n}\n", "/**\n * schema.ts \u2014 HTML input type \u2192 JSON Schema type mapping\n */\n\nexport interface JsonSchemaProperty {\n type: string;\n format?: string;\n description?: string;\n title?: string;\n enum?: string[];\n minimum?: number;\n maximum?: number;\n minLength?: number;\n maxLength?: number;\n pattern?: string;\n}\n\nexport interface JsonSchema {\n type: 'object';\n properties: Record<string, JsonSchemaProperty>;\n required: string[];\n}\n\n/** Maps an HTML <input type> to a JSON Schema property base */\nexport function inputTypeToSchema(\n input: HTMLInputElement | HTMLTextAreaElement | HTMLSelectElement,\n): JsonSchemaProperty | null {\n if (input instanceof HTMLInputElement) {\n return mapInputElement(input);\n }\n if (input instanceof HTMLTextAreaElement) {\n return { type: 'string' };\n }\n if (input instanceof HTMLSelectElement) {\n return mapSelectElement(input);\n }\n return null;\n}\n\nfunction mapInputElement(input: HTMLInputElement): JsonSchemaProperty | null {\n const type = input.type.toLowerCase();\n\n switch (type) {\n case 'text':\n case 'search':\n case 'tel':\n return buildStringSchema(input);\n\n case 'email':\n return { ...buildStringSchema(input), format: 'email' };\n\n case 'url':\n return { ...buildStringSchema(input), format: 'uri' };\n\n case 'number':\n case 'range': {\n const prop: JsonSchemaProperty = { type: 'number' };\n if (input.min !== '') prop.minimum = parseFloat(input.min);\n if (input.max !== '') prop.maximum = parseFloat(input.max);\n return prop;\n }\n\n case 'date':\n return { type: 'string', format: 'date' };\n\n case 'datetime-local':\n return { type: 'string', format: 'date-time' };\n\n case 'time':\n return { type: 'string', format: 'time' };\n\n case 'month':\n return { type: 'string', pattern: '^\\\\d{4}-\\\\d{2}$' };\n\n case 'week':\n return { type: 'string', pattern: '^\\\\d{4}-W\\\\d{2}$' };\n\n case 'color':\n return { type: 'string', pattern: '^#[0-9a-fA-F]{6}$' };\n\n case 'checkbox':\n return { type: 'boolean' };\n\n case 'radio':\n // Radio groups are handled at the form level in analyzer.ts\n return { type: 'string' };\n\n case 'file':\n case 'hidden':\n case 'submit':\n case 'reset':\n case 'button':\n case 'image':\n // These are not exposed to agents\n return null;\n\n case 'password':\n // Skip passwords \u2014 never expose to agents\n return null;\n\n default:\n return { type: 'string' };\n }\n}\n\nfunction buildStringSchema(input: HTMLInputElement): JsonSchemaProperty {\n const prop: JsonSchemaProperty = { type: 'string' };\n if (input.minLength > 0) prop.minLength = input.minLength;\n if (input.maxLength > 0 && input.maxLength !== 524288) prop.maxLength = input.maxLength;\n if (input.pattern) prop.pattern = input.pattern;\n return prop;\n}\n\nfunction mapSelectElement(select: HTMLSelectElement): JsonSchemaProperty {\n const options = Array.from(select.options)\n .filter((o) => o.value !== '')\n .map((o) => o.value);\n\n if (options.length === 0) {\n return { type: 'string' };\n }\n\n return {\n type: 'string',\n enum: options,\n };\n}\n\n/** Collect all radio button values for a given name within a form */\nexport function collectRadioEnum(form: HTMLFormElement, name: string): string[] {\n const radios = Array.from(\n form.querySelectorAll<HTMLInputElement>(`input[type=\"radio\"][name=\"${CSS.escape(name)}\"]`),\n );\n return radios.map((r) => r.value).filter((v) => v !== '');\n}\n", "/**\n * analyzer.ts \u2014 Infer tool name, description, and JSON Schema from form DOM\n */\n\nimport { JsonSchema, JsonSchemaProperty, inputTypeToSchema, collectRadioEnum } from './schema.js';\nimport { FormOverride } from './config.js';\n\nexport interface ToolMetadata {\n name: string;\n description: string;\n inputSchema: JsonSchema;\n}\n\n// Track form index for fallback naming\nlet formIndex = 0;\n\n/** Reset form index counter (useful in tests) */\nexport function resetFormIndex(): void {\n formIndex = 0;\n}\n\n/** Derive ToolMetadata from a <form> element */\nexport function analyzeForm(form: HTMLFormElement, override?: FormOverride): ToolMetadata {\n const name = override?.name ?? inferToolName(form);\n const description = override?.description ?? inferToolDescription(form);\n const inputSchema = buildSchema(form);\n\n return { name, description, inputSchema };\n}\n\n// ---------------------------------------------------------------------------\n// Tool name inference\n// ---------------------------------------------------------------------------\n\nfunction inferToolName(form: HTMLFormElement): string {\n // 1. Explicit data attribute\n const explicit = form.dataset['webmcpName'];\n if (explicit) return sanitizeName(explicit);\n\n // 2. Submit button text\n const submitText = getSubmitButtonText(form);\n if (submitText) return sanitizeName(submitText);\n\n // 3. Nearest heading above the form\n const heading = getNearestHeadingText(form);\n if (heading) return sanitizeName(heading);\n\n // 4. Form id or name attribute\n if (form.id) return sanitizeName(form.id);\n if (form.name) return sanitizeName(form.name);\n\n // 5. Form action URL path segment\n if (form.action) {\n const segment = getLastPathSegment(form.action);\n if (segment) return sanitizeName(segment);\n }\n\n // 6. Fallback\n return `form_${++formIndex}`;\n}\n\nfunction sanitizeName(raw: string): string {\n return raw\n .toLowerCase()\n .trim()\n .replace(/[^a-z0-9]+/g, '_')\n .replace(/^_+|_+$/g, '')\n .slice(0, 64) || 'form';\n}\n\nfunction getSubmitButtonText(form: HTMLFormElement): string {\n const buttons = [\n ...Array.from(form.querySelectorAll<HTMLButtonElement>('button[type=\"submit\"], button:not([type])')),\n ...Array.from(form.querySelectorAll<HTMLInputElement>('input[type=\"submit\"]')),\n ];\n\n for (const btn of buttons) {\n const text =\n btn instanceof HTMLInputElement\n ? btn.value.trim()\n : btn.textContent?.trim() ?? '';\n if (text && text.length > 0 && text.length < 80) return text;\n }\n return '';\n}\n\nfunction getNearestHeadingText(form: HTMLFormElement): string {\n // Walk up the DOM looking for a preceding sibling or parent heading\n let node: Element | null = form;\n while (node) {\n // Check preceding siblings\n let sibling = node.previousElementSibling;\n while (sibling) {\n if (/^H[1-3]$/i.test(sibling.tagName)) {\n const text = sibling.textContent?.trim() ?? '';\n if (text) return text;\n }\n sibling = sibling.previousElementSibling;\n }\n node = node.parentElement;\n // Stop at body\n if (!node || node === document.body) break;\n }\n return '';\n}\n\nfunction getLastPathSegment(url: string): string {\n try {\n const parsed = new URL(url, window.location.href);\n const segments = parsed.pathname.split('/').filter(Boolean);\n return segments[segments.length - 1] ?? '';\n } catch {\n return '';\n }\n}\n\n// ---------------------------------------------------------------------------\n// Tool description inference\n// ---------------------------------------------------------------------------\n\nfunction inferToolDescription(form: HTMLFormElement): string {\n // 1. Explicit data attribute\n const explicit = form.dataset['webmcpDescription'];\n if (explicit) return explicit.trim();\n\n // 2. <legend> inside the form\n const legend = form.querySelector('legend');\n if (legend?.textContent?.trim()) return legend.textContent.trim();\n\n // 3. aria-label on the form\n const ariaLabel = form.getAttribute('aria-label');\n if (ariaLabel?.trim()) return ariaLabel.trim();\n\n // 4. aria-describedby\n const describedById = form.getAttribute('aria-describedby');\n if (describedById) {\n const descEl = document.getElementById(describedById);\n if (descEl?.textContent?.trim()) return descEl.textContent.trim();\n }\n\n // 5. Combine nearest heading + page title\n const heading = getNearestHeadingText(form);\n const pageTitle = document.title?.trim();\n if (heading && pageTitle) return `${heading} \u2014 ${pageTitle}`;\n if (heading) return heading;\n if (pageTitle) return pageTitle;\n\n return 'Submit form';\n}\n\n// ---------------------------------------------------------------------------\n// JSON Schema construction\n// ---------------------------------------------------------------------------\n\nfunction buildSchema(form: HTMLFormElement): JsonSchema {\n const properties: Record<string, JsonSchemaProperty> = {};\n const required: string[] = [];\n\n // Track which radio group names we've already processed\n const processedRadioGroups = new Set<string>();\n\n const controls = Array.from(\n form.querySelectorAll<HTMLInputElement | HTMLTextAreaElement | HTMLSelectElement>(\n 'input, textarea, select',\n ),\n );\n\n for (const control of controls) {\n // Skip unnamed controls \u2014 can't be submitted\n const name = control.name;\n if (!name) continue;\n\n // Skip already-processed radio groups\n if (\n control instanceof HTMLInputElement &&\n control.type === 'radio'\n ) {\n if (processedRadioGroups.has(name)) continue;\n processedRadioGroups.add(name);\n }\n\n const schemaProp = inputTypeToSchema(control);\n if (!schemaProp) continue; // skipped types\n\n // Enrich with title and description\n schemaProp.title = inferFieldTitle(control);\n const desc = inferFieldDescription(control);\n if (desc) schemaProp.description = desc;\n\n // For radio groups, add enum values\n if (\n control instanceof HTMLInputElement &&\n control.type === 'radio'\n ) {\n schemaProp.enum = collectRadioEnum(form, name);\n }\n\n properties[name] = schemaProp;\n\n // Mark as required if the HTML attribute says so\n if (control.required) {\n required.push(name);\n }\n }\n\n return { type: 'object', properties, required };\n}\n\nfunction inferFieldTitle(\n control: HTMLInputElement | HTMLTextAreaElement | HTMLSelectElement,\n): string {\n // 1. data-webmcp-title\n if ('dataset' in control && (control as HTMLElement).dataset['webmcpTitle']) {\n return (control as HTMLElement).dataset['webmcpTitle']!;\n }\n\n // 2. Associated <label> text\n const labelText = getAssociatedLabelText(control);\n if (labelText) return labelText;\n\n // 3. name attribute (humanised)\n if (control.name) return humanizeName(control.name);\n\n // 4. id attribute (humanised)\n if (control.id) return humanizeName(control.id);\n\n return '';\n}\n\nfunction inferFieldDescription(\n control: HTMLInputElement | HTMLTextAreaElement | HTMLSelectElement,\n): string {\n // 1. data-webmcp-description\n const el = control as HTMLElement;\n if (el.dataset['webmcpDescription']) return el.dataset['webmcpDescription']!;\n\n // 2. aria-description or aria-describedby\n const ariaDesc = control.getAttribute('aria-description');\n if (ariaDesc) return ariaDesc;\n\n const describedById = control.getAttribute('aria-describedby');\n if (describedById) {\n const descEl = document.getElementById(describedById);\n if (descEl?.textContent?.trim()) return descEl.textContent.trim();\n }\n\n // 3. placeholder (only as a last resort \u2014 can be noisy)\n if (control instanceof HTMLInputElement || control instanceof HTMLTextAreaElement) {\n const ph = control.placeholder?.trim();\n if (ph && ph.length > 0) return ph;\n }\n\n // 4. Associated label text (if title didn't use it, use it for description)\n return '';\n}\n\nfunction getAssociatedLabelText(\n control: HTMLInputElement | HTMLTextAreaElement | HTMLSelectElement,\n): string {\n // 1. Labels collection (for/id association)\n if (control.id) {\n const label = document.querySelector<HTMLLabelElement>(`label[for=\"${CSS.escape(control.id)}\"]`);\n if (label) {\n const text = labelTextWithoutNested(label);\n if (text) return text;\n }\n }\n\n // 2. Wrapping <label>\n const parent = control.closest('label');\n if (parent) {\n const text = labelTextWithoutNested(parent);\n if (text) return text;\n }\n\n return '';\n}\n\nfunction labelTextWithoutNested(label: HTMLLabelElement): string {\n // Clone and remove any nested input/select/textarea before getting text\n const clone = label.cloneNode(true) as HTMLLabelElement;\n clone.querySelectorAll('input, select, textarea, button').forEach((el) => el.remove());\n return clone.textContent?.trim() ?? '';\n}\n\nfunction humanizeName(raw: string): string {\n return raw\n .replace(/[-_]/g, ' ')\n .replace(/([a-z])([A-Z])/g, '$1 $2')\n .trim()\n .replace(/\\b\\w/g, (c) => c.toUpperCase());\n}\n", "/**\n * discovery.ts \u2014 Form scanning & MutationObserver for SPA support\n */\n\nimport { ResolvedConfig } from './config.js';\nimport { analyzeForm } from './analyzer.js';\nimport { registerFormTool, unregisterFormTool } from './registry.js';\nimport { buildExecuteHandler } from './interceptor.js';\nimport { enrichMetadata } from './enhancer.js';\n\n// ---------------------------------------------------------------------------\n// Events\n// ---------------------------------------------------------------------------\n\nexport type FormLifecycleEvent = CustomEvent<{\n form: HTMLFormElement;\n toolName: string;\n}>;\n\nfunction emit(type: 'form:registered' | 'form:unregistered', form: HTMLFormElement, toolName: string): void {\n window.dispatchEvent(\n new CustomEvent(type, { detail: { form, toolName } }) as FormLifecycleEvent,\n );\n}\n\n// ---------------------------------------------------------------------------\n// Registration helpers\n// ---------------------------------------------------------------------------\n\n/** Check whether a form should be excluded per config */\nfunction isExcluded(form: HTMLFormElement, config: ResolvedConfig): boolean {\n // Skip forms that already have explicit WebMCP attributes (browser handles)\n if (form.hasAttribute('toolname')) return true;\n // Skip forms with data-no-webmcp\n if (form.dataset['noWebmcp'] !== undefined) return true;\n // Skip per config exclude list\n for (const selector of config.exclude) {\n try {\n if (form.matches(selector)) return true;\n } catch {\n // invalid selector \u2014 ignore\n }\n }\n return false;\n}\n\nasync function registerForm(form: HTMLFormElement, config: ResolvedConfig): Promise<void> {\n if (isExcluded(form, config)) return;\n\n // Find matching override (first matching selector wins)\n let override;\n for (const [selector, ovr] of Object.entries(config.overrides)) {\n try {\n if (form.matches(selector)) {\n override = ovr;\n break;\n }\n } catch {\n // invalid selector\n }\n }\n\n let metadata = analyzeForm(form, override);\n if (config.enhance) {\n if (config.debug) console.debug(`[auto-webmcp] Enriching: ${metadata.name}\u2026`);\n metadata = await enrichMetadata(metadata, config.enhance);\n }\n const execute = buildExecuteHandler(form, config);\n\n await registerFormTool(form, metadata, execute);\n\n if (config.debug) {\n console.debug(`[auto-webmcp] Registered: ${metadata.name}`, metadata);\n }\n\n emit('form:registered', form, metadata.name);\n}\n\nasync function unregisterForm(form: HTMLFormElement, config: ResolvedConfig): Promise<void> {\n const { getRegisteredToolName } = await import('./registry.js');\n const name = getRegisteredToolName(form);\n if (!name) return;\n\n await unregisterFormTool(form);\n\n if (config.debug) {\n console.debug(`[auto-webmcp] Unregistered: ${name}`);\n }\n\n emit('form:unregistered', form, name);\n}\n\n// ---------------------------------------------------------------------------\n// MutationObserver\n// ---------------------------------------------------------------------------\n\nlet observer: MutationObserver | null = null;\n\nfunction startObserver(config: ResolvedConfig): void {\n if (observer) return;\n\n observer = new MutationObserver((mutations) => {\n for (const mutation of mutations) {\n for (const node of mutation.addedNodes) {\n if (!(node instanceof Element)) continue;\n\n const forms = node instanceof HTMLFormElement\n ? [node]\n : Array.from(node.querySelectorAll<HTMLFormElement>('form'));\n\n for (const form of forms) {\n void registerForm(form, config);\n }\n }\n\n for (const node of mutation.removedNodes) {\n if (!(node instanceof Element)) continue;\n\n const forms = node instanceof HTMLFormElement\n ? [node]\n : Array.from(node.querySelectorAll<HTMLFormElement>('form'));\n\n for (const form of forms) {\n void unregisterForm(form, config);\n }\n }\n }\n });\n\n observer.observe(document.body, { childList: true, subtree: true });\n}\n\n// ---------------------------------------------------------------------------\n// SPA route change support\n// ---------------------------------------------------------------------------\n\nfunction listenForRouteChanges(config: ResolvedConfig): void {\n // Hash changes\n window.addEventListener('hashchange', () => scanForms(config));\n\n // History API (pushState / replaceState)\n const original = {\n pushState: history.pushState.bind(history),\n replaceState: history.replaceState.bind(history),\n };\n\n history.pushState = function (...args) {\n original.pushState(...args);\n scanForms(config);\n };\n\n history.replaceState = function (...args) {\n original.replaceState(...args);\n scanForms(config);\n };\n\n window.addEventListener('popstate', () => scanForms(config));\n}\n\n// ---------------------------------------------------------------------------\n// Main scan\n// ---------------------------------------------------------------------------\n\nasync function scanForms(config: ResolvedConfig): Promise<void> {\n const forms = Array.from(document.querySelectorAll<HTMLFormElement>('form'));\n await Promise.all(forms.map((form) => registerForm(form, config)));\n}\n\n// ---------------------------------------------------------------------------\n// Public API\n// ---------------------------------------------------------------------------\n\nexport async function startDiscovery(config: ResolvedConfig): Promise<void> {\n if (document.readyState === 'loading') {\n await new Promise<void>((resolve) =>\n document.addEventListener('DOMContentLoaded', () => resolve(), { once: true }),\n );\n }\n\n await scanForms(config);\n startObserver(config);\n listenForRouteChanges(config);\n}\n\nexport function stopDiscovery(): void {\n observer?.disconnect();\n observer = null;\n}\n", "/**\n * interceptor.ts \u2014 Form submit interception for agent-invoked submissions\n *\n * WebMCP's `execute` callback receives form parameters and is expected to\n * return a result. This module bridges the gap: it fills form fields with\n * the agent-supplied values, submits the form, and resolves the execute\n * promise with a structured response.\n */\n\nimport { ResolvedConfig } from './config.js';\n\n// ---------------------------------------------------------------------------\n// Extended SubmitEvent types (WebMCP additions)\n// ---------------------------------------------------------------------------\n\ndeclare global {\n interface SubmitEvent {\n /** True when the form was submitted by an AI agent via WebMCP */\n agentInvoked?: boolean;\n /** Call to return a structured result to the agent */\n respondWith?: (promise: Promise<unknown>) => void;\n }\n}\n\nexport interface ExecuteResult {\n success: boolean;\n data?: Record<string, unknown>;\n url?: string;\n error?: string;\n}\n\ntype Resolver = (result: ExecuteResult) => void;\ntype Rejecter = (error: Error) => void;\n\n/** Per-form pending execute promises */\nconst pendingExecutions = new WeakMap<\n HTMLFormElement,\n { resolve: Resolver; reject: Rejecter }\n>();\n\n/**\n * Build an `execute` function for a form tool.\n *\n * When the agent calls execute(params):\n * 1. Fills form fields with the supplied params\n * 2. Fires a submit event (or auto-submits if configured)\n * 3. Resolves with structured form data once submitted\n */\nexport function buildExecuteHandler(\n form: HTMLFormElement,\n config: ResolvedConfig,\n): (params: Record<string, unknown>) => Promise<ExecuteResult> {\n // Attach submit listener once per form\n attachSubmitInterceptor(form);\n\n return async (params: Record<string, unknown>): Promise<ExecuteResult> => {\n fillFormFields(form, params);\n\n return new Promise<ExecuteResult>((resolve, reject) => {\n pendingExecutions.set(form, { resolve, reject });\n\n if (config.autoSubmit || form.dataset['webmcpAutosubmit'] !== undefined) {\n // Programmatically submit\n form.requestSubmit();\n }\n // Otherwise: the form stays filled; human clicks submit,\n // which fires the submit event interceptor below.\n });\n };\n}\n\nfunction attachSubmitInterceptor(form: HTMLFormElement): void {\n // Guard against attaching multiple times\n if ((form as unknown as Record<string, unknown>)['__awmcp_intercepted']) return;\n (form as unknown as Record<string, unknown>)['__awmcp_intercepted'] = true;\n\n form.addEventListener('submit', (e: SubmitEvent) => {\n const pending = pendingExecutions.get(form);\n if (!pending) return; // Normal human submission \u2014 do nothing\n\n // Agent-invoked path\n const { resolve } = pending;\n pendingExecutions.delete(form);\n\n const formData = serializeFormData(form);\n\n if (e.agentInvoked && typeof e.respondWith === 'function') {\n // Native WebMCP path: use respondWith to return to browser\n e.preventDefault();\n e.respondWith(\n Promise.resolve({\n success: true,\n data: formData,\n }),\n );\n resolve({ success: true, data: formData });\n } else {\n // Fallback path: let form submit normally, resolve with data + target URL\n const targetUrl = resolveFormAction(form);\n resolve({ success: true, data: formData, url: targetUrl });\n }\n });\n}\n\n// ---------------------------------------------------------------------------\n// Field filling\n// ---------------------------------------------------------------------------\n\nfunction fillFormFields(form: HTMLFormElement, params: Record<string, unknown>): void {\n for (const [name, value] of Object.entries(params)) {\n const escapedName = CSS.escape(name);\n\n // Try input, textarea, select with this name\n const input = form.querySelector<HTMLInputElement | HTMLTextAreaElement | HTMLSelectElement>(\n `[name=\"${escapedName}\"]`,\n );\n\n if (!input) continue;\n\n if (input instanceof HTMLInputElement) {\n fillInput(input, form, name, value);\n } else if (input instanceof HTMLTextAreaElement) {\n input.value = String(value ?? '');\n input.dispatchEvent(new Event('input', { bubbles: true }));\n input.dispatchEvent(new Event('change', { bubbles: true }));\n } else if (input instanceof HTMLSelectElement) {\n input.value = String(value ?? '');\n input.dispatchEvent(new Event('change', { bubbles: true }));\n }\n }\n}\n\nfunction fillInput(\n input: HTMLInputElement,\n form: HTMLFormElement,\n name: string,\n value: unknown,\n): void {\n const type = input.type.toLowerCase();\n\n if (type === 'checkbox') {\n input.checked = Boolean(value);\n input.dispatchEvent(new Event('change', { bubbles: true }));\n return;\n }\n\n if (type === 'radio') {\n const escapedName = CSS.escape(name);\n const radios = form.querySelectorAll<HTMLInputElement>(\n `input[type=\"radio\"][name=\"${escapedName}\"]`,\n );\n for (const radio of radios) {\n if (radio.value === String(value)) {\n radio.checked = true;\n radio.dispatchEvent(new Event('change', { bubbles: true }));\n break;\n }\n }\n return;\n }\n\n input.value = String(value ?? '');\n input.dispatchEvent(new Event('input', { bubbles: true }));\n input.dispatchEvent(new Event('change', { bubbles: true }));\n}\n\n// ---------------------------------------------------------------------------\n// Serialization\n// ---------------------------------------------------------------------------\n\nfunction serializeFormData(form: HTMLFormElement): Record<string, unknown> {\n const result: Record<string, unknown> = {};\n const data = new FormData(form);\n\n for (const [key, val] of data.entries()) {\n if (result[key] !== undefined) {\n // Multiple values \u2192 array\n const existing = result[key];\n if (Array.isArray(existing)) {\n existing.push(val);\n } else {\n result[key] = [existing, val];\n }\n } else {\n result[key] = val;\n }\n }\n\n return result;\n}\n\nfunction resolveFormAction(form: HTMLFormElement): string {\n if (form.action) {\n try {\n return new URL(form.action, window.location.href).href;\n } catch {\n // ignore\n }\n }\n return window.location.href;\n}\n", "/**\n * enhancer.ts \u2014 Optional LLM-based description enrichment\n *\n * Calls a small LLM to generate richer tool descriptions than heuristics\n * alone can provide. Activated only when config.enhance is set.\n */\n\nimport { ToolMetadata } from './analyzer.js';\nimport { EnhancerConfig } from './config.js';\n\nexport async function enrichMetadata(\n metadata: ToolMetadata,\n enhancer: EnhancerConfig,\n): Promise<ToolMetadata> {\n try {\n const enriched = await callLLM(metadata, enhancer);\n return { ...metadata, description: enriched };\n } catch (err) {\n // Enhancement is optional \u2014 fall back to heuristic description\n console.warn('[auto-webmcp] Enrichment failed, using heuristic description:', err);\n return metadata;\n }\n}\n\nasync function callLLM(metadata: ToolMetadata, config: EnhancerConfig): Promise<string> {\n const prompt = buildPrompt(metadata);\n\n if (config.provider === 'claude') {\n return callClaude(prompt, config);\n } else {\n return callGemini(prompt, config);\n }\n}\n\nfunction buildPrompt(metadata: ToolMetadata): string {\n const fields = Object.entries(metadata.inputSchema.properties)\n .map(([name, prop]) => `- ${prop.title ?? name} (${prop.type}): ${prop.description ?? ''}`)\n .join('\\n');\n\n return `You are helping describe a web form as an AI tool. Given this form information:\n\nName: ${metadata.name}\nCurrent description: ${metadata.description}\nFields:\n${fields}\n\nWrite a concise (1-2 sentence) description of what this tool does and when an AI agent should use it. Be specific and actionable. Respond with only the description, no preamble.`;\n}\n\nasync function callClaude(prompt: string, config: EnhancerConfig): Promise<string> {\n const model = config.model ?? 'claude-haiku-4-5-20251001';\n\n const response = await fetch('https://api.anthropic.com/v1/messages', {\n method: 'POST',\n headers: {\n 'x-api-key': config.apiKey,\n 'anthropic-version': '2023-06-01',\n 'content-type': 'application/json',\n },\n body: JSON.stringify({\n model,\n max_tokens: 150,\n messages: [{ role: 'user', content: prompt }],\n }),\n });\n\n if (!response.ok) {\n throw new Error(`Claude API error: ${response.status}`);\n }\n\n const data = await response.json() as {\n content: Array<{ type: string; text: string }>;\n };\n\n return data.content\n .filter((block) => block.type === 'text')\n .map((block) => block.text)\n .join('')\n .trim();\n}\n\nasync function callGemini(prompt: string, config: EnhancerConfig): Promise<string> {\n const model = config.model ?? 'gemini-1.5-flash';\n const url = `https://generativelanguage.googleapis.com/v1beta/models/${model}:generateContent?key=${config.apiKey}`;\n\n const response = await fetch(url, {\n method: 'POST',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify({\n contents: [{ parts: [{ text: prompt }] }],\n generationConfig: { maxOutputTokens: 150, temperature: 0.2 },\n }),\n });\n\n if (!response.ok) {\n throw new Error(`Gemini API error: ${response.status}`);\n }\n\n const data = await response.json() as {\n candidates: Array<{\n content: { parts: Array<{ text: string }> };\n }>;\n };\n\n return data.candidates[0]?.content.parts.map((p) => p.text).join('').trim() ?? '';\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["/**\n * registry.ts \u2014 Wrapper around navigator.modelContext WebMCP Imperative API\n */\n\nimport { ToolMetadata } from './analyzer.js';\n\n// ---------------------------------------------------------------------------\n// WebMCP type declarations (not yet in TypeScript DOM lib)\n// ---------------------------------------------------------------------------\n\nexport interface WebMCPTool {\n name: string;\n description: string;\n inputSchema: object;\n execute: (params: Record<string, unknown>) => Promise<unknown>;\n}\n\ndeclare global {\n interface Navigator {\n modelContext?: {\n registerTool(tool: WebMCPTool): Promise<void>;\n unregisterTool(name: string): Promise<void>;\n };\n }\n}\n\n// ---------------------------------------------------------------------------\n// Registry\n// ---------------------------------------------------------------------------\n\n/** Tracks registered tools: form element \u2192 tool name */\nconst registeredTools = new Map<HTMLFormElement, string>();\n\n/** True if the browser supports navigator.modelContext */\nexport function isWebMCPSupported(): boolean {\n return typeof navigator !== 'undefined' && typeof navigator.modelContext !== 'undefined';\n}\n\n/**\n * Register a form as a WebMCP tool.\n * Silently no-ops if WebMCP is not supported.\n */\nexport async function registerFormTool(\n form: HTMLFormElement,\n metadata: ToolMetadata,\n execute: (params: Record<string, unknown>) => Promise<unknown>,\n): Promise<void> {\n if (!isWebMCPSupported()) return;\n\n // Unregister any previously-registered tool for this same form element\n const existing = registeredTools.get(form);\n if (existing) {\n await unregisterFormTool(form);\n }\n\n await navigator.modelContext!.registerTool({\n name: metadata.name,\n description: metadata.description,\n inputSchema: metadata.inputSchema,\n execute,\n });\n\n registeredTools.set(form, metadata.name);\n}\n\n/**\n * Unregister the WebMCP tool associated with a form element.\n * Silently no-ops if not registered or WebMCP not supported.\n */\nexport async function unregisterFormTool(form: HTMLFormElement): Promise<void> {\n if (!isWebMCPSupported()) return;\n\n const name = registeredTools.get(form);\n if (!name) return;\n\n try {\n await navigator.modelContext!.unregisterTool(name);\n } catch {\n // Tool may have already been removed \u2014 ignore\n }\n\n registeredTools.delete(form);\n}\n\n/** Get the registered tool name for a form, if any */\nexport function getRegisteredToolName(form: HTMLFormElement): string | undefined {\n return registeredTools.get(form);\n}\n\n/** Return a snapshot of all currently registered form\u2192name pairs */\nexport function getAllRegisteredTools(): Array<{ form: HTMLFormElement; name: string }> {\n return Array.from(registeredTools.entries()).map(([form, name]) => ({ form, name }));\n}\n\n/** Unregister all tools (e.g. on teardown) */\nexport async function unregisterAll(): Promise<void> {\n const entries = Array.from(registeredTools.entries());\n await Promise.all(entries.map(([form]) => unregisterFormTool(form)));\n}\n", "/**\n * index.ts \u2014 Entry point & public API for auto-webmcp\n *\n * Zero-config drop-in:\n * <script src=\"auto-webmcp.iife.js\"></script>\n *\n * ESM usage:\n * import { autoWebMCP } from 'auto-webmcp';\n * autoWebMCP({ exclude: ['#login-form'] });\n */\n\nimport { AutoWebMCPConfig, resolveConfig } from './config.js';\nimport { startDiscovery, stopDiscovery } from './discovery.js';\nimport { unregisterAll, getAllRegisteredTools, isWebMCPSupported } from './registry.js';\n\nexport type { AutoWebMCPConfig } from './config.js';\nexport type { ToolMetadata } from './analyzer.js';\nexport type { JsonSchema, JsonSchemaProperty } from './schema.js';\n\nexport interface AutoWebMCPHandle {\n /** Stop observing and unregister all tools */\n destroy: () => Promise<void>;\n /** Return all currently registered tools */\n getTools: () => Array<{ form: HTMLFormElement; name: string }>;\n /** True if running in a WebMCP-capable browser */\n isSupported: boolean;\n}\n\n/**\n * Initialize auto-webmcp.\n *\n * @param config \u2014 Optional configuration (all fields optional)\n * @returns A handle to inspect or tear down the instance\n */\nexport async function autoWebMCP(config?: AutoWebMCPConfig): Promise<AutoWebMCPHandle> {\n const resolved = resolveConfig(config);\n\n if (resolved.debug) {\n console.debug('[auto-webmcp] Initializing', {\n webmcpSupported: isWebMCPSupported(),\n config: resolved,\n });\n }\n\n await startDiscovery(resolved);\n\n return {\n destroy: async () => {\n stopDiscovery();\n await unregisterAll();\n },\n getTools: getAllRegisteredTools,\n isSupported: isWebMCPSupported(),\n };\n}\n\n// ---------------------------------------------------------------------------\n// Auto-init for IIFE / script-tag usage\n// ---------------------------------------------------------------------------\n\n// When loaded as a <script> tag, auto-initialize with zero config.\n// Users can prevent this by setting window.__AUTO_WEBMCP_NO_AUTOINIT = true\n// before the script loads.\n\nif (\n typeof window !== 'undefined' &&\n !(window as unknown as Record<string, unknown>)['__AUTO_WEBMCP_NO_AUTOINIT']\n) {\n void autoWebMCP();\n}\n", "/**\n * config.ts \u2014 User configuration merging & defaults\n */\n\nexport interface EnhancerConfig {\n provider: 'gemini' | 'claude';\n apiKey: string;\n model?: string;\n}\n\nexport interface FormOverride {\n name?: string;\n description?: string;\n}\n\nexport interface AutoWebMCPConfig {\n /**\n * CSS selectors for forms to skip. E.g. ['#login-form', '[data-no-webmcp]']\n */\n exclude?: string[];\n\n /**\n * If true, agent-invoked forms are auto-submitted without human confirmation.\n * Default: false\n */\n autoSubmit?: boolean;\n\n /**\n * Optional AI enrichment for richer tool descriptions.\n */\n enhance?: EnhancerConfig;\n\n /**\n * Per-form name/description overrides keyed by CSS selector.\n */\n overrides?: Record<string, FormOverride>;\n\n /**\n * Log registered tools to console on init. Default: false\n */\n debug?: boolean;\n}\n\nexport interface ResolvedConfig {\n exclude: string[];\n autoSubmit: boolean;\n enhance: EnhancerConfig | null;\n overrides: Record<string, FormOverride>;\n debug: boolean;\n}\n\nexport function resolveConfig(userConfig?: AutoWebMCPConfig): ResolvedConfig {\n return {\n exclude: userConfig?.exclude ?? [],\n autoSubmit: userConfig?.autoSubmit ?? false,\n enhance: userConfig?.enhance ?? null,\n overrides: userConfig?.overrides ?? {},\n debug: userConfig?.debug ?? false,\n };\n}\n", "/**\n * schema.ts \u2014 HTML input type \u2192 JSON Schema type mapping\n */\n\nexport interface JsonSchemaProperty {\n type: string;\n format?: string;\n description?: string;\n title?: string;\n enum?: string[];\n oneOf?: Array<{ const: string; title: string }>;\n minimum?: number;\n maximum?: number;\n minLength?: number;\n maxLength?: number;\n pattern?: string;\n}\n\nexport interface JsonSchema {\n type: 'object';\n properties: Record<string, JsonSchemaProperty>;\n required: string[];\n}\n\n/** Maps an HTML <input type> to a JSON Schema property base */\nexport function inputTypeToSchema(\n input: HTMLInputElement | HTMLTextAreaElement | HTMLSelectElement,\n): JsonSchemaProperty | null {\n if (input instanceof HTMLInputElement) {\n return mapInputElement(input);\n }\n if (input instanceof HTMLTextAreaElement) {\n return { type: 'string' };\n }\n if (input instanceof HTMLSelectElement) {\n return mapSelectElement(input);\n }\n return null;\n}\n\nfunction mapInputElement(input: HTMLInputElement): JsonSchemaProperty | null {\n const type = input.type.toLowerCase();\n\n switch (type) {\n case 'text':\n case 'search':\n case 'tel':\n return buildStringSchema(input);\n\n case 'email':\n return { ...buildStringSchema(input), format: 'email' };\n\n case 'url':\n return { ...buildStringSchema(input), format: 'uri' };\n\n case 'number':\n case 'range': {\n const prop: JsonSchemaProperty = { type: 'number' };\n if (input.min !== '') prop.minimum = parseFloat(input.min);\n if (input.max !== '') prop.maximum = parseFloat(input.max);\n return prop;\n }\n\n case 'date':\n return { type: 'string', format: 'date' };\n\n case 'datetime-local':\n return { type: 'string', format: 'date-time' };\n\n case 'time':\n return { type: 'string', format: 'time' };\n\n case 'month':\n return { type: 'string', pattern: '^\\\\d{4}-\\\\d{2}$' };\n\n case 'week':\n return { type: 'string', pattern: '^\\\\d{4}-W\\\\d{2}$' };\n\n case 'color':\n return { type: 'string', pattern: '^#[0-9a-fA-F]{6}$' };\n\n case 'checkbox':\n return { type: 'boolean' };\n\n case 'radio':\n // Radio groups are handled at the form level in analyzer.ts\n return { type: 'string' };\n\n case 'file':\n case 'hidden':\n case 'submit':\n case 'reset':\n case 'button':\n case 'image':\n // These are not exposed to agents\n return null;\n\n case 'password':\n // Skip passwords \u2014 never expose to agents\n return null;\n\n default:\n return { type: 'string' };\n }\n}\n\nfunction buildStringSchema(input: HTMLInputElement): JsonSchemaProperty {\n const prop: JsonSchemaProperty = { type: 'string' };\n if (input.minLength > 0) prop.minLength = input.minLength;\n if (input.maxLength > 0 && input.maxLength !== 524288) prop.maxLength = input.maxLength;\n if (input.pattern) prop.pattern = input.pattern;\n return prop;\n}\n\nfunction mapSelectElement(select: HTMLSelectElement): JsonSchemaProperty {\n const filtered = Array.from(select.options).filter((o) => o.value !== '');\n\n if (filtered.length === 0) {\n return { type: 'string' };\n }\n\n const enumValues = filtered.map((o) => o.value);\n const oneOf = filtered.map((o) => ({ const: o.value, title: o.text.trim() || o.value }));\n\n return { type: 'string', enum: enumValues, oneOf };\n}\n\n/** Collect all radio button values for a given name within a form */\nexport function collectRadioEnum(form: HTMLFormElement, name: string): string[] {\n const radios = Array.from(\n form.querySelectorAll<HTMLInputElement>(`input[type=\"radio\"][name=\"${CSS.escape(name)}\"]`),\n );\n return radios.map((r) => r.value).filter((v) => v !== '');\n}\n\n/** Collect radio button values + label titles as oneOf entries */\nexport function collectRadioOneOf(\n form: HTMLFormElement,\n name: string,\n): Array<{ const: string; title: string }> {\n const radios = Array.from(\n form.querySelectorAll<HTMLInputElement>(`input[type=\"radio\"][name=\"${CSS.escape(name)}\"]`),\n ).filter((r) => r.value !== '');\n\n return radios.map((r) => {\n const title = getRadioLabelText(r);\n return { const: r.value, title: title || r.value };\n });\n}\n\nfunction getRadioLabelText(radio: HTMLInputElement): string {\n // 1. Wrapping label\n const parent = radio.closest('label');\n if (parent) {\n const clone = parent.cloneNode(true) as HTMLLabelElement;\n clone.querySelectorAll('input, select, textarea, button').forEach((el) => el.remove());\n const text = clone.textContent?.trim() ?? '';\n if (text) return text;\n }\n // 2. Label pointing to radio by id\n if (radio.id) {\n const label = document.querySelector<HTMLLabelElement>(`label[for=\"${CSS.escape(radio.id)}\"]`);\n if (label) {\n const text = label.textContent?.trim() ?? '';\n if (text) return text;\n }\n }\n return '';\n}\n", "/**\n * analyzer.ts \u2014 Infer tool name, description, and JSON Schema from form DOM\n */\n\nimport { JsonSchema, JsonSchemaProperty, inputTypeToSchema, collectRadioEnum, collectRadioOneOf } from './schema.js';\nimport { FormOverride } from './config.js';\n\nexport interface ToolMetadata {\n name: string;\n description: string;\n inputSchema: JsonSchema;\n}\n\n// Track form index for fallback naming\nlet formIndex = 0;\n\n/** Reset form index counter (useful in tests) */\nexport function resetFormIndex(): void {\n formIndex = 0;\n}\n\n/** Derive ToolMetadata from a <form> element */\nexport function analyzeForm(form: HTMLFormElement, override?: FormOverride): ToolMetadata {\n const name = override?.name ?? inferToolName(form);\n const description = override?.description ?? inferToolDescription(form);\n const inputSchema = buildSchema(form);\n\n return { name, description, inputSchema };\n}\n\n// ---------------------------------------------------------------------------\n// Tool name inference\n// ---------------------------------------------------------------------------\n\nfunction inferToolName(form: HTMLFormElement): string {\n // 1. Native toolname attribute (spec)\n const nativeName = form.getAttribute('toolname');\n if (nativeName) return sanitizeName(nativeName);\n\n // 2. Explicit data attribute\n const explicit = form.dataset['webmcpName'];\n if (explicit) return sanitizeName(explicit);\n\n // 2. Submit button text\n const submitText = getSubmitButtonText(form);\n if (submitText) return sanitizeName(submitText);\n\n // 3. Nearest heading above the form\n const heading = getNearestHeadingText(form);\n if (heading) return sanitizeName(heading);\n\n // 4. Form id or name attribute\n if (form.id) return sanitizeName(form.id);\n if (form.name) return sanitizeName(form.name);\n\n // 5. Form action URL path segment\n if (form.action) {\n const segment = getLastPathSegment(form.action);\n if (segment) return sanitizeName(segment);\n }\n\n // 6. Fallback\n return `form_${++formIndex}`;\n}\n\nfunction sanitizeName(raw: string): string {\n return raw\n .toLowerCase()\n .trim()\n .replace(/[^a-z0-9]+/g, '_')\n .replace(/^_+|_+$/g, '')\n .slice(0, 64) || 'form';\n}\n\nfunction getSubmitButtonText(form: HTMLFormElement): string {\n const buttons = [\n ...Array.from(form.querySelectorAll<HTMLButtonElement>('button[type=\"submit\"], button:not([type])')),\n ...Array.from(form.querySelectorAll<HTMLInputElement>('input[type=\"submit\"]')),\n ];\n\n for (const btn of buttons) {\n const text =\n btn instanceof HTMLInputElement\n ? btn.value.trim()\n : btn.textContent?.trim() ?? '';\n if (text && text.length > 0 && text.length < 80) return text;\n }\n return '';\n}\n\nfunction getNearestHeadingText(form: HTMLFormElement): string {\n // Walk up the DOM looking for a preceding sibling or parent heading\n let node: Element | null = form;\n while (node) {\n // Check preceding siblings\n let sibling = node.previousElementSibling;\n while (sibling) {\n if (/^H[1-3]$/i.test(sibling.tagName)) {\n const text = sibling.textContent?.trim() ?? '';\n if (text) return text;\n }\n sibling = sibling.previousElementSibling;\n }\n node = node.parentElement;\n // Stop at body\n if (!node || node === document.body) break;\n }\n return '';\n}\n\nfunction getLastPathSegment(url: string): string {\n try {\n const parsed = new URL(url, window.location.href);\n const segments = parsed.pathname.split('/').filter(Boolean);\n return segments[segments.length - 1] ?? '';\n } catch {\n return '';\n }\n}\n\n// ---------------------------------------------------------------------------\n// Tool description inference\n// ---------------------------------------------------------------------------\n\nfunction inferToolDescription(form: HTMLFormElement): string {\n // 1. Native tooldescription attribute (spec)\n const nativeDesc = form.getAttribute('tooldescription');\n if (nativeDesc) return nativeDesc.trim();\n\n // 2. Explicit data attribute\n const explicit = form.dataset['webmcpDescription'];\n if (explicit) return explicit.trim();\n\n // 2. <legend> inside the form\n const legend = form.querySelector('legend');\n if (legend?.textContent?.trim()) return legend.textContent.trim();\n\n // 3. aria-label on the form\n const ariaLabel = form.getAttribute('aria-label');\n if (ariaLabel?.trim()) return ariaLabel.trim();\n\n // 4. aria-describedby\n const describedById = form.getAttribute('aria-describedby');\n if (describedById) {\n const descEl = document.getElementById(describedById);\n if (descEl?.textContent?.trim()) return descEl.textContent.trim();\n }\n\n // 5. Combine nearest heading + page title\n const heading = getNearestHeadingText(form);\n const pageTitle = document.title?.trim();\n if (heading && pageTitle) return `${heading} \u2014 ${pageTitle}`;\n if (heading) return heading;\n if (pageTitle) return pageTitle;\n\n return 'Submit form';\n}\n\n// ---------------------------------------------------------------------------\n// JSON Schema construction\n// ---------------------------------------------------------------------------\n\nfunction buildSchema(form: HTMLFormElement): JsonSchema {\n const properties: Record<string, JsonSchemaProperty> = {};\n const required: string[] = [];\n\n // Track which radio group names we've already processed\n const processedRadioGroups = new Set<string>();\n\n const controls = Array.from(\n form.querySelectorAll<HTMLInputElement | HTMLTextAreaElement | HTMLSelectElement>(\n 'input, textarea, select',\n ),\n );\n\n for (const control of controls) {\n // Skip unnamed controls \u2014 can't be submitted\n const name = control.name;\n if (!name) continue;\n\n // Skip already-processed radio groups\n if (\n control instanceof HTMLInputElement &&\n control.type === 'radio'\n ) {\n if (processedRadioGroups.has(name)) continue;\n processedRadioGroups.add(name);\n }\n\n const schemaProp = inputTypeToSchema(control);\n if (!schemaProp) continue; // skipped types\n\n // Enrich with title and description\n schemaProp.title = inferFieldTitle(control);\n const desc = inferFieldDescription(control);\n if (desc) schemaProp.description = desc;\n\n // For radio groups, add enum and oneOf values\n if (\n control instanceof HTMLInputElement &&\n control.type === 'radio'\n ) {\n schemaProp.enum = collectRadioEnum(form, name);\n const radioOneOf = collectRadioOneOf(form, name);\n if (radioOneOf.length > 0) schemaProp.oneOf = radioOneOf;\n }\n\n properties[name] = schemaProp;\n\n // Mark as required if the HTML attribute says so\n if (control.required) {\n required.push(name);\n }\n }\n\n return { type: 'object', properties, required };\n}\n\nfunction inferFieldTitle(\n control: HTMLInputElement | HTMLTextAreaElement | HTMLSelectElement,\n): string {\n // 1. data-webmcp-title\n if ('dataset' in control && (control as HTMLElement).dataset['webmcpTitle']) {\n return (control as HTMLElement).dataset['webmcpTitle']!;\n }\n\n // 2. Associated <label> text\n const labelText = getAssociatedLabelText(control);\n if (labelText) return labelText;\n\n // 3. name attribute (humanised)\n if (control.name) return humanizeName(control.name);\n\n // 4. id attribute (humanised)\n if (control.id) return humanizeName(control.id);\n\n return '';\n}\n\nfunction inferFieldDescription(\n control: HTMLInputElement | HTMLTextAreaElement | HTMLSelectElement,\n): string {\n // 1. Native toolparamdescription attribute (spec)\n const nativeParamDesc = control.getAttribute('toolparamdescription');\n if (nativeParamDesc) return nativeParamDesc.trim();\n\n // 2. data-webmcp-description\n const el = control as HTMLElement;\n if (el.dataset['webmcpDescription']) return el.dataset['webmcpDescription']!;\n\n // 2. aria-description or aria-describedby\n const ariaDesc = control.getAttribute('aria-description');\n if (ariaDesc) return ariaDesc;\n\n const describedById = control.getAttribute('aria-describedby');\n if (describedById) {\n const descEl = document.getElementById(describedById);\n if (descEl?.textContent?.trim()) return descEl.textContent.trim();\n }\n\n // 3. placeholder (only as a last resort \u2014 can be noisy)\n if (control instanceof HTMLInputElement || control instanceof HTMLTextAreaElement) {\n const ph = control.placeholder?.trim();\n if (ph && ph.length > 0) return ph;\n }\n\n // 4. Associated label text (if title didn't use it, use it for description)\n return '';\n}\n\nfunction getAssociatedLabelText(\n control: HTMLInputElement | HTMLTextAreaElement | HTMLSelectElement,\n): string {\n // 1. Labels collection (for/id association)\n if (control.id) {\n const label = document.querySelector<HTMLLabelElement>(`label[for=\"${CSS.escape(control.id)}\"]`);\n if (label) {\n const text = labelTextWithoutNested(label);\n if (text) return text;\n }\n }\n\n // 2. Wrapping <label>\n const parent = control.closest('label');\n if (parent) {\n const text = labelTextWithoutNested(parent);\n if (text) return text;\n }\n\n return '';\n}\n\nfunction labelTextWithoutNested(label: HTMLLabelElement): string {\n // Clone and remove any nested input/select/textarea before getting text\n const clone = label.cloneNode(true) as HTMLLabelElement;\n clone.querySelectorAll('input, select, textarea, button').forEach((el) => el.remove());\n return clone.textContent?.trim() ?? '';\n}\n\nfunction humanizeName(raw: string): string {\n return raw\n .replace(/[-_]/g, ' ')\n .replace(/([a-z])([A-Z])/g, '$1 $2')\n .trim()\n .replace(/\\b\\w/g, (c) => c.toUpperCase());\n}\n", "/**\n * discovery.ts \u2014 Form scanning & MutationObserver for SPA support\n */\n\nimport { ResolvedConfig } from './config.js';\nimport { analyzeForm } from './analyzer.js';\nimport { registerFormTool, unregisterFormTool } from './registry.js';\nimport { buildExecuteHandler } from './interceptor.js';\nimport { enrichMetadata } from './enhancer.js';\n\n// ---------------------------------------------------------------------------\n// Events\n// ---------------------------------------------------------------------------\n\nexport type FormLifecycleEvent = CustomEvent<{\n form: HTMLFormElement;\n toolName: string;\n}>;\n\nfunction emit(type: 'form:registered' | 'form:unregistered', form: HTMLFormElement, toolName: string): void {\n window.dispatchEvent(\n new CustomEvent(type, { detail: { form, toolName } }) as FormLifecycleEvent,\n );\n}\n\n// ---------------------------------------------------------------------------\n// Registration helpers\n// ---------------------------------------------------------------------------\n\n/** Check whether a form should be excluded per config */\nfunction isExcluded(form: HTMLFormElement, config: ResolvedConfig): boolean {\n // Skip forms with data-no-webmcp\n if (form.dataset['noWebmcp'] !== undefined) return true;\n // Skip per config exclude list\n for (const selector of config.exclude) {\n try {\n if (form.matches(selector)) return true;\n } catch {\n // invalid selector \u2014 ignore\n }\n }\n return false;\n}\n\nasync function registerForm(form: HTMLFormElement, config: ResolvedConfig): Promise<void> {\n if (isExcluded(form, config)) return;\n\n // Find matching override (first matching selector wins)\n let override;\n for (const [selector, ovr] of Object.entries(config.overrides)) {\n try {\n if (form.matches(selector)) {\n override = ovr;\n break;\n }\n } catch {\n // invalid selector\n }\n }\n\n let metadata = analyzeForm(form, override);\n if (config.enhance) {\n if (config.debug) console.debug(`[auto-webmcp] Enriching: ${metadata.name}\u2026`);\n metadata = await enrichMetadata(metadata, config.enhance);\n }\n\n if (config.debug) {\n warnToolQuality(metadata.name, metadata.description);\n }\n\n const execute = buildExecuteHandler(form, config, metadata.name);\n\n await registerFormTool(form, metadata, execute);\n\n if (config.debug) {\n console.debug(`[auto-webmcp] Registered: ${metadata.name}`, metadata);\n }\n\n emit('form:registered', form, metadata.name);\n}\n\nasync function unregisterForm(form: HTMLFormElement, config: ResolvedConfig): Promise<void> {\n const { getRegisteredToolName } = await import('./registry.js');\n const name = getRegisteredToolName(form);\n if (!name) return;\n\n await unregisterFormTool(form);\n\n if (config.debug) {\n console.debug(`[auto-webmcp] Unregistered: ${name}`);\n }\n\n emit('form:unregistered', form, name);\n}\n\n// ---------------------------------------------------------------------------\n// MutationObserver\n// ---------------------------------------------------------------------------\n\nlet observer: MutationObserver | null = null;\n\nfunction startObserver(config: ResolvedConfig): void {\n if (observer) return;\n\n observer = new MutationObserver((mutations) => {\n for (const mutation of mutations) {\n for (const node of mutation.addedNodes) {\n if (!(node instanceof Element)) continue;\n\n const forms = node instanceof HTMLFormElement\n ? [node]\n : Array.from(node.querySelectorAll<HTMLFormElement>('form'));\n\n for (const form of forms) {\n void registerForm(form, config);\n }\n }\n\n for (const node of mutation.removedNodes) {\n if (!(node instanceof Element)) continue;\n\n const forms = node instanceof HTMLFormElement\n ? [node]\n : Array.from(node.querySelectorAll<HTMLFormElement>('form'));\n\n for (const form of forms) {\n void unregisterForm(form, config);\n }\n }\n }\n });\n\n observer.observe(document.body, { childList: true, subtree: true });\n}\n\n// ---------------------------------------------------------------------------\n// SPA route change support\n// ---------------------------------------------------------------------------\n\nfunction listenForRouteChanges(config: ResolvedConfig): void {\n // Hash changes\n window.addEventListener('hashchange', () => scanForms(config));\n\n // History API (pushState / replaceState)\n const original = {\n pushState: history.pushState.bind(history),\n replaceState: history.replaceState.bind(history),\n };\n\n history.pushState = function (...args) {\n original.pushState(...args);\n scanForms(config);\n };\n\n history.replaceState = function (...args) {\n original.replaceState(...args);\n scanForms(config);\n };\n\n window.addEventListener('popstate', () => scanForms(config));\n}\n\n// ---------------------------------------------------------------------------\n// Main scan\n// ---------------------------------------------------------------------------\n\nasync function scanForms(config: ResolvedConfig): Promise<void> {\n const forms = Array.from(document.querySelectorAll<HTMLFormElement>('form'));\n await Promise.all(forms.map((form) => registerForm(form, config)));\n}\n\n// ---------------------------------------------------------------------------\n// Public API\n// ---------------------------------------------------------------------------\n\nfunction warnToolQuality(name: string, description: string): void {\n if (/^form_\\d+$|^submit$|^form$/.test(name)) {\n console.warn(`[auto-webmcp] Tool \"${name}\" has a generic name. Consider adding a toolname or data-webmcp-name attribute.`);\n }\n if (!description || description === 'Submit form') {\n console.warn(`[auto-webmcp] Tool \"${name}\" has no meaningful description.`);\n }\n if (/don'?t|do not|never|avoid|not for/i.test(description)) {\n console.warn(`[auto-webmcp] Tool \"${name}\" description contains negative instructions. Per spec best practices, prefer positive descriptions.`);\n }\n}\n\nexport async function startDiscovery(config: ResolvedConfig): Promise<void> {\n if (document.readyState === 'loading') {\n await new Promise<void>((resolve) =>\n document.addEventListener('DOMContentLoaded', () => resolve(), { once: true }),\n );\n }\n\n await scanForms(config);\n startObserver(config);\n listenForRouteChanges(config);\n}\n\nexport function stopDiscovery(): void {\n observer?.disconnect();\n observer = null;\n}\n", "/**\n * interceptor.ts \u2014 Form submit interception for agent-invoked submissions\n *\n * WebMCP's `execute` callback receives form parameters and is expected to\n * return a result. This module bridges the gap: it fills form fields with\n * the agent-supplied values, submits the form, and resolves the execute\n * promise with a structured response.\n */\n\nimport { ResolvedConfig } from './config.js';\n\n// ---------------------------------------------------------------------------\n// Extended SubmitEvent types (WebMCP additions)\n// ---------------------------------------------------------------------------\n\ndeclare global {\n interface SubmitEvent {\n /** True when the form was submitted by an AI agent via WebMCP */\n agentInvoked?: boolean;\n /** Call to return a structured result to the agent */\n respondWith?: (promise: Promise<unknown>) => void;\n }\n}\n\nexport interface ExecuteResult {\n content: Array<{ type: 'text'; text: string }>;\n}\n\ntype Resolver = (result: ExecuteResult) => void;\ntype Rejecter = (error: Error) => void;\n\n/** Per-form pending execute promises */\nconst pendingExecutions = new WeakMap<\n HTMLFormElement,\n { resolve: Resolver; reject: Rejecter }\n>();\n\n/**\n * Build an `execute` function for a form tool.\n *\n * When the agent calls execute(params):\n * 1. Fills form fields with the supplied params\n * 2. Fires a submit event (or auto-submits if configured)\n * 3. Resolves with structured form data once submitted\n */\nexport function buildExecuteHandler(\n form: HTMLFormElement,\n config: ResolvedConfig,\n toolName: string,\n): (params: Record<string, unknown>) => Promise<ExecuteResult> {\n // Attach submit/reset listeners once per form\n attachSubmitInterceptor(form, toolName);\n\n return async (params: Record<string, unknown>): Promise<ExecuteResult> => {\n fillFormFields(form, params);\n\n // Dispatch toolactivated event per spec\n window.dispatchEvent(new CustomEvent('toolactivated', { detail: { toolName } }));\n\n return new Promise<ExecuteResult>((resolve, reject) => {\n pendingExecutions.set(form, { resolve, reject });\n\n if (\n config.autoSubmit ||\n form.hasAttribute('toolautosubmit') ||\n form.dataset['webmcpAutosubmit'] !== undefined\n ) {\n // Programmatically submit\n form.requestSubmit();\n }\n // Otherwise: the form stays filled; human clicks submit,\n // which fires the submit event interceptor below.\n });\n };\n}\n\nfunction attachSubmitInterceptor(form: HTMLFormElement, toolName: string): void {\n // Guard against attaching multiple times\n if ((form as unknown as Record<string, unknown>)['__awmcp_intercepted']) return;\n (form as unknown as Record<string, unknown>)['__awmcp_intercepted'] = true;\n\n form.addEventListener('submit', (e: SubmitEvent) => {\n const pending = pendingExecutions.get(form);\n if (!pending) return; // Normal human submission \u2014 do nothing\n\n // Agent-invoked path\n const { resolve } = pending;\n pendingExecutions.delete(form);\n\n const formData = serializeFormData(form);\n const text = JSON.stringify(formData);\n const result: ExecuteResult = { content: [{ type: 'text', text }] };\n\n if (e.agentInvoked && typeof e.respondWith === 'function') {\n // Native WebMCP path: use respondWith to return to browser\n e.preventDefault();\n e.respondWith(Promise.resolve(result));\n }\n resolve(result);\n });\n\n // Dispatch toolcancel when form is reset\n form.addEventListener('reset', () => {\n window.dispatchEvent(new CustomEvent('toolcancel', { detail: { toolName } }));\n });\n}\n\n// ---------------------------------------------------------------------------\n// Field filling\n// ---------------------------------------------------------------------------\n\nfunction fillFormFields(form: HTMLFormElement, params: Record<string, unknown>): void {\n for (const [name, value] of Object.entries(params)) {\n const escapedName = CSS.escape(name);\n\n // Try input, textarea, select with this name\n const input = form.querySelector<HTMLInputElement | HTMLTextAreaElement | HTMLSelectElement>(\n `[name=\"${escapedName}\"]`,\n );\n\n if (!input) continue;\n\n if (input instanceof HTMLInputElement) {\n fillInput(input, form, name, value);\n } else if (input instanceof HTMLTextAreaElement) {\n input.value = String(value ?? '');\n input.dispatchEvent(new Event('input', { bubbles: true }));\n input.dispatchEvent(new Event('change', { bubbles: true }));\n } else if (input instanceof HTMLSelectElement) {\n input.value = String(value ?? '');\n input.dispatchEvent(new Event('change', { bubbles: true }));\n }\n }\n}\n\nfunction fillInput(\n input: HTMLInputElement,\n form: HTMLFormElement,\n name: string,\n value: unknown,\n): void {\n const type = input.type.toLowerCase();\n\n if (type === 'checkbox') {\n input.checked = Boolean(value);\n input.dispatchEvent(new Event('change', { bubbles: true }));\n return;\n }\n\n if (type === 'radio') {\n const escapedName = CSS.escape(name);\n const radios = form.querySelectorAll<HTMLInputElement>(\n `input[type=\"radio\"][name=\"${escapedName}\"]`,\n );\n for (const radio of radios) {\n if (radio.value === String(value)) {\n radio.checked = true;\n radio.dispatchEvent(new Event('change', { bubbles: true }));\n break;\n }\n }\n return;\n }\n\n input.value = String(value ?? '');\n input.dispatchEvent(new Event('input', { bubbles: true }));\n input.dispatchEvent(new Event('change', { bubbles: true }));\n}\n\n// ---------------------------------------------------------------------------\n// Serialization\n// ---------------------------------------------------------------------------\n\nfunction serializeFormData(form: HTMLFormElement): Record<string, unknown> {\n const result: Record<string, unknown> = {};\n const data = new FormData(form);\n\n for (const [key, val] of data.entries()) {\n if (result[key] !== undefined) {\n // Multiple values \u2192 array\n const existing = result[key];\n if (Array.isArray(existing)) {\n existing.push(val);\n } else {\n result[key] = [existing, val];\n }\n } else {\n result[key] = val;\n }\n }\n\n return result;\n}\n\nfunction resolveFormAction(form: HTMLFormElement): string {\n if (form.action) {\n try {\n return new URL(form.action, window.location.href).href;\n } catch {\n // ignore\n }\n }\n return window.location.href;\n}\n", "/**\n * enhancer.ts \u2014 Optional LLM-based description enrichment\n *\n * Calls a small LLM to generate richer tool descriptions than heuristics\n * alone can provide. Activated only when config.enhance is set.\n */\n\nimport { ToolMetadata } from './analyzer.js';\nimport { EnhancerConfig } from './config.js';\n\nexport async function enrichMetadata(\n metadata: ToolMetadata,\n enhancer: EnhancerConfig,\n): Promise<ToolMetadata> {\n try {\n const enriched = await callLLM(metadata, enhancer);\n return { ...metadata, description: enriched };\n } catch (err) {\n // Enhancement is optional \u2014 fall back to heuristic description\n console.warn('[auto-webmcp] Enrichment failed, using heuristic description:', err);\n return metadata;\n }\n}\n\nasync function callLLM(metadata: ToolMetadata, config: EnhancerConfig): Promise<string> {\n const prompt = buildPrompt(metadata);\n\n if (config.provider === 'claude') {\n return callClaude(prompt, config);\n } else {\n return callGemini(prompt, config);\n }\n}\n\nfunction buildPrompt(metadata: ToolMetadata): string {\n const fields = Object.entries(metadata.inputSchema.properties)\n .map(([name, prop]) => `- ${prop.title ?? name} (${prop.type}): ${prop.description ?? ''}`)\n .join('\\n');\n\n return `You are helping describe a web form as an AI tool. Given this form information:\n\nName: ${metadata.name}\nCurrent description: ${metadata.description}\nFields:\n${fields}\n\nWrite a concise (1-2 sentence) description of what this tool does and when an AI agent should use it. Be specific and actionable. Respond with only the description, no preamble.`;\n}\n\nasync function callClaude(prompt: string, config: EnhancerConfig): Promise<string> {\n const model = config.model ?? 'claude-haiku-4-5-20251001';\n\n const response = await fetch('https://api.anthropic.com/v1/messages', {\n method: 'POST',\n headers: {\n 'x-api-key': config.apiKey,\n 'anthropic-version': '2023-06-01',\n 'content-type': 'application/json',\n },\n body: JSON.stringify({\n model,\n max_tokens: 150,\n messages: [{ role: 'user', content: prompt }],\n }),\n });\n\n if (!response.ok) {\n throw new Error(`Claude API error: ${response.status}`);\n }\n\n const data = await response.json() as {\n content: Array<{ type: string; text: string }>;\n };\n\n return data.content\n .filter((block) => block.type === 'text')\n .map((block) => block.text)\n .join('')\n .trim();\n}\n\nasync function callGemini(prompt: string, config: EnhancerConfig): Promise<string> {\n const model = config.model ?? 'gemini-1.5-flash';\n const url = `https://generativelanguage.googleapis.com/v1beta/models/${model}:generateContent?key=${config.apiKey}`;\n\n const response = await fetch(url, {\n method: 'POST',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify({\n contents: [{ parts: [{ text: prompt }] }],\n generationConfig: { maxOutputTokens: 150, temperature: 0.2 },\n }),\n });\n\n if (!response.ok) {\n throw new Error(`Gemini API error: ${response.status}`);\n }\n\n const data = await response.json() as {\n candidates: Array<{\n content: { parts: Array<{ text: string }> };\n }>;\n };\n\n return data.candidates[0]?.content.parts.map((p) => p.text).join('').trim() ?? '';\n}\n"],
5
+ "mappings": ";;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAkCO,SAAS,oBAA6B;AAC3C,SAAO,OAAO,cAAc,eAAe,OAAO,UAAU,iBAAiB;AAC/E;AAMA,eAAsB,iBACpB,MACA,UACA,SACe;AACf,MAAI,CAAC,kBAAkB;AAAG;AAG1B,QAAM,WAAW,gBAAgB,IAAI,IAAI;AACzC,MAAI,UAAU;AACZ,UAAM,mBAAmB,IAAI;AAAA,EAC/B;AAEA,QAAM,UAAU,aAAc,aAAa;AAAA,IACzC,MAAM,SAAS;AAAA,IACf,aAAa,SAAS;AAAA,IACtB,aAAa,SAAS;AAAA,IACtB;AAAA,EACF,CAAC;AAED,kBAAgB,IAAI,MAAM,SAAS,IAAI;AACzC;AAMA,eAAsB,mBAAmB,MAAsC;AAC7E,MAAI,CAAC,kBAAkB;AAAG;AAE1B,QAAM,OAAO,gBAAgB,IAAI,IAAI;AACrC,MAAI,CAAC;AAAM;AAEX,MAAI;AACF,UAAM,UAAU,aAAc,eAAe,IAAI;AAAA,EACnD,QAAQ;AAAA,EAER;AAEA,kBAAgB,OAAO,IAAI;AAC7B;AAGO,SAAS,sBAAsB,MAA2C;AAC/E,SAAO,gBAAgB,IAAI,IAAI;AACjC;AAGO,SAAS,wBAAwE;AACtF,SAAO,MAAM,KAAK,gBAAgB,QAAQ,CAAC,EAAE,IAAI,CAAC,CAAC,MAAM,IAAI,OAAO,EAAE,MAAM,KAAK,EAAE;AACrF;AAGA,eAAsB,gBAA+B;AACnD,QAAM,UAAU,MAAM,KAAK,gBAAgB,QAAQ,CAAC;AACpD,QAAM,QAAQ,IAAI,QAAQ,IAAI,CAAC,CAAC,IAAI,MAAM,mBAAmB,IAAI,CAAC,CAAC;AACrE;AAlGA,IA+BM;AA/BN;AAAA;AAAA;AA+BA,IAAM,kBAAkB,oBAAI,IAA6B;AAAA;AAAA;;;AC/BzD;AAAA;AAAA;AAAA;AAAA;;;ACmDO,SAAS,cAAc,YAA+C;AAC3E,SAAO;AAAA,IACL,SAAS,YAAY,WAAW,CAAC;AAAA,IACjC,YAAY,YAAY,cAAc;AAAA,IACtC,SAAS,YAAY,WAAW;AAAA,IAChC,WAAW,YAAY,aAAa,CAAC;AAAA,IACrC,OAAO,YAAY,SAAS;AAAA,EAC9B;AACF;;;AClCO,SAAS,kBACd,OAC2B;AAC3B,MAAI,iBAAiB,kBAAkB;AACrC,WAAO,gBAAgB,KAAK;AAAA,EAC9B;AACA,MAAI,iBAAiB,qBAAqB;AACxC,WAAO,EAAE,MAAM,SAAS;AAAA,EAC1B;AACA,MAAI,iBAAiB,mBAAmB;AACtC,WAAO,iBAAiB,KAAK;AAAA,EAC/B;AACA,SAAO;AACT;AAEA,SAAS,gBAAgB,OAAoD;AAC3E,QAAM,OAAO,MAAM,KAAK,YAAY;AAEpC,UAAQ,MAAM;AAAA,IACZ,KAAK;AAAA,IACL,KAAK;AAAA,IACL,KAAK;AACH,aAAO,kBAAkB,KAAK;AAAA,IAEhC,KAAK;AACH,aAAO,EAAE,GAAG,kBAAkB,KAAK,GAAG,QAAQ,QAAQ;AAAA,IAExD,KAAK;AACH,aAAO,EAAE,GAAG,kBAAkB,KAAK,GAAG,QAAQ,MAAM;AAAA,IAEtD,KAAK;AAAA,IACL,KAAK,SAAS;AACZ,YAAM,OAA2B,EAAE,MAAM,SAAS;AAClD,UAAI,MAAM,QAAQ;AAAI,aAAK,UAAU,WAAW,MAAM,GAAG;AACzD,UAAI,MAAM,QAAQ;AAAI,aAAK,UAAU,WAAW,MAAM,GAAG;AACzD,aAAO;AAAA,IACT;AAAA,IAEA,KAAK;AACH,aAAO,EAAE,MAAM,UAAU,QAAQ,OAAO;AAAA,IAE1C,KAAK;AACH,aAAO,EAAE,MAAM,UAAU,QAAQ,YAAY;AAAA,IAE/C,KAAK;AACH,aAAO,EAAE,MAAM,UAAU,QAAQ,OAAO;AAAA,IAE1C,KAAK;AACH,aAAO,EAAE,MAAM,UAAU,SAAS,kBAAkB;AAAA,IAEtD,KAAK;AACH,aAAO,EAAE,MAAM,UAAU,SAAS,mBAAmB;AAAA,IAEvD,KAAK;AACH,aAAO,EAAE,MAAM,UAAU,SAAS,oBAAoB;AAAA,IAExD,KAAK;AACH,aAAO,EAAE,MAAM,UAAU;AAAA,IAE3B,KAAK;AAEH,aAAO,EAAE,MAAM,SAAS;AAAA,IAE1B,KAAK;AAAA,IACL,KAAK;AAAA,IACL,KAAK;AAAA,IACL,KAAK;AAAA,IACL,KAAK;AAAA,IACL,KAAK;AAEH,aAAO;AAAA,IAET,KAAK;AAEH,aAAO;AAAA,IAET;AACE,aAAO,EAAE,MAAM,SAAS;AAAA,EAC5B;AACF;AAEA,SAAS,kBAAkB,OAA6C;AACtE,QAAM,OAA2B,EAAE,MAAM,SAAS;AAClD,MAAI,MAAM,YAAY;AAAG,SAAK,YAAY,MAAM;AAChD,MAAI,MAAM,YAAY,KAAK,MAAM,cAAc;AAAQ,SAAK,YAAY,MAAM;AAC9E,MAAI,MAAM;AAAS,SAAK,UAAU,MAAM;AACxC,SAAO;AACT;AAEA,SAAS,iBAAiB,QAA+C;AACvE,QAAM,WAAW,MAAM,KAAK,OAAO,OAAO,EAAE,OAAO,CAAC,MAAM,EAAE,UAAU,EAAE;AAExE,MAAI,SAAS,WAAW,GAAG;AACzB,WAAO,EAAE,MAAM,SAAS;AAAA,EAC1B;AAEA,QAAM,aAAa,SAAS,IAAI,CAAC,MAAM,EAAE,KAAK;AAC9C,QAAM,QAAQ,SAAS,IAAI,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,OAAO,EAAE,KAAK,KAAK,KAAK,EAAE,MAAM,EAAE;AAEvF,SAAO,EAAE,MAAM,UAAU,MAAM,YAAY,MAAM;AACnD;AAGO,SAAS,iBAAiB,MAAuB,MAAwB;AAC9E,QAAM,SAAS,MAAM;AAAA,IACnB,KAAK,iBAAmC,6BAA6B,IAAI,OAAO,IAAI,CAAC,IAAI;AAAA,EAC3F;AACA,SAAO,OAAO,IAAI,CAAC,MAAM,EAAE,KAAK,EAAE,OAAO,CAAC,MAAM,MAAM,EAAE;AAC1D;AAGO,SAAS,kBACd,MACA,MACyC;AACzC,QAAM,SAAS,MAAM;AAAA,IACnB,KAAK,iBAAmC,6BAA6B,IAAI,OAAO,IAAI,CAAC,IAAI;AAAA,EAC3F,EAAE,OAAO,CAAC,MAAM,EAAE,UAAU,EAAE;AAE9B,SAAO,OAAO,IAAI,CAAC,MAAM;AACvB,UAAM,QAAQ,kBAAkB,CAAC;AACjC,WAAO,EAAE,OAAO,EAAE,OAAO,OAAO,SAAS,EAAE,MAAM;AAAA,EACnD,CAAC;AACH;AAEA,SAAS,kBAAkB,OAAiC;AAE1D,QAAM,SAAS,MAAM,QAAQ,OAAO;AACpC,MAAI,QAAQ;AACV,UAAM,QAAQ,OAAO,UAAU,IAAI;AACnC,UAAM,iBAAiB,iCAAiC,EAAE,QAAQ,CAAC,OAAO,GAAG,OAAO,CAAC;AACrF,UAAM,OAAO,MAAM,aAAa,KAAK,KAAK;AAC1C,QAAI;AAAM,aAAO;AAAA,EACnB;AAEA,MAAI,MAAM,IAAI;AACZ,UAAM,QAAQ,SAAS,cAAgC,cAAc,IAAI,OAAO,MAAM,EAAE,CAAC,IAAI;AAC7F,QAAI,OAAO;AACT,YAAM,OAAO,MAAM,aAAa,KAAK,KAAK;AAC1C,UAAI;AAAM,eAAO;AAAA,IACnB;AAAA,EACF;AACA,SAAO;AACT;;;AC1JA,IAAI,YAAY;AAQT,SAAS,YAAY,MAAuB,UAAuC;AACxF,QAAM,OAAO,UAAU,QAAQ,cAAc,IAAI;AACjD,QAAM,cAAc,UAAU,eAAe,qBAAqB,IAAI;AACtE,QAAM,cAAc,YAAY,IAAI;AAEpC,SAAO,EAAE,MAAM,aAAa,YAAY;AAC1C;AAMA,SAAS,cAAc,MAA+B;AAEpD,QAAM,aAAa,KAAK,aAAa,UAAU;AAC/C,MAAI;AAAY,WAAO,aAAa,UAAU;AAG9C,QAAM,WAAW,KAAK,QAAQ,YAAY;AAC1C,MAAI;AAAU,WAAO,aAAa,QAAQ;AAG1C,QAAM,aAAa,oBAAoB,IAAI;AAC3C,MAAI;AAAY,WAAO,aAAa,UAAU;AAG9C,QAAM,UAAU,sBAAsB,IAAI;AAC1C,MAAI;AAAS,WAAO,aAAa,OAAO;AAGxC,MAAI,KAAK;AAAI,WAAO,aAAa,KAAK,EAAE;AACxC,MAAI,KAAK;AAAM,WAAO,aAAa,KAAK,IAAI;AAG5C,MAAI,KAAK,QAAQ;AACf,UAAM,UAAU,mBAAmB,KAAK,MAAM;AAC9C,QAAI;AAAS,aAAO,aAAa,OAAO;AAAA,EAC1C;AAGA,SAAO,QAAQ,EAAE,SAAS;AAC5B;AAEA,SAAS,aAAa,KAAqB;AACzC,SAAO,IACJ,YAAY,EACZ,KAAK,EACL,QAAQ,eAAe,GAAG,EAC1B,QAAQ,YAAY,EAAE,EACtB,MAAM,GAAG,EAAE,KAAK;AACrB;AAEA,SAAS,oBAAoB,MAA+B;AAC1D,QAAM,UAAU;AAAA,IACd,GAAG,MAAM,KAAK,KAAK,iBAAoC,2CAA2C,CAAC;AAAA,IACnG,GAAG,MAAM,KAAK,KAAK,iBAAmC,sBAAsB,CAAC;AAAA,EAC/E;AAEA,aAAW,OAAO,SAAS;AACzB,UAAM,OACJ,eAAe,mBACX,IAAI,MAAM,KAAK,IACf,IAAI,aAAa,KAAK,KAAK;AACjC,QAAI,QAAQ,KAAK,SAAS,KAAK,KAAK,SAAS;AAAI,aAAO;AAAA,EAC1D;AACA,SAAO;AACT;AAEA,SAAS,sBAAsB,MAA+B;AAE5D,MAAI,OAAuB;AAC3B,SAAO,MAAM;AAEX,QAAI,UAAU,KAAK;AACnB,WAAO,SAAS;AACd,UAAI,YAAY,KAAK,QAAQ,OAAO,GAAG;AACrC,cAAM,OAAO,QAAQ,aAAa,KAAK,KAAK;AAC5C,YAAI;AAAM,iBAAO;AAAA,MACnB;AACA,gBAAU,QAAQ;AAAA,IACpB;AACA,WAAO,KAAK;AAEZ,QAAI,CAAC,QAAQ,SAAS,SAAS;AAAM;AAAA,EACvC;AACA,SAAO;AACT;AAEA,SAAS,mBAAmB,KAAqB;AAC/C,MAAI;AACF,UAAM,SAAS,IAAI,IAAI,KAAK,OAAO,SAAS,IAAI;AAChD,UAAM,WAAW,OAAO,SAAS,MAAM,GAAG,EAAE,OAAO,OAAO;AAC1D,WAAO,SAAS,SAAS,SAAS,CAAC,KAAK;AAAA,EAC1C,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAMA,SAAS,qBAAqB,MAA+B;AAE3D,QAAM,aAAa,KAAK,aAAa,iBAAiB;AACtD,MAAI;AAAY,WAAO,WAAW,KAAK;AAGvC,QAAM,WAAW,KAAK,QAAQ,mBAAmB;AACjD,MAAI;AAAU,WAAO,SAAS,KAAK;AAGnC,QAAM,SAAS,KAAK,cAAc,QAAQ;AAC1C,MAAI,QAAQ,aAAa,KAAK;AAAG,WAAO,OAAO,YAAY,KAAK;AAGhE,QAAM,YAAY,KAAK,aAAa,YAAY;AAChD,MAAI,WAAW,KAAK;AAAG,WAAO,UAAU,KAAK;AAG7C,QAAM,gBAAgB,KAAK,aAAa,kBAAkB;AAC1D,MAAI,eAAe;AACjB,UAAM,SAAS,SAAS,eAAe,aAAa;AACpD,QAAI,QAAQ,aAAa,KAAK;AAAG,aAAO,OAAO,YAAY,KAAK;AAAA,EAClE;AAGA,QAAM,UAAU,sBAAsB,IAAI;AAC1C,QAAM,YAAY,SAAS,OAAO,KAAK;AACvC,MAAI,WAAW;AAAW,WAAO,GAAG,OAAO,WAAM,SAAS;AAC1D,MAAI;AAAS,WAAO;AACpB,MAAI;AAAW,WAAO;AAEtB,SAAO;AACT;AAMA,SAAS,YAAY,MAAmC;AACtD,QAAM,aAAiD,CAAC;AACxD,QAAM,WAAqB,CAAC;AAG5B,QAAM,uBAAuB,oBAAI,IAAY;AAE7C,QAAM,WAAW,MAAM;AAAA,IACrB,KAAK;AAAA,MACH;AAAA,IACF;AAAA,EACF;AAEA,aAAW,WAAW,UAAU;AAE9B,UAAM,OAAO,QAAQ;AACrB,QAAI,CAAC;AAAM;AAGX,QACE,mBAAmB,oBACnB,QAAQ,SAAS,SACjB;AACA,UAAI,qBAAqB,IAAI,IAAI;AAAG;AACpC,2BAAqB,IAAI,IAAI;AAAA,IAC/B;AAEA,UAAM,aAAa,kBAAkB,OAAO;AAC5C,QAAI,CAAC;AAAY;AAGjB,eAAW,QAAQ,gBAAgB,OAAO;AAC1C,UAAM,OAAO,sBAAsB,OAAO;AAC1C,QAAI;AAAM,iBAAW,cAAc;AAGnC,QACE,mBAAmB,oBACnB,QAAQ,SAAS,SACjB;AACA,iBAAW,OAAO,iBAAiB,MAAM,IAAI;AAC7C,YAAM,aAAa,kBAAkB,MAAM,IAAI;AAC/C,UAAI,WAAW,SAAS;AAAG,mBAAW,QAAQ;AAAA,IAChD;AAEA,eAAW,IAAI,IAAI;AAGnB,QAAI,QAAQ,UAAU;AACpB,eAAS,KAAK,IAAI;AAAA,IACpB;AAAA,EACF;AAEA,SAAO,EAAE,MAAM,UAAU,YAAY,SAAS;AAChD;AAEA,SAAS,gBACP,SACQ;AAER,MAAI,aAAa,WAAY,QAAwB,QAAQ,aAAa,GAAG;AAC3E,WAAQ,QAAwB,QAAQ,aAAa;AAAA,EACvD;AAGA,QAAM,YAAY,uBAAuB,OAAO;AAChD,MAAI;AAAW,WAAO;AAGtB,MAAI,QAAQ;AAAM,WAAO,aAAa,QAAQ,IAAI;AAGlD,MAAI,QAAQ;AAAI,WAAO,aAAa,QAAQ,EAAE;AAE9C,SAAO;AACT;AAEA,SAAS,sBACP,SACQ;AAER,QAAM,kBAAkB,QAAQ,aAAa,sBAAsB;AACnE,MAAI;AAAiB,WAAO,gBAAgB,KAAK;AAGjD,QAAM,KAAK;AACX,MAAI,GAAG,QAAQ,mBAAmB;AAAG,WAAO,GAAG,QAAQ,mBAAmB;AAG1E,QAAM,WAAW,QAAQ,aAAa,kBAAkB;AACxD,MAAI;AAAU,WAAO;AAErB,QAAM,gBAAgB,QAAQ,aAAa,kBAAkB;AAC7D,MAAI,eAAe;AACjB,UAAM,SAAS,SAAS,eAAe,aAAa;AACpD,QAAI,QAAQ,aAAa,KAAK;AAAG,aAAO,OAAO,YAAY,KAAK;AAAA,EAClE;AAGA,MAAI,mBAAmB,oBAAoB,mBAAmB,qBAAqB;AACjF,UAAM,KAAK,QAAQ,aAAa,KAAK;AACrC,QAAI,MAAM,GAAG,SAAS;AAAG,aAAO;AAAA,EAClC;AAGA,SAAO;AACT;AAEA,SAAS,uBACP,SACQ;AAER,MAAI,QAAQ,IAAI;AACd,UAAM,QAAQ,SAAS,cAAgC,cAAc,IAAI,OAAO,QAAQ,EAAE,CAAC,IAAI;AAC/F,QAAI,OAAO;AACT,YAAM,OAAO,uBAAuB,KAAK;AACzC,UAAI;AAAM,eAAO;AAAA,IACnB;AAAA,EACF;AAGA,QAAM,SAAS,QAAQ,QAAQ,OAAO;AACtC,MAAI,QAAQ;AACV,UAAM,OAAO,uBAAuB,MAAM;AAC1C,QAAI;AAAM,aAAO;AAAA,EACnB;AAEA,SAAO;AACT;AAEA,SAAS,uBAAuB,OAAiC;AAE/D,QAAM,QAAQ,MAAM,UAAU,IAAI;AAClC,QAAM,iBAAiB,iCAAiC,EAAE,QAAQ,CAAC,OAAO,GAAG,OAAO,CAAC;AACrF,SAAO,MAAM,aAAa,KAAK,KAAK;AACtC;AAEA,SAAS,aAAa,KAAqB;AACzC,SAAO,IACJ,QAAQ,SAAS,GAAG,EACpB,QAAQ,mBAAmB,OAAO,EAClC,KAAK,EACL,QAAQ,SAAS,CAAC,MAAM,EAAE,YAAY,CAAC;AAC5C;;;AC3SA;;;AC0BA,IAAM,oBAAoB,oBAAI,QAG5B;AAUK,SAAS,oBACd,MACA,QACA,UAC6D;AAE7D,0BAAwB,MAAM,QAAQ;AAEtC,SAAO,OAAO,WAA4D;AACxE,mBAAe,MAAM,MAAM;AAG3B,WAAO,cAAc,IAAI,YAAY,iBAAiB,EAAE,QAAQ,EAAE,SAAS,EAAE,CAAC,CAAC;AAE/E,WAAO,IAAI,QAAuB,CAAC,SAAS,WAAW;AACrD,wBAAkB,IAAI,MAAM,EAAE,SAAS,OAAO,CAAC;AAE/C,UACE,OAAO,cACP,KAAK,aAAa,gBAAgB,KAClC,KAAK,QAAQ,kBAAkB,MAAM,QACrC;AAEA,aAAK,cAAc;AAAA,MACrB;AAAA,IAGF,CAAC;AAAA,EACH;AACF;AAEA,SAAS,wBAAwB,MAAuB,UAAwB;AAE9E,MAAK,KAA4C,qBAAqB;AAAG;AACzE,EAAC,KAA4C,qBAAqB,IAAI;AAEtE,OAAK,iBAAiB,UAAU,CAAC,MAAmB;AAClD,UAAM,UAAU,kBAAkB,IAAI,IAAI;AAC1C,QAAI,CAAC;AAAS;AAGd,UAAM,EAAE,QAAQ,IAAI;AACpB,sBAAkB,OAAO,IAAI;AAE7B,UAAM,WAAW,kBAAkB,IAAI;AACvC,UAAM,OAAO,KAAK,UAAU,QAAQ;AACpC,UAAM,SAAwB,EAAE,SAAS,CAAC,EAAE,MAAM,QAAQ,KAAK,CAAC,EAAE;AAElE,QAAI,EAAE,gBAAgB,OAAO,EAAE,gBAAgB,YAAY;AAEzD,QAAE,eAAe;AACjB,QAAE,YAAY,QAAQ,QAAQ,MAAM,CAAC;AAAA,IACvC;AACA,YAAQ,MAAM;AAAA,EAChB,CAAC;AAGD,OAAK,iBAAiB,SAAS,MAAM;AACnC,WAAO,cAAc,IAAI,YAAY,cAAc,EAAE,QAAQ,EAAE,SAAS,EAAE,CAAC,CAAC;AAAA,EAC9E,CAAC;AACH;AAMA,SAAS,eAAe,MAAuB,QAAuC;AACpF,aAAW,CAAC,MAAM,KAAK,KAAK,OAAO,QAAQ,MAAM,GAAG;AAClD,UAAM,cAAc,IAAI,OAAO,IAAI;AAGnC,UAAM,QAAQ,KAAK;AAAA,MACjB,UAAU,WAAW;AAAA,IACvB;AAEA,QAAI,CAAC;AAAO;AAEZ,QAAI,iBAAiB,kBAAkB;AACrC,gBAAU,OAAO,MAAM,MAAM,KAAK;AAAA,IACpC,WAAW,iBAAiB,qBAAqB;AAC/C,YAAM,QAAQ,OAAO,SAAS,EAAE;AAChC,YAAM,cAAc,IAAI,MAAM,SAAS,EAAE,SAAS,KAAK,CAAC,CAAC;AACzD,YAAM,cAAc,IAAI,MAAM,UAAU,EAAE,SAAS,KAAK,CAAC,CAAC;AAAA,IAC5D,WAAW,iBAAiB,mBAAmB;AAC7C,YAAM,QAAQ,OAAO,SAAS,EAAE;AAChC,YAAM,cAAc,IAAI,MAAM,UAAU,EAAE,SAAS,KAAK,CAAC,CAAC;AAAA,IAC5D;AAAA,EACF;AACF;AAEA,SAAS,UACP,OACA,MACA,MACA,OACM;AACN,QAAM,OAAO,MAAM,KAAK,YAAY;AAEpC,MAAI,SAAS,YAAY;AACvB,UAAM,UAAU,QAAQ,KAAK;AAC7B,UAAM,cAAc,IAAI,MAAM,UAAU,EAAE,SAAS,KAAK,CAAC,CAAC;AAC1D;AAAA,EACF;AAEA,MAAI,SAAS,SAAS;AACpB,UAAM,cAAc,IAAI,OAAO,IAAI;AACnC,UAAM,SAAS,KAAK;AAAA,MAClB,6BAA6B,WAAW;AAAA,IAC1C;AACA,eAAW,SAAS,QAAQ;AAC1B,UAAI,MAAM,UAAU,OAAO,KAAK,GAAG;AACjC,cAAM,UAAU;AAChB,cAAM,cAAc,IAAI,MAAM,UAAU,EAAE,SAAS,KAAK,CAAC,CAAC;AAC1D;AAAA,MACF;AAAA,IACF;AACA;AAAA,EACF;AAEA,QAAM,QAAQ,OAAO,SAAS,EAAE;AAChC,QAAM,cAAc,IAAI,MAAM,SAAS,EAAE,SAAS,KAAK,CAAC,CAAC;AACzD,QAAM,cAAc,IAAI,MAAM,UAAU,EAAE,SAAS,KAAK,CAAC,CAAC;AAC5D;AAMA,SAAS,kBAAkB,MAAgD;AACzE,QAAM,SAAkC,CAAC;AACzC,QAAM,OAAO,IAAI,SAAS,IAAI;AAE9B,aAAW,CAAC,KAAK,GAAG,KAAK,KAAK,QAAQ,GAAG;AACvC,QAAI,OAAO,GAAG,MAAM,QAAW;AAE7B,YAAM,WAAW,OAAO,GAAG;AAC3B,UAAI,MAAM,QAAQ,QAAQ,GAAG;AAC3B,iBAAS,KAAK,GAAG;AAAA,MACnB,OAAO;AACL,eAAO,GAAG,IAAI,CAAC,UAAU,GAAG;AAAA,MAC9B;AAAA,IACF,OAAO;AACL,aAAO,GAAG,IAAI;AAAA,IAChB;AAAA,EACF;AAEA,SAAO;AACT;;;ACtLA,eAAsB,eACpB,UACA,UACuB;AACvB,MAAI;AACF,UAAM,WAAW,MAAM,QAAQ,UAAU,QAAQ;AACjD,WAAO,EAAE,GAAG,UAAU,aAAa,SAAS;AAAA,EAC9C,SAAS,KAAK;AAEZ,YAAQ,KAAK,iEAAiE,GAAG;AACjF,WAAO;AAAA,EACT;AACF;AAEA,eAAe,QAAQ,UAAwB,QAAyC;AACtF,QAAM,SAAS,YAAY,QAAQ;AAEnC,MAAI,OAAO,aAAa,UAAU;AAChC,WAAO,WAAW,QAAQ,MAAM;AAAA,EAClC,OAAO;AACL,WAAO,WAAW,QAAQ,MAAM;AAAA,EAClC;AACF;AAEA,SAAS,YAAY,UAAgC;AACnD,QAAM,SAAS,OAAO,QAAQ,SAAS,YAAY,UAAU,EAC1D,IAAI,CAAC,CAAC,MAAM,IAAI,MAAM,KAAK,KAAK,SAAS,IAAI,KAAK,KAAK,IAAI,MAAM,KAAK,eAAe,EAAE,EAAE,EACzF,KAAK,IAAI;AAEZ,SAAO;AAAA;AAAA,QAED,SAAS,IAAI;AAAA,uBACE,SAAS,WAAW;AAAA;AAAA,EAEzC,MAAM;AAAA;AAAA;AAGR;AAEA,eAAe,WAAW,QAAgB,QAAyC;AACjF,QAAM,QAAQ,OAAO,SAAS;AAE9B,QAAM,WAAW,MAAM,MAAM,yCAAyC;AAAA,IACpE,QAAQ;AAAA,IACR,SAAS;AAAA,MACP,aAAa,OAAO;AAAA,MACpB,qBAAqB;AAAA,MACrB,gBAAgB;AAAA,IAClB;AAAA,IACA,MAAM,KAAK,UAAU;AAAA,MACnB;AAAA,MACA,YAAY;AAAA,MACZ,UAAU,CAAC,EAAE,MAAM,QAAQ,SAAS,OAAO,CAAC;AAAA,IAC9C,CAAC;AAAA,EACH,CAAC;AAED,MAAI,CAAC,SAAS,IAAI;AAChB,UAAM,IAAI,MAAM,qBAAqB,SAAS,MAAM,EAAE;AAAA,EACxD;AAEA,QAAM,OAAO,MAAM,SAAS,KAAK;AAIjC,SAAO,KAAK,QACT,OAAO,CAAC,UAAU,MAAM,SAAS,MAAM,EACvC,IAAI,CAAC,UAAU,MAAM,IAAI,EACzB,KAAK,EAAE,EACP,KAAK;AACV;AAEA,eAAe,WAAW,QAAgB,QAAyC;AACjF,QAAM,QAAQ,OAAO,SAAS;AAC9B,QAAM,MAAM,2DAA2D,KAAK,wBAAwB,OAAO,MAAM;AAEjH,QAAM,WAAW,MAAM,MAAM,KAAK;AAAA,IAChC,QAAQ;AAAA,IACR,SAAS,EAAE,gBAAgB,mBAAmB;AAAA,IAC9C,MAAM,KAAK,UAAU;AAAA,MACnB,UAAU,CAAC,EAAE,OAAO,CAAC,EAAE,MAAM,OAAO,CAAC,EAAE,CAAC;AAAA,MACxC,kBAAkB,EAAE,iBAAiB,KAAK,aAAa,IAAI;AAAA,IAC7D,CAAC;AAAA,EACH,CAAC;AAED,MAAI,CAAC,SAAS,IAAI;AAChB,UAAM,IAAI,MAAM,qBAAqB,SAAS,MAAM,EAAE;AAAA,EACxD;AAEA,QAAM,OAAO,MAAM,SAAS,KAAK;AAMjC,SAAO,KAAK,WAAW,CAAC,GAAG,QAAQ,MAAM,IAAI,CAAC,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,EAAE,KAAK,KAAK;AACjF;;;AFtFA,SAAS,KAAK,MAA+C,MAAuB,UAAwB;AAC1G,SAAO;AAAA,IACL,IAAI,YAAY,MAAM,EAAE,QAAQ,EAAE,MAAM,SAAS,EAAE,CAAC;AAAA,EACtD;AACF;AAOA,SAAS,WAAW,MAAuB,QAAiC;AAE1E,MAAI,KAAK,QAAQ,UAAU,MAAM;AAAW,WAAO;AAEnD,aAAW,YAAY,OAAO,SAAS;AACrC,QAAI;AACF,UAAI,KAAK,QAAQ,QAAQ;AAAG,eAAO;AAAA,IACrC,QAAQ;AAAA,IAER;AAAA,EACF;AACA,SAAO;AACT;AAEA,eAAe,aAAa,MAAuB,QAAuC;AACxF,MAAI,WAAW,MAAM,MAAM;AAAG;AAG9B,MAAI;AACJ,aAAW,CAAC,UAAU,GAAG,KAAK,OAAO,QAAQ,OAAO,SAAS,GAAG;AAC9D,QAAI;AACF,UAAI,KAAK,QAAQ,QAAQ,GAAG;AAC1B,mBAAW;AACX;AAAA,MACF;AAAA,IACF,QAAQ;AAAA,IAER;AAAA,EACF;AAEA,MAAI,WAAW,YAAY,MAAM,QAAQ;AACzC,MAAI,OAAO,SAAS;AAClB,QAAI,OAAO;AAAO,cAAQ,MAAM,4BAA4B,SAAS,IAAI,QAAG;AAC5E,eAAW,MAAM,eAAe,UAAU,OAAO,OAAO;AAAA,EAC1D;AAEA,MAAI,OAAO,OAAO;AAChB,oBAAgB,SAAS,MAAM,SAAS,WAAW;AAAA,EACrD;AAEA,QAAM,UAAU,oBAAoB,MAAM,QAAQ,SAAS,IAAI;AAE/D,QAAM,iBAAiB,MAAM,UAAU,OAAO;AAE9C,MAAI,OAAO,OAAO;AAChB,YAAQ,MAAM,6BAA6B,SAAS,IAAI,IAAI,QAAQ;AAAA,EACtE;AAEA,OAAK,mBAAmB,MAAM,SAAS,IAAI;AAC7C;AAEA,eAAe,eAAe,MAAuB,QAAuC;AAC1F,QAAM,EAAE,uBAAAA,uBAAsB,IAAI,MAAM;AACxC,QAAM,OAAOA,uBAAsB,IAAI;AACvC,MAAI,CAAC;AAAM;AAEX,QAAM,mBAAmB,IAAI;AAE7B,MAAI,OAAO,OAAO;AAChB,YAAQ,MAAM,+BAA+B,IAAI,EAAE;AAAA,EACrD;AAEA,OAAK,qBAAqB,MAAM,IAAI;AACtC;AAMA,IAAI,WAAoC;AAExC,SAAS,cAAc,QAA8B;AACnD,MAAI;AAAU;AAEd,aAAW,IAAI,iBAAiB,CAAC,cAAc;AAC7C,eAAW,YAAY,WAAW;AAChC,iBAAW,QAAQ,SAAS,YAAY;AACtC,YAAI,EAAE,gBAAgB;AAAU;AAEhC,cAAM,QAAQ,gBAAgB,kBAC1B,CAAC,IAAI,IACL,MAAM,KAAK,KAAK,iBAAkC,MAAM,CAAC;AAE7D,mBAAW,QAAQ,OAAO;AACxB,eAAK,aAAa,MAAM,MAAM;AAAA,QAChC;AAAA,MACF;AAEA,iBAAW,QAAQ,SAAS,cAAc;AACxC,YAAI,EAAE,gBAAgB;AAAU;AAEhC,cAAM,QAAQ,gBAAgB,kBAC1B,CAAC,IAAI,IACL,MAAM,KAAK,KAAK,iBAAkC,MAAM,CAAC;AAE7D,mBAAW,QAAQ,OAAO;AACxB,eAAK,eAAe,MAAM,MAAM;AAAA,QAClC;AAAA,MACF;AAAA,IACF;AAAA,EACF,CAAC;AAED,WAAS,QAAQ,SAAS,MAAM,EAAE,WAAW,MAAM,SAAS,KAAK,CAAC;AACpE;AAMA,SAAS,sBAAsB,QAA8B;AAE3D,SAAO,iBAAiB,cAAc,MAAM,UAAU,MAAM,CAAC;AAG7D,QAAM,WAAW;AAAA,IACf,WAAW,QAAQ,UAAU,KAAK,OAAO;AAAA,IACzC,cAAc,QAAQ,aAAa,KAAK,OAAO;AAAA,EACjD;AAEA,UAAQ,YAAY,YAAa,MAAM;AACrC,aAAS,UAAU,GAAG,IAAI;AAC1B,cAAU,MAAM;AAAA,EAClB;AAEA,UAAQ,eAAe,YAAa,MAAM;AACxC,aAAS,aAAa,GAAG,IAAI;AAC7B,cAAU,MAAM;AAAA,EAClB;AAEA,SAAO,iBAAiB,YAAY,MAAM,UAAU,MAAM,CAAC;AAC7D;AAMA,eAAe,UAAU,QAAuC;AAC9D,QAAM,QAAQ,MAAM,KAAK,SAAS,iBAAkC,MAAM,CAAC;AAC3E,QAAM,QAAQ,IAAI,MAAM,IAAI,CAAC,SAAS,aAAa,MAAM,MAAM,CAAC,CAAC;AACnE;AAMA,SAAS,gBAAgB,MAAc,aAA2B;AAChE,MAAI,6BAA6B,KAAK,IAAI,GAAG;AAC3C,YAAQ,KAAK,uBAAuB,IAAI,iFAAiF;AAAA,EAC3H;AACA,MAAI,CAAC,eAAe,gBAAgB,eAAe;AACjD,YAAQ,KAAK,uBAAuB,IAAI,kCAAkC;AAAA,EAC5E;AACA,MAAI,qCAAqC,KAAK,WAAW,GAAG;AAC1D,YAAQ,KAAK,uBAAuB,IAAI,sGAAsG;AAAA,EAChJ;AACF;AAEA,eAAsB,eAAe,QAAuC;AAC1E,MAAI,SAAS,eAAe,WAAW;AACrC,UAAM,IAAI;AAAA,MAAc,CAAC,YACvB,SAAS,iBAAiB,oBAAoB,MAAM,QAAQ,GAAG,EAAE,MAAM,KAAK,CAAC;AAAA,IAC/E;AAAA,EACF;AAEA,QAAM,UAAU,MAAM;AACtB,gBAAc,MAAM;AACpB,wBAAsB,MAAM;AAC9B;AAEO,SAAS,gBAAsB;AACpC,YAAU,WAAW;AACrB,aAAW;AACb;;;AJ7LA;AAqBA,eAAsB,WAAW,QAAsD;AACrF,QAAM,WAAW,cAAc,MAAM;AAErC,MAAI,SAAS,OAAO;AAClB,YAAQ,MAAM,8BAA8B;AAAA,MAC1C,iBAAiB,kBAAkB;AAAA,MACnC,QAAQ;AAAA,IACV,CAAC;AAAA,EACH;AAEA,QAAM,eAAe,QAAQ;AAE7B,SAAO;AAAA,IACL,SAAS,YAAY;AACnB,oBAAc;AACd,YAAM,cAAc;AAAA,IACtB;AAAA,IACA,UAAU;AAAA,IACV,aAAa,kBAAkB;AAAA,EACjC;AACF;AAUA,IACE,OAAO,WAAW,eAClB,CAAE,OAA8C,2BAA2B,GAC3E;AACA,OAAK,WAAW;AAClB;",
6
6
  "names": ["getRegisteredToolName"]
7
7
  }