@anubhav-choubey/web-for-agents 0.1.0 → 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 +74 -515
- package/dist/bin.js +4 -4
- package/dist/chunk-CGIIB6AF.js +127 -0
- package/dist/{chunk-AZG5MLNG.js → chunk-F7PN5R25.js} +2 -0
- package/dist/chunk-LCVPXUFN.js +245 -0
- package/dist/{chunk-IF32TPGR.js → chunk-P6JSPAA2.js} +169 -124
- package/dist/{chunk-5TNG4QMP.js → chunk-PGZH33B5.js} +20 -2
- package/dist/chunk-PHTV5NAY.js +44 -0
- package/dist/{chunk-ZYMNO5AO.js → chunk-PSNLS4GL.js} +93 -57
- package/dist/{chunk-HONWT6GK.js → chunk-SMFRAZAA.js} +66 -34
- package/dist/cli.js +4 -4
- package/dist/{happyDom-XVDHYJDM.js → happyDom-WTYQ5UAC.js} +3 -3
- package/dist/index.js +41 -235
- package/dist/overlay.js +7 -32
- package/dist/{renderChild-Y2RFSYY4.js → renderChild-H6TR4SGV.js} +27 -4
- package/dist/vite.d.ts +88 -2
- package/dist/vite.js +628 -146
- package/package.json +1 -1
- package/dist/chunk-CKXHTGGT.js +0 -25
- package/dist/chunk-LCVI2PRP.js +0 -13
package/dist/index.js
CHANGED
|
@@ -1,13 +1,25 @@
|
|
|
1
|
+
import {
|
|
2
|
+
EMPTY_OBJECT_SCHEMA,
|
|
3
|
+
agentFields,
|
|
4
|
+
hasOwn,
|
|
5
|
+
inDisabledFieldset,
|
|
6
|
+
isConcealed,
|
|
7
|
+
isDisabled,
|
|
8
|
+
schemaFromForm,
|
|
9
|
+
validateFormInput,
|
|
10
|
+
validateInput
|
|
11
|
+
} from "./chunk-LCVPXUFN.js";
|
|
1
12
|
import {
|
|
2
13
|
AGENT_GLOBAL_VERSION,
|
|
14
|
+
DESCRIPTION_MAX_CHARS,
|
|
15
|
+
DESCRIPTION_MIN_CHARS,
|
|
16
|
+
TITLE_MAX_CHARS,
|
|
3
17
|
isValidActionName
|
|
4
|
-
} from "./chunk-
|
|
18
|
+
} from "./chunk-PHTV5NAY.js";
|
|
5
19
|
import {
|
|
6
20
|
compareStrings
|
|
7
21
|
} from "./chunk-AAIYCJD3.js";
|
|
8
|
-
import
|
|
9
|
-
collapseWhitespace
|
|
10
|
-
} from "./chunk-FEAKVNMG.js";
|
|
22
|
+
import "./chunk-FEAKVNMG.js";
|
|
11
23
|
import {
|
|
12
24
|
ACTION_ATTR,
|
|
13
25
|
ACTION_DESCRIPTION_ATTR,
|
|
@@ -17,15 +29,13 @@ import {
|
|
|
17
29
|
CONTENT_ATTR,
|
|
18
30
|
EXCLUDE_ATTR,
|
|
19
31
|
HEAD_OWNED_ATTR,
|
|
20
|
-
HIDDEN_SELECTOR,
|
|
21
32
|
PRERENDERED_ATTR,
|
|
22
33
|
READY_GLOBAL,
|
|
23
|
-
WEBMCP_TOOLPARAMDESCRIPTION_ATTR,
|
|
24
34
|
hasScheme,
|
|
25
35
|
publicUrl,
|
|
26
36
|
resolveUrl,
|
|
27
37
|
routeOf
|
|
28
|
-
} from "./chunk-
|
|
38
|
+
} from "./chunk-F7PN5R25.js";
|
|
29
39
|
import {
|
|
30
40
|
errorMessage,
|
|
31
41
|
withPrefix
|
|
@@ -185,6 +195,7 @@ function flush(doc) {
|
|
|
185
195
|
else merged.set(tag.key, tag);
|
|
186
196
|
}
|
|
187
197
|
}
|
|
198
|
+
if (process.env.NODE_ENV !== "production") warnLengths(merged);
|
|
188
199
|
for (const key of store.applied) if (!merged.has(key)) removeHeadTag(key, doc);
|
|
189
200
|
applyHeadTags([...merged.values()], doc);
|
|
190
201
|
store.applied = new Set(merged.keys());
|
|
@@ -240,6 +251,26 @@ function release() {
|
|
|
240
251
|
}
|
|
241
252
|
}
|
|
242
253
|
var useIsoLayoutEffect = typeof window !== "undefined" ? useLayoutEffect : useEffect;
|
|
254
|
+
var warnedLengths = /* @__PURE__ */ new Set();
|
|
255
|
+
function warnLengths(merged) {
|
|
256
|
+
if (process.env.NODE_ENV !== "production") {
|
|
257
|
+
const t = merged.get("title");
|
|
258
|
+
const d = merged.get("name:description");
|
|
259
|
+
const title = t?.kind === "title" ? t.text : void 0;
|
|
260
|
+
const description = d?.kind === "meta" ? d.attrs.content : void 0;
|
|
261
|
+
const once = (value, message) => {
|
|
262
|
+
if (warnedLengths.has(message + value)) return;
|
|
263
|
+
warnedLengths.add(message + value);
|
|
264
|
+
console.warn(`[web-for-agents] ${message}: "${value}"`);
|
|
265
|
+
};
|
|
266
|
+
if (title && title.length > TITLE_MAX_CHARS) {
|
|
267
|
+
once(title, `<Seo> title is ${title.length} characters (over ${TITLE_MAX_CHARS})`);
|
|
268
|
+
}
|
|
269
|
+
if (description && (description.length < DESCRIPTION_MIN_CHARS || description.length > DESCRIPTION_MAX_CHARS)) {
|
|
270
|
+
once(description, `<Seo> description is ${description.length} characters (aim for ${DESCRIPTION_MIN_CHARS}-${DESCRIPTION_MAX_CHARS})`);
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
}
|
|
243
274
|
var DefaultsContext = createContext({});
|
|
244
275
|
function SeoProvider(props) {
|
|
245
276
|
const { defaults, children } = props;
|
|
@@ -416,231 +447,6 @@ function hydrateApp(container, app, options) {
|
|
|
416
447
|
// src/runtime/agent/react.tsx
|
|
417
448
|
import { useCallback, useEffect as useEffect2, useLayoutEffect as useLayoutEffect2, useRef as useRef2 } from "react";
|
|
418
449
|
|
|
419
|
-
// src/shared/object.ts
|
|
420
|
-
var hasOwn = (o, k) => Object.prototype.hasOwnProperty.call(o, k);
|
|
421
|
-
|
|
422
|
-
// src/runtime/agent/dom.ts
|
|
423
|
-
var INERT_OR_CLOSED = "[inert], dialog:not([open]), details:not([open]) > :not(summary)";
|
|
424
|
-
var CONCEALED = `${HIDDEN_SELECTOR}, ${INERT_OR_CLOSED}`;
|
|
425
|
-
function inDisabledFieldset(el) {
|
|
426
|
-
for (let child = el, p = el.parentElement; p; child = p, p = p.parentElement) {
|
|
427
|
-
if (p.matches("fieldset[disabled]") && child !== p.querySelector(":scope > legend")) return true;
|
|
428
|
-
}
|
|
429
|
-
return false;
|
|
430
|
-
}
|
|
431
|
-
function isDisabled(el) {
|
|
432
|
-
return el.hasAttribute("disabled") || el.getAttribute("aria-disabled") === "true" || inDisabledFieldset(el);
|
|
433
|
-
}
|
|
434
|
-
function isConcealed(el) {
|
|
435
|
-
if (!el.closest(CONCEALED)) return false;
|
|
436
|
-
const labels = el.tagName === "INPUT" && /^(checkbox|radio)$/.test(el.type) ? el.labels : null;
|
|
437
|
-
return !(labels && el.getAttribute("aria-hidden") !== "true" && !el.matches(INERT_OR_CLOSED) && !el.parentElement?.closest(CONCEALED) && Array.from(labels).some((l) => !isConcealed(l) && !isDisabled(l)));
|
|
438
|
-
}
|
|
439
|
-
|
|
440
|
-
// src/runtime/agent/formSchema.ts
|
|
441
|
-
var EMPTY_OBJECT_SCHEMA = Object.freeze({
|
|
442
|
-
type: "object",
|
|
443
|
-
properties: Object.freeze({}),
|
|
444
|
-
additionalProperties: false
|
|
445
|
-
});
|
|
446
|
-
var EXCLUDED_TYPES = /* @__PURE__ */ new Set(["hidden", "password", "file", "submit", "button", "reset", "image"]);
|
|
447
|
-
function isAgentField(e) {
|
|
448
|
-
const tag = e.tagName;
|
|
449
|
-
if (tag !== "INPUT" && tag !== "SELECT" && tag !== "TEXTAREA") return false;
|
|
450
|
-
if (!e.getAttribute("name")) return false;
|
|
451
|
-
if (e.hasAttribute("disabled") || e.hasAttribute("readonly") || inDisabledFieldset(e)) return false;
|
|
452
|
-
if (tag === "INPUT" && EXCLUDED_TYPES.has((e.getAttribute("type") ?? "text").toLowerCase())) return false;
|
|
453
|
-
return !isConcealed(e);
|
|
454
|
-
}
|
|
455
|
-
function agentFields(form) {
|
|
456
|
-
const groups = /* @__PURE__ */ new Map();
|
|
457
|
-
for (const el of Array.from(form.elements)) {
|
|
458
|
-
if (!isAgentField(el)) continue;
|
|
459
|
-
const name = el.getAttribute("name");
|
|
460
|
-
const list = groups.get(name);
|
|
461
|
-
if (list) list.push(el);
|
|
462
|
-
else groups.set(name, [el]);
|
|
463
|
-
}
|
|
464
|
-
return groups;
|
|
465
|
-
}
|
|
466
|
-
function labelText(el) {
|
|
467
|
-
const labels = el.labels ? Array.from(el.labels) : [];
|
|
468
|
-
if (labels.length === 0) {
|
|
469
|
-
const wrap = el.closest("label");
|
|
470
|
-
if (wrap) labels.push(wrap);
|
|
471
|
-
}
|
|
472
|
-
return collapseWhitespace(
|
|
473
|
-
labels.map((l) => {
|
|
474
|
-
const c = l.cloneNode(true);
|
|
475
|
-
c.querySelectorAll("input,select,textarea,button").forEach((n) => n.remove());
|
|
476
|
-
return c.textContent;
|
|
477
|
-
}).join(" ")
|
|
478
|
-
);
|
|
479
|
-
}
|
|
480
|
-
function describe(el) {
|
|
481
|
-
return collapseWhitespace(el.getAttribute(ACTION_PARAM_ATTR)) || collapseWhitespace(el.getAttribute(WEBMCP_TOOLPARAMDESCRIPTION_ATTR)) || labelText(el) || collapseWhitespace(el.getAttribute("aria-label")) || collapseWhitespace(el.getAttribute("placeholder"));
|
|
482
|
-
}
|
|
483
|
-
function num(el, attr) {
|
|
484
|
-
const v = el.getAttribute(attr);
|
|
485
|
-
if (v === null || v.trim() === "") return void 0;
|
|
486
|
-
const n = Number(v);
|
|
487
|
-
return Number.isFinite(n) ? n : void 0;
|
|
488
|
-
}
|
|
489
|
-
function inputSchema(el) {
|
|
490
|
-
const type = el instanceof HTMLTextAreaElement ? "textarea" : (el.getAttribute("type") ?? "text").toLowerCase();
|
|
491
|
-
const s = {};
|
|
492
|
-
if (type === "checkbox") {
|
|
493
|
-
s.type = "boolean";
|
|
494
|
-
return s;
|
|
495
|
-
}
|
|
496
|
-
if (type === "number" || type === "range") {
|
|
497
|
-
const step = el.getAttribute("step");
|
|
498
|
-
s.type = step === null || /^\d+$/.test(step.trim()) ? "integer" : "number";
|
|
499
|
-
const min = num(el, "min");
|
|
500
|
-
const max = num(el, "max");
|
|
501
|
-
if (min !== void 0) s.minimum = min;
|
|
502
|
-
if (max !== void 0) s.maximum = max;
|
|
503
|
-
return s;
|
|
504
|
-
}
|
|
505
|
-
s.type = "string";
|
|
506
|
-
if (type === "email") s.format = "email";
|
|
507
|
-
else if (type === "url") s.format = "uri";
|
|
508
|
-
else if (type === "date") s.format = "date";
|
|
509
|
-
else if (type === "time") s.format = "time";
|
|
510
|
-
const minLength = num(el, "minlength");
|
|
511
|
-
const maxLength = num(el, "maxlength");
|
|
512
|
-
if (minLength !== void 0) s.minLength = minLength;
|
|
513
|
-
if (maxLength !== void 0) s.maxLength = maxLength;
|
|
514
|
-
const pattern = el.getAttribute("pattern");
|
|
515
|
-
if (pattern) s.pattern = `^(?:${pattern})$`;
|
|
516
|
-
return s;
|
|
517
|
-
}
|
|
518
|
-
function withDescription(s, desc) {
|
|
519
|
-
if (desc) s.description = desc;
|
|
520
|
-
return s;
|
|
521
|
-
}
|
|
522
|
-
function selectSchema(sel, desc) {
|
|
523
|
-
const opts = Array.from(sel.querySelectorAll("option")).filter((o) => !o.hasAttribute("disabled") && !o.hasAttribute("hidden") && !o.closest("optgroup[disabled]")).map((o) => ({ value: o.getAttribute("value") ?? collapseWhitespace(o.textContent), label: collapseWhitespace(o.textContent) })).filter((o) => o.value !== "");
|
|
524
|
-
const values = opts.map((o) => o.value);
|
|
525
|
-
const list = opts.map((o) => o.label && o.label !== o.value ? `${o.value} (${o.label})` : o.value).join(", ");
|
|
526
|
-
const schema2 = sel.hasAttribute("multiple") ? { type: "array", items: { type: "string", enum: values } } : { type: "string", enum: values };
|
|
527
|
-
return withDescription(schema2, [desc, `Options: ${list}`].filter(Boolean).join(". "));
|
|
528
|
-
}
|
|
529
|
-
var isType = (e, t) => e.tagName === "INPUT" && (e.getAttribute("type") ?? "").toLowerCase() === t;
|
|
530
|
-
function groupSchema(els) {
|
|
531
|
-
const first = els[0];
|
|
532
|
-
const desc = els.map(describe).find(Boolean) ?? "";
|
|
533
|
-
if (first.tagName === "SELECT") return selectSchema(first, desc);
|
|
534
|
-
const values = () => els.map((e) => e.getAttribute("value") ?? "on");
|
|
535
|
-
if (els.every((e) => isType(e, "radio"))) return withDescription({ type: "string", enum: values() }, desc);
|
|
536
|
-
if (els.length > 1 && els.every((e) => isType(e, "checkbox"))) {
|
|
537
|
-
return withDescription({ type: "array", items: { type: "string", enum: values() } }, desc);
|
|
538
|
-
}
|
|
539
|
-
return withDescription(inputSchema(first), desc);
|
|
540
|
-
}
|
|
541
|
-
function schemaFromForm(form) {
|
|
542
|
-
const properties = /* @__PURE__ */ Object.create(null);
|
|
543
|
-
const required = [];
|
|
544
|
-
for (const [name, els] of agentFields(form)) {
|
|
545
|
-
properties[name] = groupSchema(els);
|
|
546
|
-
if (els.some((e) => e.hasAttribute("required"))) required.push(name);
|
|
547
|
-
}
|
|
548
|
-
const out = { type: "object", properties, additionalProperties: false };
|
|
549
|
-
if (required.length) out.required = required;
|
|
550
|
-
return out;
|
|
551
|
-
}
|
|
552
|
-
var MAX_REGEX_INPUT = 1e4;
|
|
553
|
-
function checkValue(s, v, field, errors) {
|
|
554
|
-
const bad = (message) => {
|
|
555
|
-
errors.push({ field, message });
|
|
556
|
-
};
|
|
557
|
-
switch (s.type) {
|
|
558
|
-
case "string":
|
|
559
|
-
if (typeof v !== "string") return bad("must be string");
|
|
560
|
-
break;
|
|
561
|
-
case "number":
|
|
562
|
-
if (typeof v !== "number" || !Number.isFinite(v)) return bad("must be number");
|
|
563
|
-
break;
|
|
564
|
-
case "integer":
|
|
565
|
-
if (typeof v !== "number" || !Number.isInteger(v)) return bad("must be integer");
|
|
566
|
-
break;
|
|
567
|
-
case "boolean":
|
|
568
|
-
if (typeof v !== "boolean") return bad("must be boolean");
|
|
569
|
-
break;
|
|
570
|
-
case "array":
|
|
571
|
-
if (!Array.isArray(v)) return bad("must be array");
|
|
572
|
-
break;
|
|
573
|
-
case "object":
|
|
574
|
-
if (!isPlainObject(v)) return bad("must be object");
|
|
575
|
-
checkObject(s, v, `${field}.`, errors);
|
|
576
|
-
return;
|
|
577
|
-
}
|
|
578
|
-
if (s.enum && !s.enum.includes(v)) {
|
|
579
|
-
return bad(`must be one of: ${s.enum.join(", ")}`);
|
|
580
|
-
}
|
|
581
|
-
if (typeof v === "string") {
|
|
582
|
-
if (s.minLength !== void 0 && v.length < s.minLength) bad(`must be at least ${s.minLength} characters`);
|
|
583
|
-
if (s.maxLength !== void 0 && v.length > s.maxLength) bad(`must be at most ${s.maxLength} characters`);
|
|
584
|
-
if ((s.pattern !== void 0 || s.format === "email") && v.length > MAX_REGEX_INPUT) {
|
|
585
|
-
return bad(`must be at most ${MAX_REGEX_INPUT} characters to be checked`);
|
|
586
|
-
}
|
|
587
|
-
if (s.pattern !== void 0) {
|
|
588
|
-
let ok = false;
|
|
589
|
-
try {
|
|
590
|
-
ok = new RegExp(s.pattern).test(v);
|
|
591
|
-
} catch {
|
|
592
|
-
ok = false;
|
|
593
|
-
}
|
|
594
|
-
if (!ok) bad(`must match pattern ${s.pattern}`);
|
|
595
|
-
}
|
|
596
|
-
if (s.format === "email" && !/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(v)) bad("must be a valid email");
|
|
597
|
-
if (s.format === "uri") {
|
|
598
|
-
try {
|
|
599
|
-
new URL(v);
|
|
600
|
-
} catch {
|
|
601
|
-
bad("must be a valid URI");
|
|
602
|
-
}
|
|
603
|
-
}
|
|
604
|
-
}
|
|
605
|
-
if (typeof v === "number") {
|
|
606
|
-
if (s.minimum !== void 0 && v < s.minimum) bad(`must be >= ${s.minimum}`);
|
|
607
|
-
if (s.maximum !== void 0 && v > s.maximum) bad(`must be <= ${s.maximum}`);
|
|
608
|
-
}
|
|
609
|
-
if (Array.isArray(v) && s.items) {
|
|
610
|
-
v.forEach((item, i) => checkValue(s.items, item, `${field}[${i}]`, errors));
|
|
611
|
-
}
|
|
612
|
-
}
|
|
613
|
-
function isPlainObject(v) {
|
|
614
|
-
if (typeof v !== "object" || v === null) return false;
|
|
615
|
-
const proto = Object.getPrototypeOf(v);
|
|
616
|
-
return proto === Object.prototype || proto === null;
|
|
617
|
-
}
|
|
618
|
-
function checkObject(schema2, obj, prefix, errors) {
|
|
619
|
-
const props = schema2.properties ?? {};
|
|
620
|
-
for (const name of schema2.required ?? []) {
|
|
621
|
-
if (!hasOwn(obj, name) || obj[name] === void 0) errors.push({ field: prefix + name, message: "is required" });
|
|
622
|
-
}
|
|
623
|
-
for (const [key, value] of Object.entries(obj)) {
|
|
624
|
-
const prop = props[key];
|
|
625
|
-
if (!hasOwn(props, key) || !prop) {
|
|
626
|
-
if (schema2.additionalProperties !== true) errors.push({ field: prefix + key, message: "is not an allowed field" });
|
|
627
|
-
continue;
|
|
628
|
-
}
|
|
629
|
-
if (value === void 0) continue;
|
|
630
|
-
checkValue(prop, value, prefix + key, errors);
|
|
631
|
-
}
|
|
632
|
-
}
|
|
633
|
-
function validateInput(schema2, input) {
|
|
634
|
-
if (!isPlainObject(input)) return { ok: false, errors: [{ field: "", message: "input must be an object" }] };
|
|
635
|
-
const errors = [];
|
|
636
|
-
checkObject(schema2, input, "", errors);
|
|
637
|
-
return errors.length ? { ok: false, errors } : { ok: true, value: input };
|
|
638
|
-
}
|
|
639
|
-
function validateFormInput(schema2, input) {
|
|
640
|
-
const r = validateInput({ ...schema2, additionalProperties: true }, input);
|
|
641
|
-
return r.ok ? r : validateInput(schema2, input);
|
|
642
|
-
}
|
|
643
|
-
|
|
644
450
|
// src/runtime/agent/formAutomation.ts
|
|
645
451
|
var MESSAGE_SELECTOR = '[role="alert"], [role="status"], [aria-live]';
|
|
646
452
|
var MAX_MESSAGE = 500;
|
|
@@ -850,7 +656,7 @@ function schemaOf(r) {
|
|
|
850
656
|
}
|
|
851
657
|
return r.spec.inputSchema ?? EMPTY_OBJECT_SCHEMA;
|
|
852
658
|
}
|
|
853
|
-
function
|
|
659
|
+
function describe(name, entry) {
|
|
854
660
|
const r = resolve(entry);
|
|
855
661
|
if (r.kind === null) return null;
|
|
856
662
|
const d = {
|
|
@@ -865,7 +671,7 @@ function describe2(name, entry) {
|
|
|
865
671
|
return d;
|
|
866
672
|
}
|
|
867
673
|
function listAgentActions() {
|
|
868
|
-
return Array.from(activeEntries(), ([name, [, entry]]) =>
|
|
674
|
+
return Array.from(activeEntries(), ([name, [, entry]]) => describe(name, entry)).filter((d) => d !== null).sort((a, b) => compareStrings(a.name, b.name));
|
|
869
675
|
}
|
|
870
676
|
var UNSAFE = /[\0-\t\v-\x1F\x7F-\x9F\xAD\u061C\u200B\u200E\u200F\u2028-\u202E\u2060\u2066-\u2069\uFEFF]/g;
|
|
871
677
|
var UNIT = /\\u[\da-f]{4}|\\[^]|[^]/giu;
|
|
@@ -981,7 +787,7 @@ function warnUndescribable(name, err) {
|
|
|
981
787
|
function buildTool(name, entry) {
|
|
982
788
|
let d;
|
|
983
789
|
try {
|
|
984
|
-
d =
|
|
790
|
+
d = describe(name, entry);
|
|
985
791
|
} catch (err) {
|
|
986
792
|
warnUndescribable(name, err);
|
|
987
793
|
return null;
|
package/dist/overlay.js
CHANGED
|
@@ -2,11 +2,12 @@ import {
|
|
|
2
2
|
DEFAULT_CONTENT_SELECTOR,
|
|
3
3
|
DEFAULT_SHORTCUT,
|
|
4
4
|
buildPageMarkdown,
|
|
5
|
+
markupActions,
|
|
5
6
|
matchesShortcut,
|
|
6
7
|
parseShortcut,
|
|
7
8
|
readPageMeta,
|
|
8
9
|
selectContentRegion
|
|
9
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-PSNLS4GL.js";
|
|
10
11
|
import {
|
|
11
12
|
compareStrings
|
|
12
13
|
} from "./chunk-AAIYCJD3.js";
|
|
@@ -15,15 +16,10 @@ import {
|
|
|
15
16
|
} from "./chunk-LCLDQ3A3.js";
|
|
16
17
|
import "./chunk-FEAKVNMG.js";
|
|
17
18
|
import {
|
|
18
|
-
ACTION_ATTR,
|
|
19
|
-
ACTION_DESCRIPTION_ATTR,
|
|
20
|
-
ACTION_DESTRUCTIVE_ATTR,
|
|
21
19
|
AGENT_GLOBAL,
|
|
22
|
-
WEBMCP_TOOLDESCRIPTION_ATTR,
|
|
23
|
-
WEBMCP_TOOLNAME_ATTR,
|
|
24
20
|
routeOf,
|
|
25
21
|
trimTrailingSlash
|
|
26
|
-
} from "./chunk-
|
|
22
|
+
} from "./chunk-F7PN5R25.js";
|
|
27
23
|
import {
|
|
28
24
|
errorMessage
|
|
29
25
|
} from "./chunk-JJN6FNJD.js";
|
|
@@ -68,33 +64,12 @@ function registryActions(doc) {
|
|
|
68
64
|
}
|
|
69
65
|
}
|
|
70
66
|
function collectActions(doc) {
|
|
71
|
-
const markup =
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
if (!name) return;
|
|
75
|
-
markup.push({
|
|
76
|
-
name,
|
|
77
|
-
description: el2.getAttribute(ACTION_DESCRIPTION_ATTR) || null,
|
|
78
|
-
kind: el2.tagName === "FORM" ? "form" : "click",
|
|
79
|
-
destructive: el2.getAttribute(ACTION_DESTRUCTIVE_ATTR) === "true",
|
|
80
|
-
source: "markup"
|
|
81
|
-
});
|
|
82
|
-
});
|
|
83
|
-
const declarative = [];
|
|
84
|
-
doc.querySelectorAll(`form[${WEBMCP_TOOLNAME_ATTR}]`).forEach((el2) => {
|
|
85
|
-
const name = el2.getAttribute(WEBMCP_TOOLNAME_ATTR)?.trim();
|
|
86
|
-
if (!name) return;
|
|
87
|
-
declarative.push({
|
|
88
|
-
name,
|
|
89
|
-
description: el2.getAttribute(WEBMCP_TOOLDESCRIPTION_ATTR) || null,
|
|
90
|
-
kind: "form",
|
|
91
|
-
destructive: false,
|
|
92
|
-
source: "webmcp-declarative"
|
|
93
|
-
});
|
|
94
|
-
});
|
|
67
|
+
const markup = markupActions(doc).map(
|
|
68
|
+
({ name, description, kind, destructive, source }) => ({ name, description, kind, destructive, source })
|
|
69
|
+
);
|
|
95
70
|
const seen = /* @__PURE__ */ new Set();
|
|
96
71
|
const out = [];
|
|
97
|
-
for (const a of [...registryActions(doc), ...markup
|
|
72
|
+
for (const a of [...registryActions(doc), ...markup]) {
|
|
98
73
|
if (seen.has(a.name)) continue;
|
|
99
74
|
seen.add(a.name);
|
|
100
75
|
out.push(a);
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import "./chunk-
|
|
1
|
+
import "./chunk-PGZH33B5.js";
|
|
2
2
|
import {
|
|
3
3
|
errorMessage
|
|
4
4
|
} from "./chunk-JJN6FNJD.js";
|
|
@@ -196,13 +196,35 @@ function isSyncResources(v) {
|
|
|
196
196
|
(r) => r !== null && typeof r === "object" && typeof r.body === "string" && typeof r.contentType === "string"
|
|
197
197
|
);
|
|
198
198
|
}
|
|
199
|
+
function parseChildOptions(json) {
|
|
200
|
+
const o = JSON.parse(json);
|
|
201
|
+
if (o === null || typeof o !== "object" || Array.isArray(o)) throw new Error("render options are not an object");
|
|
202
|
+
const v = o;
|
|
203
|
+
const bad = (field, want) => {
|
|
204
|
+
throw new Error(`render option ${field} must be ${want}, got ${JSON.stringify(v[field])}`);
|
|
205
|
+
};
|
|
206
|
+
const strings = (x) => Array.isArray(x) && x.every((s) => typeof s === "string");
|
|
207
|
+
if (!strings(v.localOrigins)) bad("localOrigins", "an array of strings");
|
|
208
|
+
if (v.allowOrigins !== void 0 && !strings(v.allowOrigins)) bad("allowOrigins", "an array of strings");
|
|
209
|
+
if (v.idleMs !== void 0 && !(typeof v.idleMs === "number" && Number.isInteger(v.idleMs) && v.idleMs >= 0)) {
|
|
210
|
+
bad("idleMs", "a non-negative integer");
|
|
211
|
+
}
|
|
212
|
+
if (v.readySelector !== void 0 && !(typeof v.readySelector === "string" && v.readySelector.trim() !== "")) {
|
|
213
|
+
bad("readySelector", "a non-empty string");
|
|
214
|
+
}
|
|
215
|
+
if (v.onTimeout !== void 0 && v.onTimeout !== "fail" && v.onTimeout !== "snapshot") {
|
|
216
|
+
bad("onTimeout", '"fail" or "snapshot"');
|
|
217
|
+
}
|
|
218
|
+
if (v.syncResources !== void 0 && !isSyncResources(v.syncResources)) bad("syncResources", "a resources object");
|
|
219
|
+
return o;
|
|
220
|
+
}
|
|
199
221
|
async function runRenderChild() {
|
|
200
222
|
const send = (m) => process.send(m);
|
|
201
|
-
const options =
|
|
223
|
+
const options = parseChildOptions(process.env[CHILD_OPTIONS_ENV] ?? "{}");
|
|
202
224
|
const allow = createAllowList();
|
|
203
225
|
for (const o of [...options.localOrigins ?? [], ...options.allowOrigins ?? []]) allowOrigin(allow, o);
|
|
204
226
|
containNetwork(allow);
|
|
205
|
-
const { createHappyDomRenderer } = await import("./happyDom-
|
|
227
|
+
const { createHappyDomRenderer } = await import("./happyDom-WTYQ5UAC.js");
|
|
206
228
|
const renderer = createHappyDomRenderer(options);
|
|
207
229
|
process.on("message", (m) => {
|
|
208
230
|
if (m.type === "resources") {
|
|
@@ -241,5 +263,6 @@ export {
|
|
|
241
263
|
CHILD_ENTRY,
|
|
242
264
|
CHILD_ENV,
|
|
243
265
|
CHILD_OPTIONS_ENV,
|
|
244
|
-
isSyncResources
|
|
266
|
+
isSyncResources,
|
|
267
|
+
parseChildOptions
|
|
245
268
|
};
|
package/dist/vite.d.ts
CHANGED
|
@@ -80,10 +80,43 @@ interface PrerenderOptions {
|
|
|
80
80
|
isolation?: {
|
|
81
81
|
codeGeneration?: boolean;
|
|
82
82
|
};
|
|
83
|
+
/**
|
|
84
|
+
* Where each route's HTML is written. "directory": "/about" -> about/index.html.
|
|
85
|
+
* "flat": "/about" -> about.html ("/" stays index.html). Default "directory".
|
|
86
|
+
*/
|
|
87
|
+
fileLayout?: FileLayout;
|
|
88
|
+
/**
|
|
89
|
+
* CSS selector that marks a route as rendered: the page is ready once it matches and no request
|
|
90
|
+
* is in flight, even if the DOM keeps changing (animations). Default: wait for the DOM to go quiet.
|
|
91
|
+
*/
|
|
92
|
+
readySelector?: string;
|
|
93
|
+
/**
|
|
94
|
+
* What to do when a route is not ready by `timeoutMs`. "fail" stops the build; "snapshot" saves the
|
|
95
|
+
* page as it is at the deadline and logs a warning. Default "fail".
|
|
96
|
+
*/
|
|
97
|
+
onTimeout?: "fail" | "snapshot";
|
|
83
98
|
}
|
|
99
|
+
type FileLayout = "directory" | "flat";
|
|
100
|
+
/** What `markdown.transform` receives for each page. */
|
|
101
|
+
interface MarkdownTransformPage {
|
|
102
|
+
/** Route path, e.g. "/about". */
|
|
103
|
+
route: string;
|
|
104
|
+
/** Absolute URL of the page. */
|
|
105
|
+
url: string;
|
|
106
|
+
title: string;
|
|
107
|
+
description?: string;
|
|
108
|
+
/** The generated markdown. */
|
|
109
|
+
markdown: string;
|
|
110
|
+
/** The page's full rendered HTML. */
|
|
111
|
+
html: string;
|
|
112
|
+
}
|
|
113
|
+
/** Returns the markdown to use instead, or undefined to keep the generated one. */
|
|
114
|
+
type MarkdownTransform = (page: MarkdownTransformPage) => string | undefined | Promise<string | undefined>;
|
|
84
115
|
interface MarkdownOptions {
|
|
85
116
|
/** CSS selector for the page content converted to markdown. Default "main". */
|
|
86
117
|
contentSelector?: string;
|
|
118
|
+
/** Rewrites each page's markdown (used for the .md file and llms-full.txt). */
|
|
119
|
+
transform?: MarkdownTransform;
|
|
87
120
|
}
|
|
88
121
|
interface LlmsOptions {
|
|
89
122
|
/** llms.txt heading. Default: the title of "/". */
|
|
@@ -92,6 +125,59 @@ interface LlmsOptions {
|
|
|
92
125
|
description?: string;
|
|
93
126
|
}
|
|
94
127
|
|
|
128
|
+
interface GenerateOptions {
|
|
129
|
+
/** Build output directory holding the prerendered HTML, e.g. "dist". */
|
|
130
|
+
outDir: string;
|
|
131
|
+
/** Absolute http(s) URL of the deployed site. */
|
|
132
|
+
siteUrl: string;
|
|
133
|
+
/** robots.txt policy. `ai.training` and `ai.search` are required. */
|
|
134
|
+
robots: WebForAgentsOptions["robots"];
|
|
135
|
+
/** Routes to leave out. A string is an exact path, or a prefix when it ends in "/*". */
|
|
136
|
+
exclude?: Array<string | RegExp>;
|
|
137
|
+
/** Write sitemap.xml and the `Sitemap:` line in robots.txt. Default true. */
|
|
138
|
+
sitemap?: boolean;
|
|
139
|
+
/** Write a `.md` version of each page. `false` also turns off llms-full.txt. */
|
|
140
|
+
markdown?: MarkdownOptions | false;
|
|
141
|
+
/** Write llms.txt and llms-full.txt. Default on. */
|
|
142
|
+
llms?: LlmsOptions | false;
|
|
143
|
+
/** Write agents.json from the actions in each page's markup. Default true. */
|
|
144
|
+
agentMap?: boolean | AgentMapOptions;
|
|
145
|
+
/** Add `<link rel="alternate" type="text/markdown">` to each page's head. Default true. */
|
|
146
|
+
linkMarkdown?: boolean;
|
|
147
|
+
/** Replace an existing robots.txt, sitemap.xml, llms.txt, llms-full.txt or agent map that differs. Default false. */
|
|
148
|
+
overwrite?: boolean;
|
|
149
|
+
/** Where warnings and the summary go. Default console. */
|
|
150
|
+
logger?: {
|
|
151
|
+
warn(message: string): void;
|
|
152
|
+
info(message: string): void;
|
|
153
|
+
};
|
|
154
|
+
}
|
|
155
|
+
interface GeneratedPage {
|
|
156
|
+
route: string;
|
|
157
|
+
/** HTML file, relative to outDir, with "/" separators. */
|
|
158
|
+
file: string;
|
|
159
|
+
/** False for noindex pages: they get a .md file but stay out of llms.txt, the sitemap and the agent map. */
|
|
160
|
+
listed: boolean;
|
|
161
|
+
}
|
|
162
|
+
interface GenerateResult {
|
|
163
|
+
outDir: string;
|
|
164
|
+
/** "flat" (about.html), "directory" (about/index.html), or "mixed". Only "/" found counts as "directory". */
|
|
165
|
+
fileLayout: "directory" | "flat" | "mixed";
|
|
166
|
+
/** Sorted by route. */
|
|
167
|
+
pages: GeneratedPage[];
|
|
168
|
+
/** Files written, relative to outDir, sorted. */
|
|
169
|
+
written: string[];
|
|
170
|
+
/** Existing files that were kept because their content differs (see `overwrite`), sorted. */
|
|
171
|
+
kept: string[];
|
|
172
|
+
warnings: string[];
|
|
173
|
+
}
|
|
174
|
+
/**
|
|
175
|
+
* Writes llms.txt, llms-full.txt, a `.md` copy of each page, robots.txt, sitemap.xml and agents.json
|
|
176
|
+
* for HTML you prerendered yourself, and links each page to its markdown. Reads every `.html`
|
|
177
|
+
* under outDir except 200.html, 404.html and assets/. Nothing is written if any step fails.
|
|
178
|
+
*/
|
|
179
|
+
declare function generateAgentFiles(options: GenerateOptions): Promise<GenerateResult>;
|
|
180
|
+
|
|
95
181
|
/** Known AI crawler user agents, grouped by robots.ai policy. */
|
|
96
182
|
declare const AI_BOTS: {
|
|
97
183
|
training: readonly string[];
|
|
@@ -104,5 +190,5 @@ declare const AI_BOTS: {
|
|
|
104
190
|
*/
|
|
105
191
|
declare function webForAgents(options: WebForAgentsOptions): Plugin[];
|
|
106
192
|
|
|
107
|
-
export { AI_BOTS, webForAgents };
|
|
108
|
-
export type { AgentMapOptions, LlmsOptions, MarkdownOptions, OverlayPluginOptions, PrerenderOptions, RendererName, Rule, WebForAgentsOptions };
|
|
193
|
+
export { AI_BOTS, generateAgentFiles, webForAgents };
|
|
194
|
+
export type { AgentMapOptions, FileLayout, GenerateOptions, GenerateResult, GeneratedPage, LlmsOptions, MarkdownOptions, MarkdownTransform, MarkdownTransformPage, OverlayPluginOptions, PrerenderOptions, RendererName, Rule, WebForAgentsOptions };
|