auto-webmcp 0.1.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/LICENSE +21 -0
- package/README.md +193 -0
- package/dist/analyzer.d.ts +15 -0
- package/dist/analyzer.d.ts.map +1 -0
- package/dist/auto-webmcp.cjs.js +703 -0
- package/dist/auto-webmcp.cjs.js.map +7 -0
- package/dist/auto-webmcp.esm.js +687 -0
- package/dist/auto-webmcp.esm.js.map +7 -0
- package/dist/auto-webmcp.iife.js +10 -0
- package/dist/auto-webmcp.iife.js.map +7 -0
- package/dist/config.d.ts +44 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/discovery.d.ts +11 -0
- package/dist/discovery.d.ts.map +1 -0
- package/dist/enhancer.d.ts +10 -0
- package/dist/enhancer.d.ts.map +1 -0
- package/dist/index.d.ts +33 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/interceptor.d.ts +33 -0
- package/dist/interceptor.d.ts.map +1 -0
- package/dist/registry.d.ts +40 -0
- package/dist/registry.d.ts.map +1 -0
- package/dist/schema.d.ts +25 -0
- package/dist/schema.d.ts.map +1 -0
- package/package.json +46 -0
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 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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",
|
|
6
|
+
"names": ["getRegisteredToolName"]
|
|
7
|
+
}
|