auto-webmcp 0.2.10 → 0.3.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/dist/analyzer.d.ts +7 -0
- package/dist/analyzer.d.ts.map +1 -1
- package/dist/auto-webmcp.cjs.js +100 -13
- package/dist/auto-webmcp.cjs.js.map +2 -2
- package/dist/auto-webmcp.esm.js +100 -13
- package/dist/auto-webmcp.esm.js.map +2 -2
- package/dist/auto-webmcp.iife.js +2 -2
- package/dist/auto-webmcp.iife.js.map +3 -3
- package/dist/registry.d.ts +7 -1
- package/dist/registry.d.ts.map +1 -1
- package/dist/schema.d.ts +1 -0
- package/dist/schema.d.ts.map +1 -1
- package/package.json +1 -1
package/dist/analyzer.d.ts
CHANGED
|
@@ -3,10 +3,17 @@
|
|
|
3
3
|
*/
|
|
4
4
|
import { JsonSchema } from './schema.js';
|
|
5
5
|
import { FormOverride } from './config.js';
|
|
6
|
+
export interface ToolAnnotations {
|
|
7
|
+
readOnlyHint?: boolean;
|
|
8
|
+
destructiveHint?: boolean;
|
|
9
|
+
idempotentHint?: boolean;
|
|
10
|
+
openWorldHint?: boolean;
|
|
11
|
+
}
|
|
6
12
|
export interface ToolMetadata {
|
|
7
13
|
name: string;
|
|
8
14
|
description: string;
|
|
9
15
|
inputSchema: JsonSchema;
|
|
16
|
+
annotations?: ToolAnnotations;
|
|
10
17
|
/** Key → DOM element for fields not addressable by name (id-keyed or ARIA-role controls). */
|
|
11
18
|
fieldElements?: Map<string, Element>;
|
|
12
19
|
}
|
package/dist/analyzer.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"analyzer.d.ts","sourceRoot":"","sources":["../src/analyzer.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,UAAU,EAAmJ,MAAM,aAAa,CAAC;AAC1L,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAE3C,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,UAAU,CAAC;IACxB,6FAA6F;IAC7F,aAAa,CAAC,EAAE,GAAG,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACtC;AAKD,iDAAiD;AACjD,wBAAgB,cAAc,IAAI,IAAI,CAErC;AAED,gDAAgD;AAChD,wBAAgB,WAAW,CAAC,IAAI,EAAE,eAAe,EAAE,QAAQ,CAAC,EAAE,YAAY,GAAG,YAAY,
|
|
1
|
+
{"version":3,"file":"analyzer.d.ts","sourceRoot":"","sources":["../src/analyzer.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,UAAU,EAAmJ,MAAM,aAAa,CAAC;AAC1L,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAE3C,MAAM,WAAW,eAAe;IAC9B,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,aAAa,CAAC,EAAE,OAAO,CAAC;CACzB;AAED,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,UAAU,CAAC;IACxB,WAAW,CAAC,EAAE,eAAe,CAAC;IAC9B,6FAA6F;IAC7F,aAAa,CAAC,EAAE,GAAG,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACtC;AAKD,iDAAiD;AACjD,wBAAgB,cAAc,IAAI,IAAI,CAErC;AAED,gDAAgD;AAChD,wBAAgB,WAAW,CAAC,IAAI,EAAE,eAAe,EAAE,QAAQ,CAAC,EAAE,YAAY,GAAG,YAAY,CAOxF;AAynBD;;;GAGG;AACH,wBAAgB,uBAAuB,CACrC,SAAS,EAAE,OAAO,EAClB,MAAM,EAAE,KAAK,CAAC,gBAAgB,GAAG,mBAAmB,GAAG,iBAAiB,CAAC,EACzE,SAAS,EAAE,iBAAiB,GAAG,gBAAgB,GAAG,IAAI,GACrD,YAAY,CAKd"}
|
package/dist/auto-webmcp.cjs.js
CHANGED
|
@@ -40,22 +40,21 @@ async function registerFormTool(form, metadata, execute) {
|
|
|
40
40
|
if (existing) {
|
|
41
41
|
await unregisterFormTool(form);
|
|
42
42
|
}
|
|
43
|
+
const toolDef = {
|
|
44
|
+
name: metadata.name,
|
|
45
|
+
description: metadata.description,
|
|
46
|
+
inputSchema: metadata.inputSchema,
|
|
47
|
+
execute
|
|
48
|
+
};
|
|
49
|
+
if (metadata.annotations && Object.keys(metadata.annotations).length > 0) {
|
|
50
|
+
toolDef.annotations = metadata.annotations;
|
|
51
|
+
}
|
|
43
52
|
try {
|
|
44
|
-
await navigator.modelContext.registerTool(
|
|
45
|
-
name: metadata.name,
|
|
46
|
-
description: metadata.description,
|
|
47
|
-
inputSchema: metadata.inputSchema,
|
|
48
|
-
execute
|
|
49
|
-
});
|
|
53
|
+
await navigator.modelContext.registerTool(toolDef);
|
|
50
54
|
} catch {
|
|
51
55
|
try {
|
|
52
56
|
await navigator.modelContext.unregisterTool(metadata.name);
|
|
53
|
-
await navigator.modelContext.registerTool(
|
|
54
|
-
name: metadata.name,
|
|
55
|
-
description: metadata.description,
|
|
56
|
-
inputSchema: metadata.inputSchema,
|
|
57
|
-
execute
|
|
58
|
-
});
|
|
57
|
+
await navigator.modelContext.registerTool(toolDef);
|
|
59
58
|
} catch {
|
|
60
59
|
}
|
|
61
60
|
}
|
|
@@ -340,7 +339,8 @@ function analyzeForm(form, override) {
|
|
|
340
339
|
const name = override?.name ?? inferToolName(form);
|
|
341
340
|
const description = override?.description ?? inferToolDescription(form);
|
|
342
341
|
const { schema: inputSchema, fieldElements } = buildSchema(form);
|
|
343
|
-
|
|
342
|
+
const annotations = inferAnnotations(form);
|
|
343
|
+
return { name, description, inputSchema, annotations, fieldElements };
|
|
344
344
|
}
|
|
345
345
|
function inferToolName(form) {
|
|
346
346
|
const nativeName = form.getAttribute("toolname");
|
|
@@ -437,6 +437,72 @@ function inferToolDescription(form) {
|
|
|
437
437
|
return pageTitle;
|
|
438
438
|
return "Submit form";
|
|
439
439
|
}
|
|
440
|
+
var READONLY_BUTTON_PATTERNS = /^(search|find|look|filter|browse|view|show|check|preview|get|fetch|retrieve|load)\b/i;
|
|
441
|
+
var DESTRUCTIVE_BUTTON_PATTERNS = /^(delete|remove|cancel|terminate|destroy|purge|revoke|unsubscribe|deactivate)\b/i;
|
|
442
|
+
var DESTRUCTIVE_URL_PATTERNS = /\/(delete|remove|cancel|destroy)\b/i;
|
|
443
|
+
function inferAnnotations(form) {
|
|
444
|
+
const annotations = {};
|
|
445
|
+
if (form.dataset["webmcpReadonly"] !== void 0) {
|
|
446
|
+
annotations.readOnlyHint = form.dataset["webmcpReadonly"] !== "false";
|
|
447
|
+
}
|
|
448
|
+
if (form.dataset["webmcpDestructive"] !== void 0) {
|
|
449
|
+
annotations.destructiveHint = form.dataset["webmcpDestructive"] !== "false";
|
|
450
|
+
}
|
|
451
|
+
if (form.dataset["webmcpIdempotent"] !== void 0) {
|
|
452
|
+
annotations.idempotentHint = form.dataset["webmcpIdempotent"] !== "false";
|
|
453
|
+
}
|
|
454
|
+
if (form.dataset["webmcpOpenworld"] !== void 0) {
|
|
455
|
+
annotations.openWorldHint = form.dataset["webmcpOpenworld"] !== "false";
|
|
456
|
+
}
|
|
457
|
+
if (annotations.readOnlyHint === void 0) {
|
|
458
|
+
const isGet = form.method.toLowerCase() === "get";
|
|
459
|
+
const submitText = getSubmitButtonText(form);
|
|
460
|
+
const isReadLabel = submitText ? READONLY_BUTTON_PATTERNS.test(submitText.trim()) : false;
|
|
461
|
+
if (isGet || isReadLabel)
|
|
462
|
+
annotations.readOnlyHint = true;
|
|
463
|
+
}
|
|
464
|
+
if (annotations.destructiveHint === void 0) {
|
|
465
|
+
const submitText = getSubmitButtonText(form);
|
|
466
|
+
const isDestructiveLabel = submitText ? DESTRUCTIVE_BUTTON_PATTERNS.test(submitText.trim()) : false;
|
|
467
|
+
const isDestructiveUrl = form.action ? DESTRUCTIVE_URL_PATTERNS.test(form.action) : false;
|
|
468
|
+
if (isDestructiveLabel || isDestructiveUrl)
|
|
469
|
+
annotations.destructiveHint = true;
|
|
470
|
+
}
|
|
471
|
+
if (annotations.idempotentHint === void 0) {
|
|
472
|
+
if (annotations.readOnlyHint === true || form.method.toLowerCase() === "get") {
|
|
473
|
+
annotations.idempotentHint = true;
|
|
474
|
+
}
|
|
475
|
+
}
|
|
476
|
+
if (annotations.openWorldHint === void 0) {
|
|
477
|
+
annotations.openWorldHint = annotations.readOnlyHint !== true;
|
|
478
|
+
}
|
|
479
|
+
const hasNonDefault = annotations.readOnlyHint === true || annotations.destructiveHint === true || annotations.idempotentHint === true || annotations.openWorldHint === false;
|
|
480
|
+
return hasNonDefault ? annotations : {};
|
|
481
|
+
}
|
|
482
|
+
function extractDefaultValue(control) {
|
|
483
|
+
if (control instanceof HTMLInputElement) {
|
|
484
|
+
const type = control.type.toLowerCase();
|
|
485
|
+
if (type === "checkbox")
|
|
486
|
+
return control.checked ? true : void 0;
|
|
487
|
+
if (type === "radio")
|
|
488
|
+
return void 0;
|
|
489
|
+
if (type === "number" || type === "range") {
|
|
490
|
+
return control.value !== "" ? parseFloat(control.value) : void 0;
|
|
491
|
+
}
|
|
492
|
+
return control.value !== "" ? control.value : void 0;
|
|
493
|
+
}
|
|
494
|
+
if (control instanceof HTMLTextAreaElement) {
|
|
495
|
+
return control.value !== "" ? control.value : void 0;
|
|
496
|
+
}
|
|
497
|
+
if (control instanceof HTMLSelectElement) {
|
|
498
|
+
if (control.multiple) {
|
|
499
|
+
const selected = Array.from(control.options).filter((o) => o.selected).map((o) => o.value);
|
|
500
|
+
return selected.length > 0 ? selected : void 0;
|
|
501
|
+
}
|
|
502
|
+
return control.value !== "" ? control.value : void 0;
|
|
503
|
+
}
|
|
504
|
+
return void 0;
|
|
505
|
+
}
|
|
440
506
|
function buildSchema(form) {
|
|
441
507
|
const properties = {};
|
|
442
508
|
const required = [];
|
|
@@ -472,11 +538,19 @@ function buildSchema(form) {
|
|
|
472
538
|
const desc = inferFieldDescription(control);
|
|
473
539
|
if (desc)
|
|
474
540
|
schemaProp.description = desc;
|
|
541
|
+
const defaultVal = extractDefaultValue(control);
|
|
542
|
+
if (defaultVal !== void 0)
|
|
543
|
+
schemaProp.default = defaultVal;
|
|
475
544
|
if (control instanceof HTMLInputElement && control.type === "radio") {
|
|
476
545
|
schemaProp.enum = collectRadioEnum(form, fieldKey);
|
|
477
546
|
const radioOneOf = collectRadioOneOf(form, fieldKey);
|
|
478
547
|
if (radioOneOf.length > 0)
|
|
479
548
|
schemaProp.oneOf = radioOneOf;
|
|
549
|
+
const checkedRadio = form.querySelector(
|
|
550
|
+
`input[type="radio"][name="${CSS.escape(fieldKey)}"]:checked`
|
|
551
|
+
);
|
|
552
|
+
if (checkedRadio?.value)
|
|
553
|
+
schemaProp.default = checkedRadio.value;
|
|
480
554
|
}
|
|
481
555
|
if (control instanceof HTMLInputElement && control.type === "checkbox") {
|
|
482
556
|
const checkboxValues = collectCheckboxEnum(form, fieldKey);
|
|
@@ -488,6 +562,13 @@ function buildSchema(form) {
|
|
|
488
562
|
};
|
|
489
563
|
if (schemaProp.description)
|
|
490
564
|
arrayProp.description = schemaProp.description;
|
|
565
|
+
const checkedBoxes = Array.from(
|
|
566
|
+
form.querySelectorAll(
|
|
567
|
+
`input[type="checkbox"][name="${CSS.escape(fieldKey)}"]:checked`
|
|
568
|
+
)
|
|
569
|
+
).map((b) => b.value);
|
|
570
|
+
if (checkedBoxes.length > 0)
|
|
571
|
+
arrayProp.default = checkedBoxes;
|
|
491
572
|
properties[fieldKey] = arrayProp;
|
|
492
573
|
if (control.required)
|
|
493
574
|
required.push(fieldKey);
|
|
@@ -610,6 +691,9 @@ function resolveAriaFieldKey(el) {
|
|
|
610
691
|
return null;
|
|
611
692
|
}
|
|
612
693
|
function inferAriaFieldTitle(el) {
|
|
694
|
+
const nativeTitle = el.getAttribute("toolparamtitle");
|
|
695
|
+
if (nativeTitle?.trim())
|
|
696
|
+
return nativeTitle.trim();
|
|
613
697
|
const htmlEl = el;
|
|
614
698
|
if (htmlEl.dataset?.["webmcpTitle"])
|
|
615
699
|
return htmlEl.dataset["webmcpTitle"];
|
|
@@ -648,6 +732,9 @@ function inferAriaFieldDescription(el) {
|
|
|
648
732
|
return "";
|
|
649
733
|
}
|
|
650
734
|
function inferFieldTitle(control) {
|
|
735
|
+
const nativeTitle = control.getAttribute("toolparamtitle");
|
|
736
|
+
if (nativeTitle?.trim())
|
|
737
|
+
return nativeTitle.trim();
|
|
651
738
|
if ("dataset" in control && control.dataset["webmcpTitle"]) {
|
|
652
739
|
return control.dataset["webmcpTitle"];
|
|
653
740
|
}
|