web-skill 0.1.0 → 0.1.1
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 +20 -2
- package/dist/chunk-YVQDAY47.js +305 -0
- package/dist/chunk-YVQDAY47.js.map +1 -0
- package/dist/index.d.ts +18 -0
- package/{src/runtime.ts → dist/index.js} +41 -94
- package/dist/index.js.map +1 -0
- package/dist/vite-plugin-5xZLBPsq.d.ts +71 -0
- package/dist/vite-plugin.d.ts +3 -0
- package/dist/vite-plugin.js +3 -0
- package/dist/vite-plugin.js.map +1 -0
- package/docs/api.md +121 -0
- package/package.json +30 -8
- package/src/index.ts +0 -20
- package/src/markdown.ts +0 -230
- package/src/types.ts +0 -89
- package/src/utils.ts +0 -90
- package/src/vite-plugin.ts +0 -91
package/README.md
CHANGED
|
@@ -8,7 +8,9 @@ From one shared config it can:
|
|
|
8
8
|
- generate one `SKILL.md` file per published skill
|
|
9
9
|
- inject `<link rel="web-skill" ...>` tags into the HTML `<head>` through Vite
|
|
10
10
|
|
|
11
|
-
The package is
|
|
11
|
+
The package is TypeScript-first and works best in apps that already use Vite and Zod.
|
|
12
|
+
|
|
13
|
+
Status: early, but installable. The package now ships compiled `dist/` output, basic automated tests, and a small API reference so adopters do not need to compile TypeScript source themselves just to try it.
|
|
12
14
|
|
|
13
15
|
## Install
|
|
14
16
|
|
|
@@ -154,6 +156,10 @@ Each generated `SKILL.md` contains:
|
|
|
154
156
|
|
|
155
157
|
The repository also includes [`skills/use-web-skill/SKILL.md`](./skills/use-web-skill/SKILL.md), a discovery workflow for agents that inspect `<head>` before automating a page.
|
|
156
158
|
|
|
159
|
+
## API reference
|
|
160
|
+
|
|
161
|
+
For the exported surface, expected behaviors, and common runtime errors, see [`docs/api.md`](./docs/api.md).
|
|
162
|
+
|
|
157
163
|
## Design guidance
|
|
158
164
|
|
|
159
165
|
`web-skill` works best when you expose task-level actions instead of raw UI primitives.
|
|
@@ -182,11 +188,23 @@ Treat destructive actions as special cases:
|
|
|
182
188
|
- return structured results instead of relying on toast text
|
|
183
189
|
- avoid exposing unstable internal helpers just because they are easy to call
|
|
184
190
|
|
|
191
|
+
## Authorization guidance
|
|
192
|
+
|
|
193
|
+
`web-skill` does not enforce authorization by itself. The recommended model is for the application to decide which skill documents and runtime functions are exposed in the current session.
|
|
194
|
+
|
|
195
|
+
Typical patterns:
|
|
196
|
+
|
|
197
|
+
- only render admin-only `<link rel="web-skill" ...>` tags for admin users
|
|
198
|
+
- serve different skill documents for different audiences such as `/admin-only/SKILL.md` and `/user/SKILL.md`
|
|
199
|
+
- keep backend APIs as the final authorization boundary even if a browser skill becomes visible
|
|
200
|
+
|
|
201
|
+
If your agent flow benefits from advisory hints, prefer putting that information directly in the visible skill description or link title. For example, titles and descriptions such as `Admin-only order approval API` are often enough to help agents choose the right skill without adding new package-level permission features.
|
|
202
|
+
|
|
185
203
|
## Local development
|
|
186
204
|
|
|
187
205
|
```bash
|
|
188
206
|
npm install
|
|
189
|
-
npm run
|
|
207
|
+
npm run verify
|
|
190
208
|
```
|
|
191
209
|
|
|
192
210
|
## License
|
|
@@ -0,0 +1,305 @@
|
|
|
1
|
+
// src/markdown.ts
|
|
2
|
+
var INDENT = " ";
|
|
3
|
+
function generateSkillMarkdown(skill) {
|
|
4
|
+
const description = skill.description ?? `Expose browser-callable functions under \`window._web_skills.${skill.key}\`.`;
|
|
5
|
+
const lines = [
|
|
6
|
+
"---",
|
|
7
|
+
`name: ${skill.slug}`,
|
|
8
|
+
`description: ${escapeFrontmatterValue(description)}`,
|
|
9
|
+
"---",
|
|
10
|
+
"",
|
|
11
|
+
`# ${skill.title}`,
|
|
12
|
+
"",
|
|
13
|
+
"Use the browser console entrypoint:",
|
|
14
|
+
"",
|
|
15
|
+
"```js",
|
|
16
|
+
`window._web_skills.${skill.key}`,
|
|
17
|
+
"```",
|
|
18
|
+
"",
|
|
19
|
+
"Available functions:",
|
|
20
|
+
""
|
|
21
|
+
];
|
|
22
|
+
for (const definition of skill.functions) {
|
|
23
|
+
lines.push(...renderFunctionSection(skill, definition), "");
|
|
24
|
+
}
|
|
25
|
+
return `${lines.join("\n").trimEnd()}
|
|
26
|
+
`;
|
|
27
|
+
}
|
|
28
|
+
function renderFunctionSection(skill, definition) {
|
|
29
|
+
const inputSchema = definition.inputSchema ? renderZodSchema(definition.inputSchema) : "unknown";
|
|
30
|
+
const outputSchema = definition.outputSchema ? renderZodSchema(definition.outputSchema) : "unknown";
|
|
31
|
+
return [
|
|
32
|
+
`## \`${definition.name}(input)\``,
|
|
33
|
+
"",
|
|
34
|
+
`Purpose: ${definition.description ?? `Invoke \`window._web_skills.${skill.key}.${definition.name}(input)\`.`}`,
|
|
35
|
+
"",
|
|
36
|
+
"Input:",
|
|
37
|
+
"",
|
|
38
|
+
"```ts",
|
|
39
|
+
inputSchema,
|
|
40
|
+
"```",
|
|
41
|
+
"",
|
|
42
|
+
"Output:",
|
|
43
|
+
"",
|
|
44
|
+
"```ts",
|
|
45
|
+
outputSchema,
|
|
46
|
+
"```"
|
|
47
|
+
];
|
|
48
|
+
}
|
|
49
|
+
function renderZodSchema(schema) {
|
|
50
|
+
return renderSchema(schema, 0);
|
|
51
|
+
}
|
|
52
|
+
function renderSchema(schema, depth) {
|
|
53
|
+
const definition = getDefinition(schema);
|
|
54
|
+
const typeName = definition?.typeName;
|
|
55
|
+
switch (typeName) {
|
|
56
|
+
case "ZodString":
|
|
57
|
+
return "string";
|
|
58
|
+
case "ZodNumber":
|
|
59
|
+
return "number";
|
|
60
|
+
case "ZodBoolean":
|
|
61
|
+
return "boolean";
|
|
62
|
+
case "ZodBigInt":
|
|
63
|
+
return "bigint";
|
|
64
|
+
case "ZodDate":
|
|
65
|
+
return "Date";
|
|
66
|
+
case "ZodUndefined":
|
|
67
|
+
return "undefined";
|
|
68
|
+
case "ZodNull":
|
|
69
|
+
return "null";
|
|
70
|
+
case "ZodVoid":
|
|
71
|
+
return "void";
|
|
72
|
+
case "ZodAny":
|
|
73
|
+
return "any";
|
|
74
|
+
case "ZodUnknown":
|
|
75
|
+
return "unknown";
|
|
76
|
+
case "ZodNever":
|
|
77
|
+
return "never";
|
|
78
|
+
case "ZodLiteral":
|
|
79
|
+
return JSON.stringify(definition?.value);
|
|
80
|
+
case "ZodEnum":
|
|
81
|
+
return Array.isArray(definition?.values) ? definition.values.map((value) => JSON.stringify(value)).join(" | ") : "string";
|
|
82
|
+
case "ZodNativeEnum":
|
|
83
|
+
return renderNativeEnum(
|
|
84
|
+
definition?.values && typeof definition.values === "object" ? definition.values : void 0
|
|
85
|
+
);
|
|
86
|
+
case "ZodArray":
|
|
87
|
+
return `${wrapType(renderSchema(definition?.type, depth))}[]`;
|
|
88
|
+
case "ZodOptional":
|
|
89
|
+
return `${renderSchema(definition?.innerType, depth)} | undefined`;
|
|
90
|
+
case "ZodNullable":
|
|
91
|
+
return `${renderSchema(definition?.innerType, depth)} | null`;
|
|
92
|
+
case "ZodDefault":
|
|
93
|
+
case "ZodCatch":
|
|
94
|
+
return renderSchema(definition?.innerType, depth);
|
|
95
|
+
case "ZodEffects":
|
|
96
|
+
return renderSchema(definition?.schema, depth);
|
|
97
|
+
case "ZodBranded":
|
|
98
|
+
return renderSchema(definition?.type, depth);
|
|
99
|
+
case "ZodUnion":
|
|
100
|
+
return Array.isArray(definition?.options) ? definition.options.map((option) => wrapType(renderSchema(option, depth))).join(" | ") : "unknown";
|
|
101
|
+
case "ZodDiscriminatedUnion":
|
|
102
|
+
return Array.from(
|
|
103
|
+
definition?.options instanceof Map ? definition.options.values() : []
|
|
104
|
+
).map((option) => wrapType(renderSchema(option, depth))).join(" | ");
|
|
105
|
+
case "ZodIntersection":
|
|
106
|
+
return `${wrapType(renderSchema(definition?.left, depth))} & ${wrapType(renderSchema(definition?.right, depth))}`;
|
|
107
|
+
case "ZodTuple":
|
|
108
|
+
return `[${Array.isArray(definition?.items) ? definition.items.map((item) => renderSchema(item, depth)).join(", ") : ""}]`;
|
|
109
|
+
case "ZodRecord":
|
|
110
|
+
return `Record<${renderRecordKey(definition?.keyType)}, ${renderSchema(definition?.valueType, depth)}>`;
|
|
111
|
+
case "ZodObject":
|
|
112
|
+
return renderObjectSchema(schema, depth);
|
|
113
|
+
case "ZodLazy":
|
|
114
|
+
return typeof definition?.getter === "function" ? renderSchema(definition.getter(), depth) : "unknown";
|
|
115
|
+
default:
|
|
116
|
+
return "unknown";
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
function renderObjectSchema(schema, depth) {
|
|
120
|
+
const definition = getDefinition(schema);
|
|
121
|
+
const shapeSource = definition?.shape;
|
|
122
|
+
const shape = typeof shapeSource === "function" ? shapeSource() : shapeSource ?? {};
|
|
123
|
+
const entries = Object.entries(shape);
|
|
124
|
+
if (entries.length === 0) {
|
|
125
|
+
return "{}";
|
|
126
|
+
}
|
|
127
|
+
const propertyLines = entries.map(([key, propertySchema]) => {
|
|
128
|
+
const optional = isOptionalSchema(propertySchema);
|
|
129
|
+
const renderedType = renderSchema(optional ? unwrapOptionalSchema(propertySchema) : propertySchema, depth + 1);
|
|
130
|
+
return `${indent(depth + 1)}${quotePropertyKey(key)}${optional ? "?" : ""}: ${renderedType};`;
|
|
131
|
+
});
|
|
132
|
+
return ["{", ...propertyLines, `${indent(depth)}}`].join("\n");
|
|
133
|
+
}
|
|
134
|
+
function renderNativeEnum(values) {
|
|
135
|
+
if (!values) {
|
|
136
|
+
return "string | number";
|
|
137
|
+
}
|
|
138
|
+
const rendered = Array.from(
|
|
139
|
+
new Set(
|
|
140
|
+
Object.values(values).filter(
|
|
141
|
+
(value) => typeof value === "string" || typeof value === "number"
|
|
142
|
+
)
|
|
143
|
+
)
|
|
144
|
+
);
|
|
145
|
+
return rendered.map((value) => JSON.stringify(value)).join(" | ") || "string | number";
|
|
146
|
+
}
|
|
147
|
+
function renderRecordKey(keyType) {
|
|
148
|
+
if (!keyType) {
|
|
149
|
+
return "string";
|
|
150
|
+
}
|
|
151
|
+
return renderSchema(keyType, 0);
|
|
152
|
+
}
|
|
153
|
+
function isOptionalSchema(schema) {
|
|
154
|
+
return typeof schema.isOptional === "function" ? schema.isOptional() : getDefinition(schema)?.typeName === "ZodOptional";
|
|
155
|
+
}
|
|
156
|
+
function unwrapOptionalSchema(schema) {
|
|
157
|
+
const definition = getDefinition(schema);
|
|
158
|
+
if (definition?.typeName === "ZodOptional") {
|
|
159
|
+
return definition.innerType;
|
|
160
|
+
}
|
|
161
|
+
return schema;
|
|
162
|
+
}
|
|
163
|
+
function wrapType(value) {
|
|
164
|
+
return /[|&\n]/u.test(value) ? `(${value})` : value;
|
|
165
|
+
}
|
|
166
|
+
function quotePropertyKey(value) {
|
|
167
|
+
return /^[A-Za-z_$][A-Za-z0-9_$]*$/u.test(value) ? value : JSON.stringify(value);
|
|
168
|
+
}
|
|
169
|
+
function indent(depth) {
|
|
170
|
+
return INDENT.repeat(depth);
|
|
171
|
+
}
|
|
172
|
+
function getDefinition(schema) {
|
|
173
|
+
return schema._def;
|
|
174
|
+
}
|
|
175
|
+
function escapeFrontmatterValue(value) {
|
|
176
|
+
return JSON.stringify(value);
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
// src/utils.ts
|
|
180
|
+
var NON_ALPHANUMERIC_PATTERN = /[^a-zA-Z0-9]+/gu;
|
|
181
|
+
var TRIM_DASHES_PATTERN = /^-+|-+$/gu;
|
|
182
|
+
var CAMEL_BOUNDARY_PATTERN = /[-_\s]+([a-zA-Z0-9])/gu;
|
|
183
|
+
var NON_IDENTIFIER_PATTERN = /[^a-zA-Z0-9_$]/gu;
|
|
184
|
+
var LEADING_INVALID_IDENTIFIER_PATTERN = /^[^a-zA-Z_$]+/u;
|
|
185
|
+
function slugifySkillSegment(value) {
|
|
186
|
+
const normalized = value.trim().replace(NON_ALPHANUMERIC_PATTERN, "-").replace(TRIM_DASHES_PATTERN, "").toLowerCase();
|
|
187
|
+
return normalized || "web-skill";
|
|
188
|
+
}
|
|
189
|
+
function toSkillKey(value) {
|
|
190
|
+
const identifier = value.trim().replace(CAMEL_BOUNDARY_PATTERN, (_match, character) => character.toUpperCase()).replace(NON_IDENTIFIER_PATTERN, "").replace(LEADING_INVALID_IDENTIFIER_PATTERN, "");
|
|
191
|
+
if (!identifier) {
|
|
192
|
+
return "webSkill";
|
|
193
|
+
}
|
|
194
|
+
return identifier[0].toLowerCase() + identifier.slice(1);
|
|
195
|
+
}
|
|
196
|
+
function titleFromName(value) {
|
|
197
|
+
const normalized = value.replace(/([a-z0-9])([A-Z])/gu, "$1 $2").replace(/[-_]+/gu, " ").trim();
|
|
198
|
+
if (!normalized) {
|
|
199
|
+
return "Web Skill";
|
|
200
|
+
}
|
|
201
|
+
return normalized.split(/\s+/u).map((part) => part[0].toUpperCase() + part.slice(1)).join(" ");
|
|
202
|
+
}
|
|
203
|
+
function ensureUniqueString(value, used, formatter = (index) => `${value}-${index + 1}`) {
|
|
204
|
+
if (!used.has(value)) {
|
|
205
|
+
used.add(value);
|
|
206
|
+
return value;
|
|
207
|
+
}
|
|
208
|
+
let index = 1;
|
|
209
|
+
while (true) {
|
|
210
|
+
const nextValue = formatter(index);
|
|
211
|
+
if (!used.has(nextValue)) {
|
|
212
|
+
used.add(nextValue);
|
|
213
|
+
return nextValue;
|
|
214
|
+
}
|
|
215
|
+
index += 1;
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
function joinBasePath(basePath, relativePath) {
|
|
219
|
+
const normalizedBase = (basePath ?? "/").trim();
|
|
220
|
+
const base = normalizedBase === "/" ? "" : `/${normalizedBase.replace(/^\/+|\/+$/gu, "")}`;
|
|
221
|
+
const path = relativePath.startsWith("/") ? relativePath : `/${relativePath}`;
|
|
222
|
+
return `${base}${path}`;
|
|
223
|
+
}
|
|
224
|
+
function toSkillMarkdownAssetPath(skill) {
|
|
225
|
+
return `/skills/${skill.slug}/SKILL.md`;
|
|
226
|
+
}
|
|
227
|
+
function buildWebSkillLinkTags(skills, basePath) {
|
|
228
|
+
return skills.map((skill) => ({
|
|
229
|
+
href: joinBasePath(basePath, toSkillMarkdownAssetPath(skill)),
|
|
230
|
+
title: skill.title,
|
|
231
|
+
type: "text/markdown"
|
|
232
|
+
}));
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
// src/vite-plugin.ts
|
|
236
|
+
function webSkillVitePlugin(options) {
|
|
237
|
+
let resolvedConfig = null;
|
|
238
|
+
return {
|
|
239
|
+
name: "web-skill",
|
|
240
|
+
configResolved(config) {
|
|
241
|
+
resolvedConfig = config;
|
|
242
|
+
},
|
|
243
|
+
configureServer(server) {
|
|
244
|
+
server.middlewares.use((request, response, next) => {
|
|
245
|
+
if (!resolvedConfig) {
|
|
246
|
+
next();
|
|
247
|
+
return;
|
|
248
|
+
}
|
|
249
|
+
if (!tryServeGeneratedSkillMarkdown(
|
|
250
|
+
request,
|
|
251
|
+
response,
|
|
252
|
+
options.generator.getSkills(),
|
|
253
|
+
options.publicBasePath ?? resolvedConfig.base
|
|
254
|
+
)) {
|
|
255
|
+
next();
|
|
256
|
+
}
|
|
257
|
+
});
|
|
258
|
+
},
|
|
259
|
+
generateBundle() {
|
|
260
|
+
for (const skill of options.generator.getSkills()) {
|
|
261
|
+
this.emitFile({
|
|
262
|
+
fileName: `skills/${skill.slug}/SKILL.md`,
|
|
263
|
+
source: generateSkillMarkdown(skill),
|
|
264
|
+
type: "asset"
|
|
265
|
+
});
|
|
266
|
+
}
|
|
267
|
+
},
|
|
268
|
+
transformIndexHtml() {
|
|
269
|
+
const tags = buildWebSkillLinkTags(
|
|
270
|
+
options.generator.getSkills(),
|
|
271
|
+
options.publicBasePath ?? resolvedConfig?.base ?? "/"
|
|
272
|
+
);
|
|
273
|
+
return tags.map((tag) => ({
|
|
274
|
+
tag: "link",
|
|
275
|
+
attrs: {
|
|
276
|
+
rel: "web-skill",
|
|
277
|
+
href: tag.href,
|
|
278
|
+
title: tag.title,
|
|
279
|
+
type: tag.type
|
|
280
|
+
},
|
|
281
|
+
injectTo: "head"
|
|
282
|
+
}));
|
|
283
|
+
}
|
|
284
|
+
};
|
|
285
|
+
}
|
|
286
|
+
function tryServeGeneratedSkillMarkdown(request, response, skills, basePath) {
|
|
287
|
+
const requestUrl = request.url;
|
|
288
|
+
if (!requestUrl) {
|
|
289
|
+
return false;
|
|
290
|
+
}
|
|
291
|
+
const pathname = new URL(requestUrl, "http://localhost").pathname;
|
|
292
|
+
const tags = buildWebSkillLinkTags(skills, basePath);
|
|
293
|
+
const matchedIndex = tags.findIndex((tag) => tag.href === pathname);
|
|
294
|
+
if (matchedIndex === -1) {
|
|
295
|
+
return false;
|
|
296
|
+
}
|
|
297
|
+
response.statusCode = 200;
|
|
298
|
+
response.setHeader("Content-Type", "text/markdown; charset=utf-8");
|
|
299
|
+
response.end(generateSkillMarkdown(skills[matchedIndex]));
|
|
300
|
+
return true;
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
export { buildWebSkillLinkTags, ensureUniqueString, generateSkillMarkdown, renderZodSchema, slugifySkillSegment, titleFromName, toSkillKey, webSkillVitePlugin };
|
|
304
|
+
//# sourceMappingURL=chunk-YVQDAY47.js.map
|
|
305
|
+
//# sourceMappingURL=chunk-YVQDAY47.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/markdown.ts","../src/utils.ts","../src/vite-plugin.ts"],"names":[],"mappings":";AAIA,IAAM,MAAA,GAAS,IAAA;AAOR,SAAS,sBAAsB,KAAA,EAA2C;AAC/E,EAAA,MAAM,WAAA,GACJ,KAAA,CAAM,WAAA,IACH,CAAA,6DAAA,EAAgE,MAAM,GAAG,CAAA,GAAA,CAAA;AAE9E,EAAA,MAAM,KAAA,GAAkB;AAAA,IACtB,KAAA;AAAA,IACA,CAAA,MAAA,EAAS,MAAM,IAAI,CAAA,CAAA;AAAA,IACnB,CAAA,aAAA,EAAgB,sBAAA,CAAuB,WAAW,CAAC,CAAA,CAAA;AAAA,IACnD,KAAA;AAAA,IACA,EAAA;AAAA,IACA,CAAA,EAAA,EAAK,MAAM,KAAK,CAAA,CAAA;AAAA,IAChB,EAAA;AAAA,IACA,qCAAA;AAAA,IACA,EAAA;AAAA,IACA,OAAA;AAAA,IACA,CAAA,mBAAA,EAAsB,MAAM,GAAG,CAAA,CAAA;AAAA,IAC/B,KAAA;AAAA,IACA,EAAA;AAAA,IACA,sBAAA;AAAA,IACA;AAAA,GACF;AAEA,EAAA,KAAA,MAAW,UAAA,IAAc,MAAM,SAAA,EAAW;AACxC,IAAA,KAAA,CAAM,KAAK,GAAG,qBAAA,CAAsB,KAAA,EAAO,UAAU,GAAG,EAAE,CAAA;AAAA,EAC5D;AAEA,EAAA,OAAO,GAAG,KAAA,CAAM,IAAA,CAAK,IAAI,CAAA,CAAE,SAAS;AAAA,CAAA;AACtC;AAEA,SAAS,qBAAA,CACP,OACA,UAAA,EACU;AACV,EAAA,MAAM,cAAc,UAAA,CAAW,WAAA,GAAc,eAAA,CAAgB,UAAA,CAAW,WAAW,CAAA,GAAI,SAAA;AACvF,EAAA,MAAM,eAAe,UAAA,CAAW,YAAA,GAAe,eAAA,CAAgB,UAAA,CAAW,YAAY,CAAA,GAAI,SAAA;AAE1F,EAAA,OAAO;AAAA,IACL,CAAA,KAAA,EAAQ,WAAW,IAAI,CAAA,SAAA,CAAA;AAAA,IACvB,EAAA;AAAA,IACA,CAAA,SAAA,EAAY,WAAW,WAAA,IAAe,CAAA,4BAAA,EAA+B,MAAM,GAAG,CAAA,CAAA,EAAI,UAAA,CAAW,IAAI,CAAA,UAAA,CAAY,CAAA,CAAA;AAAA,IAC7G,EAAA;AAAA,IACA,QAAA;AAAA,IACA,EAAA;AAAA,IACA,OAAA;AAAA,IACA,WAAA;AAAA,IACA,KAAA;AAAA,IACA,EAAA;AAAA,IACA,SAAA;AAAA,IACA,EAAA;AAAA,IACA,OAAA;AAAA,IACA,YAAA;AAAA,IACA;AAAA,GACF;AACF;AAEO,SAAS,gBAAgB,MAAA,EAA4B;AAC1D,EAAA,OAAO,YAAA,CAAa,QAAQ,CAAC,CAAA;AAC/B;AAEA,SAAS,YAAA,CAAa,QAAoB,KAAA,EAAuB;AAC/D,EAAA,MAAM,UAAA,GAAa,cAAc,MAAM,CAAA;AACvC,EAAA,MAAM,WAAW,UAAA,EAAY,QAAA;AAE7B,EAAA,QAAQ,QAAA;AAAU,IAChB,KAAK,WAAA;AACH,MAAA,OAAO,QAAA;AAAA,IACT,KAAK,WAAA;AACH,MAAA,OAAO,QAAA;AAAA,IACT,KAAK,YAAA;AACH,MAAA,OAAO,SAAA;AAAA,IACT,KAAK,WAAA;AACH,MAAA,OAAO,QAAA;AAAA,IACT,KAAK,SAAA;AACH,MAAA,OAAO,MAAA;AAAA,IACT,KAAK,cAAA;AACH,MAAA,OAAO,WAAA;AAAA,IACT,KAAK,SAAA;AACH,MAAA,OAAO,MAAA;AAAA,IACT,KAAK,SAAA;AACH,MAAA,OAAO,MAAA;AAAA,IACT,KAAK,QAAA;AACH,MAAA,OAAO,KAAA;AAAA,IACT,KAAK,YAAA;AACH,MAAA,OAAO,SAAA;AAAA,IACT,KAAK,UAAA;AACH,MAAA,OAAO,OAAA;AAAA,IACT,KAAK,YAAA;AACH,MAAA,OAAO,IAAA,CAAK,SAAA,CAAU,UAAA,EAAY,KAAK,CAAA;AAAA,IACzC,KAAK,SAAA;AACH,MAAA,OAAO,MAAM,OAAA,CAAQ,UAAA,EAAY,MAAM,CAAA,GACnC,WAAW,MAAA,CAAO,GAAA,CAAI,CAAC,KAAA,KAAU,KAAK,SAAA,CAAU,KAAK,CAAC,CAAA,CAAE,IAAA,CAAK,KAAK,CAAA,GAClE,QAAA;AAAA,IACN,KAAK,eAAA;AACH,MAAA,OAAO,gBAAA;AAAA,QACL,YAAY,MAAA,IAAU,OAAO,WAAW,MAAA,KAAW,QAAA,GAC9C,WAAW,MAAA,GACZ;AAAA,OACN;AAAA,IACF,KAAK,UAAA;AACH,MAAA,OAAO,GAAG,QAAA,CAAS,YAAA,CAAa,YAAY,IAAA,EAAoB,KAAK,CAAC,CAAC,CAAA,EAAA,CAAA;AAAA,IACzE,KAAK,aAAA;AACH,MAAA,OAAO,CAAA,EAAG,YAAA,CAAa,UAAA,EAAY,SAAA,EAAyB,KAAK,CAAC,CAAA,YAAA,CAAA;AAAA,IACpE,KAAK,aAAA;AACH,MAAA,OAAO,CAAA,EAAG,YAAA,CAAa,UAAA,EAAY,SAAA,EAAyB,KAAK,CAAC,CAAA,OAAA,CAAA;AAAA,IACpE,KAAK,YAAA;AAAA,IACL,KAAK,UAAA;AACH,MAAA,OAAO,YAAA,CAAa,UAAA,EAAY,SAAA,EAAyB,KAAK,CAAA;AAAA,IAChE,KAAK,YAAA;AACH,MAAA,OAAO,YAAA,CAAa,UAAA,EAAY,MAAA,EAAsB,KAAK,CAAA;AAAA,IAC7D,KAAK,YAAA;AACH,MAAA,OAAO,YAAA,CAAa,UAAA,EAAY,IAAA,EAAoB,KAAK,CAAA;AAAA,IAC3D,KAAK,UAAA;AACH,MAAA,OAAO,MAAM,OAAA,CAAQ,UAAA,EAAY,OAAO,CAAA,GACpC,UAAA,CAAW,QAAQ,GAAA,CAAI,CAAC,WAAW,QAAA,CAAS,YAAA,CAAa,QAAsB,KAAK,CAAC,CAAC,CAAA,CAAE,IAAA,CAAK,KAAK,CAAA,GAClG,SAAA;AAAA,IACN,KAAK,uBAAA;AACH,MAAA,OAAO,KAAA,CAAM,IAAA;AAAA,QACX,YAAY,OAAA,YAAmB,GAAA,GAAM,WAAW,OAAA,CAAQ,MAAA,KAAW;AAAC,OACtE,CACG,GAAA,CAAI,CAAC,MAAA,KAAW,QAAA,CAAS,YAAA,CAAa,MAAA,EAAsB,KAAK,CAAC,CAAC,CAAA,CACnE,IAAA,CAAK,KAAK,CAAA;AAAA,IACf,KAAK,iBAAA;AACH,MAAA,OAAO,CAAA,EAAG,QAAA,CAAS,YAAA,CAAa,UAAA,EAAY,MAAoB,KAAK,CAAC,CAAC,CAAA,GAAA,EAAM,SAAS,YAAA,CAAa,UAAA,EAAY,KAAA,EAAqB,KAAK,CAAC,CAAC,CAAA,CAAA;AAAA,IAC7I,KAAK,UAAA;AACH,MAAA,OAAO,IAAI,KAAA,CAAM,OAAA,CAAQ,YAAY,KAAK,CAAA,GACtC,WAAW,KAAA,CAAM,GAAA,CAAI,CAAC,IAAA,KAAS,YAAA,CAAa,MAAoB,KAAK,CAAC,EAAE,IAAA,CAAK,IAAI,IACjF,EAAE,CAAA,CAAA,CAAA;AAAA,IACR,KAAK,WAAA;AACH,MAAA,OAAO,CAAA,OAAA,EAAU,eAAA,CAAgB,UAAA,EAAY,OAAiC,CAAC,KAAK,YAAA,CAAa,UAAA,EAAY,SAAA,EAAyB,KAAK,CAAC,CAAA,CAAA,CAAA;AAAA,IAC9I,KAAK,WAAA;AACH,MAAA,OAAO,kBAAA,CAAmB,QAAQ,KAAK,CAAA;AAAA,IACzC,KAAK,SAAA;AACH,MAAA,OAAO,OAAO,YAAY,MAAA,KAAW,UAAA,GACjC,aAAa,UAAA,CAAW,MAAA,EAAO,EAAiB,KAAK,CAAA,GACrD,SAAA;AAAA,IACN;AACE,MAAA,OAAO,SAAA;AAAA;AAEb;AAEA,SAAS,kBAAA,CAAmB,QAAoB,KAAA,EAAuB;AACrE,EAAA,MAAM,UAAA,GAAa,cAAc,MAAM,CAAA;AACvC,EAAA,MAAM,cAAc,UAAA,EAAY,KAAA;AAChC,EAAA,MAAM,QACJ,OAAO,WAAA,KAAgB,aAClB,WAAA,EAAY,GACX,eAAe,EAAC;AACxB,EAAA,MAAM,OAAA,GAAU,MAAA,CAAO,OAAA,CAAQ,KAAK,CAAA;AAEpC,EAAA,IAAI,OAAA,CAAQ,WAAW,CAAA,EAAG;AACxB,IAAA,OAAO,IAAA;AAAA,EACT;AAEA,EAAA,MAAM,gBAAgB,OAAA,CAAQ,GAAA,CAAI,CAAC,CAAC,GAAA,EAAK,cAAc,CAAA,KAAM;AAC3D,IAAA,MAAM,QAAA,GAAW,iBAAiB,cAAc,CAAA;AAChD,IAAA,MAAM,YAAA,GAAe,aAAa,QAAA,GAAW,oBAAA,CAAqB,cAAc,CAAA,GAAI,cAAA,EAAgB,QAAQ,CAAC,CAAA;AAC7G,IAAA,OAAO,CAAA,EAAG,MAAA,CAAO,KAAA,GAAQ,CAAC,CAAC,CAAA,EAAG,gBAAA,CAAiB,GAAG,CAAC,CAAA,EAAG,QAAA,GAAW,GAAA,GAAM,EAAE,KAAK,YAAY,CAAA,CAAA,CAAA;AAAA,EAC5F,CAAC,CAAA;AAED,EAAA,OAAO,CAAC,GAAA,EAAK,GAAG,aAAA,EAAe,CAAA,EAAG,MAAA,CAAO,KAAK,CAAC,CAAA,CAAA,CAAG,CAAA,CAAE,IAAA,CAAK,IAAI,CAAA;AAC/D;AAEA,SAAS,iBAAiB,MAAA,EAA6D;AACrF,EAAA,IAAI,CAAC,MAAA,EAAQ;AACX,IAAA,OAAO,iBAAA;AAAA,EACT;AAEA,EAAA,MAAM,WAAW,KAAA,CAAM,IAAA;AAAA,IACrB,IAAI,GAAA;AAAA,MACF,MAAA,CAAO,MAAA,CAAO,MAAM,CAAA,CAAE,MAAA;AAAA,QACpB,CAAC,KAAA,KAAoC,OAAO,KAAA,KAAU,QAAA,IAAY,OAAO,KAAA,KAAU;AAAA;AACrF;AACF,GACF;AAEA,EAAA,OAAO,QAAA,CAAS,GAAA,CAAI,CAAC,KAAA,KAAU,IAAA,CAAK,SAAA,CAAU,KAAK,CAAC,CAAA,CAAE,IAAA,CAAK,KAAK,CAAA,IAAK,iBAAA;AACvE;AAEA,SAAS,gBAAgB,OAAA,EAAyC;AAChE,EAAA,IAAI,CAAC,OAAA,EAAS;AACZ,IAAA,OAAO,QAAA;AAAA,EACT;AAEA,EAAA,OAAO,YAAA,CAAa,SAAS,CAAC,CAAA;AAChC;AAEA,SAAS,iBAAiB,MAAA,EAA6B;AACrD,EAAA,OAAO,OAAO,MAAA,CAAO,UAAA,KAAe,UAAA,GAAa,MAAA,CAAO,YAAW,GAAI,aAAA,CAAc,MAAM,CAAA,EAAG,QAAA,KAAa,aAAA;AAC7G;AAEA,SAAS,qBAAqB,MAAA,EAAgC;AAC5D,EAAA,MAAM,UAAA,GAAa,cAAc,MAAM,CAAA;AACvC,EAAA,IAAI,UAAA,EAAY,aAAa,aAAA,EAAe;AAC1C,IAAA,OAAO,UAAA,CAAW,SAAA;AAAA,EACpB;AAEA,EAAA,OAAO,MAAA;AACT;AAEA,SAAS,SAAS,KAAA,EAAuB;AACvC,EAAA,OAAO,UAAU,IAAA,CAAK,KAAK,CAAA,GAAI,CAAA,CAAA,EAAI,KAAK,CAAA,CAAA,CAAA,GAAM,KAAA;AAChD;AAEA,SAAS,iBAAiB,KAAA,EAAuB;AAC/C,EAAA,OAAO,8BAA8B,IAAA,CAAK,KAAK,IAAI,KAAA,GAAQ,IAAA,CAAK,UAAU,KAAK,CAAA;AACjF;AAEA,SAAS,OAAO,KAAA,EAAuB;AACrC,EAAA,OAAO,MAAA,CAAO,OAAO,KAAK,CAAA;AAC5B;AAEA,SAAS,cAAc,MAAA,EAAoD;AACzE,EAAA,OAAQ,MAAA,CAAoD,IAAA;AAC9D;AAEA,SAAS,uBAAuB,KAAA,EAAuB;AACrD,EAAA,OAAO,IAAA,CAAK,UAAU,KAAK,CAAA;AAC7B;;;ACnOA,IAAM,wBAAA,GAA2B,iBAAA;AACjC,IAAM,mBAAA,GAAsB,WAAA;AAC5B,IAAM,sBAAA,GAAyB,wBAAA;AAC/B,IAAM,sBAAA,GAAyB,kBAAA;AAC/B,IAAM,kCAAA,GAAqC,gBAAA;AAEpC,SAAS,oBAAoB,KAAA,EAAuB;AACzD,EAAA,MAAM,UAAA,GAAa,KAAA,CAChB,IAAA,EAAK,CACL,OAAA,CAAQ,wBAAA,EAA0B,GAAG,CAAA,CACrC,OAAA,CAAQ,mBAAA,EAAqB,EAAE,CAAA,CAC/B,WAAA,EAAY;AAEf,EAAA,OAAO,UAAA,IAAc,WAAA;AACvB;AAEO,SAAS,WAAW,KAAA,EAAuB;AAChD,EAAA,MAAM,aAAa,KAAA,CAChB,IAAA,GACA,OAAA,CAAQ,sBAAA,EAAwB,CAAC,MAAA,EAAQ,SAAA,KAAsB,UAAU,WAAA,EAAa,EACtF,OAAA,CAAQ,sBAAA,EAAwB,EAAE,CAAA,CAClC,OAAA,CAAQ,oCAAoC,EAAE,CAAA;AAEjD,EAAA,IAAI,CAAC,UAAA,EAAY;AACf,IAAA,OAAO,UAAA;AAAA,EACT;AAEA,EAAA,OAAO,WAAW,CAAC,CAAA,CAAG,aAAY,GAAI,UAAA,CAAW,MAAM,CAAC,CAAA;AAC1D;AAEO,SAAS,cAAc,KAAA,EAAuB;AACnD,EAAA,MAAM,UAAA,GAAa,KAAA,CAChB,OAAA,CAAQ,qBAAA,EAAuB,OAAO,EACtC,OAAA,CAAQ,SAAA,EAAW,GAAG,CAAA,CACtB,IAAA,EAAK;AAER,EAAA,IAAI,CAAC,UAAA,EAAY;AACf,IAAA,OAAO,WAAA;AAAA,EACT;AAEA,EAAA,OAAO,WACJ,KAAA,CAAM,MAAM,EACZ,GAAA,CAAI,CAAC,SAAS,IAAA,CAAK,CAAC,CAAA,CAAG,WAAA,KAAgB,IAAA,CAAK,KAAA,CAAM,CAAC,CAAC,CAAA,CACpD,KAAK,GAAG,CAAA;AACb;AAEO,SAAS,kBAAA,CACd,KAAA,EACA,IAAA,EACA,SAAA,GAAuC,CAAC,KAAA,KAAU,CAAA,EAAG,KAAK,CAAA,CAAA,EAAI,KAAA,GAAQ,CAAC,CAAA,CAAA,EAC/D;AACR,EAAA,IAAI,CAAC,IAAA,CAAK,GAAA,CAAI,KAAK,CAAA,EAAG;AACpB,IAAA,IAAA,CAAK,IAAI,KAAK,CAAA;AACd,IAAA,OAAO,KAAA;AAAA,EACT;AAEA,EAAA,IAAI,KAAA,GAAQ,CAAA;AACZ,EAAA,OAAO,IAAA,EAAM;AACX,IAAA,MAAM,SAAA,GAAY,UAAU,KAAK,CAAA;AACjC,IAAA,IAAI,CAAC,IAAA,CAAK,GAAA,CAAI,SAAS,CAAA,EAAG;AACxB,MAAA,IAAA,CAAK,IAAI,SAAS,CAAA;AAClB,MAAA,OAAO,SAAA;AAAA,IACT;AACA,IAAA,KAAA,IAAS,CAAA;AAAA,EACX;AACF;AAEO,SAAS,YAAA,CAAa,UAA8B,YAAA,EAA8B;AACvF,EAAA,MAAM,cAAA,GAAA,CAAkB,QAAA,IAAY,GAAA,EAAK,IAAA,EAAK;AAC9C,EAAA,MAAM,IAAA,GAAO,mBAAmB,GAAA,GAAM,EAAA,GAAK,IAAI,cAAA,CAAe,OAAA,CAAQ,aAAA,EAAe,EAAE,CAAC,CAAA,CAAA;AACxF,EAAA,MAAM,OAAO,YAAA,CAAa,UAAA,CAAW,GAAG,CAAA,GAAI,YAAA,GAAe,IAAI,YAAY,CAAA,CAAA;AAC3E,EAAA,OAAO,CAAA,EAAG,IAAI,CAAA,EAAG,IAAI,CAAA,CAAA;AACvB;AAEO,SAAS,yBAAyB,KAAA,EAA2C;AAClF,EAAA,OAAO,CAAA,QAAA,EAAW,MAAM,IAAI,CAAA,SAAA,CAAA;AAC9B;AAEO,SAAS,qBAAA,CACd,QACA,QAAA,EACmB;AACnB,EAAA,OAAO,MAAA,CAAO,GAAA,CAAI,CAAC,KAAA,MAAW;AAAA,IAC5B,IAAA,EAAM,YAAA,CAAa,QAAA,EAAU,wBAAA,CAAyB,KAAK,CAAC,CAAA;AAAA,IAC5D,OAAO,KAAA,CAAM,KAAA;AAAA,IACb,IAAA,EAAM;AAAA,GACR,CAAE,CAAA;AACJ;;;ACjFO,SAAS,mBAAmB,OAAA,EAA4C;AAC7E,EAAA,IAAI,cAAA,GAAwC,IAAA;AAE5C,EAAA,OAAO;AAAA,IACL,IAAA,EAAM,WAAA;AAAA,IAEN,eAAe,MAAA,EAAc;AAC3B,MAAA,cAAA,GAAiB,MAAA;AAAA,IACnB,CAAA;AAAA,IAEA,gBAAgB,MAAA,EAAQ;AACtB,MAAA,MAAA,CAAO,WAAA,CAAY,GAAA,CAAI,CAAC,OAAA,EAAS,UAAU,IAAA,KAAS;AAClD,QAAA,IAAI,CAAC,cAAA,EAAgB;AACnB,UAAA,IAAA,EAAK;AACL,UAAA;AAAA,QACF;AAEA,QAAA,IACE,CAAC,8BAAA;AAAA,UACC,OAAA;AAAA,UACA,QAAA;AAAA,UACA,OAAA,CAAQ,UAAU,SAAA,EAAU;AAAA,UAC5B,OAAA,CAAQ,kBAAkB,cAAA,CAAe;AAAA,SAC3C,EACA;AACA,UAAA,IAAA,EAAK;AAAA,QACP;AAAA,MACF,CAAC,CAAA;AAAA,IACH,CAAA;AAAA,IAEA,cAAA,GAAiB;AACf,MAAA,KAAA,MAAW,KAAA,IAAS,OAAA,CAAQ,SAAA,CAAU,SAAA,EAAU,EAAG;AACjD,QAAA,IAAA,CAAK,QAAA,CAAS;AAAA,UACZ,QAAA,EAAU,CAAA,OAAA,EAAU,KAAA,CAAM,IAAI,CAAA,SAAA,CAAA;AAAA,UAC9B,MAAA,EAAQ,sBAAsB,KAAK,CAAA;AAAA,UACnC,IAAA,EAAM;AAAA,SACP,CAAA;AAAA,MACH;AAAA,IACF,CAAA;AAAA,IAEA,kBAAA,GAAqB;AACnB,MAAA,MAAM,IAAA,GAAO,qBAAA;AAAA,QACX,OAAA,CAAQ,UAAU,SAAA,EAAU;AAAA,QAC5B,OAAA,CAAQ,cAAA,IAAkB,cAAA,EAAgB,IAAA,IAAQ;AAAA,OACpD;AACA,MAAA,OAAO,IAAA,CAAK,GAAA,CAAI,CAAC,GAAA,MAAS;AAAA,QACxB,GAAA,EAAK,MAAA;AAAA,QACL,KAAA,EAAO;AAAA,UACL,GAAA,EAAK,WAAA;AAAA,UACL,MAAM,GAAA,CAAI,IAAA;AAAA,UACV,OAAO,GAAA,CAAI,KAAA;AAAA,UACX,MAAM,GAAA,CAAI;AAAA,SACZ;AAAA,QACA,QAAA,EAAU;AAAA,OACZ,CAAE,CAAA;AAAA,IACJ;AAAA,GACF;AACF;AAEA,SAAS,8BAAA,CACP,OAAA,EACA,QAAA,EACA,MAAA,EACA,QAAA,EACS;AACT,EAAA,MAAM,aAAa,OAAA,CAAQ,GAAA;AAC3B,EAAA,IAAI,CAAC,UAAA,EAAY;AACf,IAAA,OAAO,KAAA;AAAA,EACT;AAEA,EAAA,MAAM,QAAA,GAAW,IAAI,GAAA,CAAI,UAAA,EAAY,kBAAkB,CAAA,CAAE,QAAA;AACzD,EAAA,MAAM,IAAA,GAAO,qBAAA,CAAsB,MAAA,EAAQ,QAAQ,CAAA;AACnD,EAAA,MAAM,eAAe,IAAA,CAAK,SAAA,CAAU,CAAC,GAAA,KAAQ,GAAA,CAAI,SAAS,QAAQ,CAAA;AAElE,EAAA,IAAI,iBAAiB,EAAA,EAAI;AACvB,IAAA,OAAO,KAAA;AAAA,EACT;AAEA,EAAA,QAAA,CAAS,UAAA,GAAa,GAAA;AACtB,EAAA,QAAA,CAAS,SAAA,CAAU,gBAAgB,8BAA8B,CAAA;AACjE,EAAA,QAAA,CAAS,GAAA,CAAI,qBAAA,CAAsB,MAAA,CAAO,YAAY,CAAE,CAAC,CAAA;AACzD,EAAA,OAAO,IAAA;AACT","file":"chunk-YVQDAY47.js","sourcesContent":["import type { ZodTypeAny } from \"zod\";\n\nimport type { ResolvedWebSkillDefinition, ResolvedWebSkillFunctionDefinition } from \"./types.ts\";\n\nconst INDENT = \" \";\n\ninterface LooseZodDefinition {\n typeName?: string;\n [key: string]: unknown;\n}\n\nexport function generateSkillMarkdown(skill: ResolvedWebSkillDefinition): string {\n const description =\n skill.description\n ?? `Expose browser-callable functions under \\`window._web_skills.${skill.key}\\`.`;\n\n const lines: string[] = [\n \"---\",\n `name: ${skill.slug}`,\n `description: ${escapeFrontmatterValue(description)}`,\n \"---\",\n \"\",\n `# ${skill.title}`,\n \"\",\n \"Use the browser console entrypoint:\",\n \"\",\n \"```js\",\n `window._web_skills.${skill.key}`,\n \"```\",\n \"\",\n \"Available functions:\",\n \"\",\n ];\n\n for (const definition of skill.functions) {\n lines.push(...renderFunctionSection(skill, definition), \"\");\n }\n\n return `${lines.join(\"\\n\").trimEnd()}\\n`;\n}\n\nfunction renderFunctionSection(\n skill: ResolvedWebSkillDefinition,\n definition: ResolvedWebSkillFunctionDefinition,\n): string[] {\n const inputSchema = definition.inputSchema ? renderZodSchema(definition.inputSchema) : \"unknown\";\n const outputSchema = definition.outputSchema ? renderZodSchema(definition.outputSchema) : \"unknown\";\n\n return [\n `## \\`${definition.name}(input)\\``,\n \"\",\n `Purpose: ${definition.description ?? `Invoke \\`window._web_skills.${skill.key}.${definition.name}(input)\\`.`}`,\n \"\",\n \"Input:\",\n \"\",\n \"```ts\",\n inputSchema,\n \"```\",\n \"\",\n \"Output:\",\n \"\",\n \"```ts\",\n outputSchema,\n \"```\",\n ];\n}\n\nexport function renderZodSchema(schema: ZodTypeAny): string {\n return renderSchema(schema, 0);\n}\n\nfunction renderSchema(schema: ZodTypeAny, depth: number): string {\n const definition = getDefinition(schema);\n const typeName = definition?.typeName;\n\n switch (typeName) {\n case \"ZodString\":\n return \"string\";\n case \"ZodNumber\":\n return \"number\";\n case \"ZodBoolean\":\n return \"boolean\";\n case \"ZodBigInt\":\n return \"bigint\";\n case \"ZodDate\":\n return \"Date\";\n case \"ZodUndefined\":\n return \"undefined\";\n case \"ZodNull\":\n return \"null\";\n case \"ZodVoid\":\n return \"void\";\n case \"ZodAny\":\n return \"any\";\n case \"ZodUnknown\":\n return \"unknown\";\n case \"ZodNever\":\n return \"never\";\n case \"ZodLiteral\":\n return JSON.stringify(definition?.value);\n case \"ZodEnum\":\n return Array.isArray(definition?.values)\n ? definition.values.map((value) => JSON.stringify(value)).join(\" | \")\n : \"string\";\n case \"ZodNativeEnum\":\n return renderNativeEnum(\n definition?.values && typeof definition.values === \"object\"\n ? (definition.values as Record<string, string | number>)\n : undefined,\n );\n case \"ZodArray\":\n return `${wrapType(renderSchema(definition?.type as ZodTypeAny, depth))}[]`;\n case \"ZodOptional\":\n return `${renderSchema(definition?.innerType as ZodTypeAny, depth)} | undefined`;\n case \"ZodNullable\":\n return `${renderSchema(definition?.innerType as ZodTypeAny, depth)} | null`;\n case \"ZodDefault\":\n case \"ZodCatch\":\n return renderSchema(definition?.innerType as ZodTypeAny, depth);\n case \"ZodEffects\":\n return renderSchema(definition?.schema as ZodTypeAny, depth);\n case \"ZodBranded\":\n return renderSchema(definition?.type as ZodTypeAny, depth);\n case \"ZodUnion\":\n return Array.isArray(definition?.options)\n ? definition.options.map((option) => wrapType(renderSchema(option as ZodTypeAny, depth))).join(\" | \")\n : \"unknown\";\n case \"ZodDiscriminatedUnion\":\n return Array.from(\n definition?.options instanceof Map ? definition.options.values() : [],\n )\n .map((option) => wrapType(renderSchema(option as ZodTypeAny, depth)))\n .join(\" | \");\n case \"ZodIntersection\":\n return `${wrapType(renderSchema(definition?.left as ZodTypeAny, depth))} & ${wrapType(renderSchema(definition?.right as ZodTypeAny, depth))}`;\n case \"ZodTuple\":\n return `[${Array.isArray(definition?.items)\n ? definition.items.map((item) => renderSchema(item as ZodTypeAny, depth)).join(\", \")\n : \"\"}]`;\n case \"ZodRecord\":\n return `Record<${renderRecordKey(definition?.keyType as ZodTypeAny | undefined)}, ${renderSchema(definition?.valueType as ZodTypeAny, depth)}>`;\n case \"ZodObject\":\n return renderObjectSchema(schema, depth);\n case \"ZodLazy\":\n return typeof definition?.getter === \"function\"\n ? renderSchema(definition.getter() as ZodTypeAny, depth)\n : \"unknown\";\n default:\n return \"unknown\";\n }\n}\n\nfunction renderObjectSchema(schema: ZodTypeAny, depth: number): string {\n const definition = getDefinition(schema);\n const shapeSource = definition?.shape;\n const shape =\n typeof shapeSource === \"function\"\n ? (shapeSource() as Record<string, ZodTypeAny>)\n : ((shapeSource ?? {}) as Record<string, ZodTypeAny>);\n const entries = Object.entries(shape);\n\n if (entries.length === 0) {\n return \"{}\";\n }\n\n const propertyLines = entries.map(([key, propertySchema]) => {\n const optional = isOptionalSchema(propertySchema);\n const renderedType = renderSchema(optional ? unwrapOptionalSchema(propertySchema) : propertySchema, depth + 1);\n return `${indent(depth + 1)}${quotePropertyKey(key)}${optional ? \"?\" : \"\"}: ${renderedType};`;\n });\n\n return [\"{\", ...propertyLines, `${indent(depth)}}`].join(\"\\n\");\n}\n\nfunction renderNativeEnum(values: Record<string, string | number> | undefined): string {\n if (!values) {\n return \"string | number\";\n }\n\n const rendered = Array.from(\n new Set(\n Object.values(values).filter(\n (value): value is string | number => typeof value === \"string\" || typeof value === \"number\",\n ),\n ),\n );\n\n return rendered.map((value) => JSON.stringify(value)).join(\" | \") || \"string | number\";\n}\n\nfunction renderRecordKey(keyType: ZodTypeAny | undefined): string {\n if (!keyType) {\n return \"string\";\n }\n\n return renderSchema(keyType, 0);\n}\n\nfunction isOptionalSchema(schema: ZodTypeAny): boolean {\n return typeof schema.isOptional === \"function\" ? schema.isOptional() : getDefinition(schema)?.typeName === \"ZodOptional\";\n}\n\nfunction unwrapOptionalSchema(schema: ZodTypeAny): ZodTypeAny {\n const definition = getDefinition(schema);\n if (definition?.typeName === \"ZodOptional\") {\n return definition.innerType as ZodTypeAny;\n }\n\n return schema;\n}\n\nfunction wrapType(value: string): string {\n return /[|&\\n]/u.test(value) ? `(${value})` : value;\n}\n\nfunction quotePropertyKey(value: string): string {\n return /^[A-Za-z_$][A-Za-z0-9_$]*$/u.test(value) ? value : JSON.stringify(value);\n}\n\nfunction indent(depth: number): string {\n return INDENT.repeat(depth);\n}\n\nfunction getDefinition(schema: ZodTypeAny): LooseZodDefinition | undefined {\n return (schema as unknown as { _def?: LooseZodDefinition })._def;\n}\n\nfunction escapeFrontmatterValue(value: string): string {\n return JSON.stringify(value);\n}\n","import type { ResolvedWebSkillDefinition, WebSkillLinkTag } from \"./types.ts\";\n\nconst NON_ALPHANUMERIC_PATTERN = /[^a-zA-Z0-9]+/gu;\nconst TRIM_DASHES_PATTERN = /^-+|-+$/gu;\nconst CAMEL_BOUNDARY_PATTERN = /[-_\\s]+([a-zA-Z0-9])/gu;\nconst NON_IDENTIFIER_PATTERN = /[^a-zA-Z0-9_$]/gu;\nconst LEADING_INVALID_IDENTIFIER_PATTERN = /^[^a-zA-Z_$]+/u;\n\nexport function slugifySkillSegment(value: string): string {\n const normalized = value\n .trim()\n .replace(NON_ALPHANUMERIC_PATTERN, \"-\")\n .replace(TRIM_DASHES_PATTERN, \"\")\n .toLowerCase();\n\n return normalized || \"web-skill\";\n}\n\nexport function toSkillKey(value: string): string {\n const identifier = value\n .trim()\n .replace(CAMEL_BOUNDARY_PATTERN, (_match, character: string) => character.toUpperCase())\n .replace(NON_IDENTIFIER_PATTERN, \"\")\n .replace(LEADING_INVALID_IDENTIFIER_PATTERN, \"\");\n\n if (!identifier) {\n return \"webSkill\";\n }\n\n return identifier[0]!.toLowerCase() + identifier.slice(1);\n}\n\nexport function titleFromName(value: string): string {\n const normalized = value\n .replace(/([a-z0-9])([A-Z])/gu, \"$1 $2\")\n .replace(/[-_]+/gu, \" \")\n .trim();\n\n if (!normalized) {\n return \"Web Skill\";\n }\n\n return normalized\n .split(/\\s+/u)\n .map((part) => part[0]!.toUpperCase() + part.slice(1))\n .join(\" \");\n}\n\nexport function ensureUniqueString(\n value: string,\n used: Set<string>,\n formatter: (index: number) => string = (index) => `${value}-${index + 1}`,\n): string {\n if (!used.has(value)) {\n used.add(value);\n return value;\n }\n\n let index = 1;\n while (true) {\n const nextValue = formatter(index);\n if (!used.has(nextValue)) {\n used.add(nextValue);\n return nextValue;\n }\n index += 1;\n }\n}\n\nexport function joinBasePath(basePath: string | undefined, relativePath: string): string {\n const normalizedBase = (basePath ?? \"/\").trim();\n const base = normalizedBase === \"/\" ? \"\" : `/${normalizedBase.replace(/^\\/+|\\/+$/gu, \"\")}`;\n const path = relativePath.startsWith(\"/\") ? relativePath : `/${relativePath}`;\n return `${base}${path}`;\n}\n\nexport function toSkillMarkdownAssetPath(skill: ResolvedWebSkillDefinition): string {\n return `/skills/${skill.slug}/SKILL.md`;\n}\n\nexport function buildWebSkillLinkTags(\n skills: ResolvedWebSkillDefinition[],\n basePath?: string,\n): WebSkillLinkTag[] {\n return skills.map((skill) => ({\n href: joinBasePath(basePath, toSkillMarkdownAssetPath(skill)),\n title: skill.title,\n type: \"text/markdown\",\n }));\n}\n","import type { IncomingMessage, ServerResponse } from \"node:http\";\n\nimport type { Plugin, ResolvedConfig } from \"vite\";\n\nimport { generateSkillMarkdown } from \"./markdown.ts\";\nimport type { ResolvedWebSkillDefinition, WebSkillVitePluginOptions } from \"./types.ts\";\nimport { buildWebSkillLinkTags } from \"./utils.ts\";\n\nexport function webSkillVitePlugin(options: WebSkillVitePluginOptions): Plugin {\n let resolvedConfig: ResolvedConfig | null = null;\n\n return {\n name: \"web-skill\",\n\n configResolved(config): void {\n resolvedConfig = config;\n },\n\n configureServer(server) {\n server.middlewares.use((request, response, next) => {\n if (!resolvedConfig) {\n next();\n return;\n }\n\n if (\n !tryServeGeneratedSkillMarkdown(\n request,\n response,\n options.generator.getSkills(),\n options.publicBasePath ?? resolvedConfig.base,\n )\n ) {\n next();\n }\n });\n },\n\n generateBundle() {\n for (const skill of options.generator.getSkills()) {\n this.emitFile({\n fileName: `skills/${skill.slug}/SKILL.md`,\n source: generateSkillMarkdown(skill),\n type: \"asset\",\n });\n }\n },\n\n transformIndexHtml() {\n const tags = buildWebSkillLinkTags(\n options.generator.getSkills(),\n options.publicBasePath ?? resolvedConfig?.base ?? \"/\",\n );\n return tags.map((tag) => ({\n tag: \"link\",\n attrs: {\n rel: \"web-skill\",\n href: tag.href,\n title: tag.title,\n type: tag.type,\n },\n injectTo: \"head\" as const,\n }));\n },\n };\n}\n\nfunction tryServeGeneratedSkillMarkdown(\n request: IncomingMessage,\n response: ServerResponse,\n skills: ResolvedWebSkillDefinition[],\n basePath: string,\n): boolean {\n const requestUrl = request.url;\n if (!requestUrl) {\n return false;\n }\n\n const pathname = new URL(requestUrl, \"http://localhost\").pathname;\n const tags = buildWebSkillLinkTags(skills, basePath);\n const matchedIndex = tags.findIndex((tag) => tag.href === pathname);\n\n if (matchedIndex === -1) {\n return false;\n }\n\n response.statusCode = 200;\n response.setHeader(\"Content-Type\", \"text/markdown; charset=utf-8\");\n response.end(generateSkillMarkdown(skills[matchedIndex]!));\n return true;\n}\n"]}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { ZodTypeAny } from 'zod';
|
|
2
|
+
import { R as ResolvedWebSkillDefinition, W as WebSkillsWindowShape, a as WebSkillGenerator, b as WebSkillLinkTag } from './vite-plugin-5xZLBPsq.js';
|
|
3
|
+
export { A as AddWebSkillFunctionOptions, N as NewWebSkillOptions, c as ResolvedWebSkillFunctionDefinition, d as WebSkillBuilder, e as WebSkillFunctionDefinition, f as WebSkillFunctionHandler, g as WebSkillMetadata, h as WebSkillVitePluginOptions, i as WebSkillWindowEntry, j as WebSkillWindowFunction, w as webSkillVitePlugin } from './vite-plugin-5xZLBPsq.js';
|
|
4
|
+
import 'vite';
|
|
5
|
+
|
|
6
|
+
declare function generateSkillMarkdown(skill: ResolvedWebSkillDefinition): string;
|
|
7
|
+
declare function renderZodSchema(schema: ZodTypeAny): string;
|
|
8
|
+
|
|
9
|
+
declare function createWebSkillGenerator(): WebSkillGenerator;
|
|
10
|
+
declare global {
|
|
11
|
+
interface Window {
|
|
12
|
+
_web_skills?: WebSkillsWindowShape;
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
declare function buildWebSkillLinkTags(skills: ResolvedWebSkillDefinition[], basePath?: string): WebSkillLinkTag[];
|
|
17
|
+
|
|
18
|
+
export { ResolvedWebSkillDefinition, WebSkillGenerator, WebSkillLinkTag, WebSkillsWindowShape, buildWebSkillLinkTags, createWebSkillGenerator, generateSkillMarkdown, renderZodSchema };
|
|
@@ -1,42 +1,15 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { ensureUniqueString, slugifySkillSegment, toSkillKey, titleFromName } from './chunk-YVQDAY47.js';
|
|
2
|
+
export { buildWebSkillLinkTags, generateSkillMarkdown, renderZodSchema, webSkillVitePlugin } from './chunk-YVQDAY47.js';
|
|
2
3
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
WebSkillFunctionDefinition,
|
|
10
|
-
WebSkillFunctionHandler,
|
|
11
|
-
WebSkillGenerator,
|
|
12
|
-
WebSkillMetadata,
|
|
13
|
-
WebSkillsWindowShape,
|
|
14
|
-
WebSkillWindowEntry,
|
|
15
|
-
WebSkillWindowFunction,
|
|
16
|
-
} from "./types.ts";
|
|
17
|
-
import { ensureUniqueString, slugifySkillSegment, titleFromName, toSkillKey } from "./utils.ts";
|
|
18
|
-
|
|
19
|
-
interface MutableWebSkillDefinition {
|
|
20
|
-
description: string | null;
|
|
21
|
-
functions: WebSkillFunctionDefinition<any, any>[];
|
|
22
|
-
key: string;
|
|
23
|
-
name: string;
|
|
24
|
-
slug: string;
|
|
25
|
-
title: string;
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
class WebSkillBuilderImpl implements WebSkillBuilder {
|
|
29
|
-
constructor(private readonly skill: MutableWebSkillDefinition) {}
|
|
30
|
-
|
|
31
|
-
addFunction<TInput, TOutput>(
|
|
32
|
-
func: WebSkillFunctionHandler<TInput, TOutput>,
|
|
33
|
-
name: string,
|
|
34
|
-
options: AddWebSkillFunctionOptions<TInput, TOutput> = {},
|
|
35
|
-
): WebSkillBuilder {
|
|
4
|
+
// src/runtime.ts
|
|
5
|
+
var WebSkillBuilderImpl = class {
|
|
6
|
+
constructor(skill) {
|
|
7
|
+
this.skill = skill;
|
|
8
|
+
}
|
|
9
|
+
addFunction(func, name, options = {}) {
|
|
36
10
|
if (typeof func !== "function") {
|
|
37
11
|
throw new TypeError(`web-skill function "${name}" must be a function.`);
|
|
38
12
|
}
|
|
39
|
-
|
|
40
13
|
const normalizedName = name.trim();
|
|
41
14
|
if (!normalizedName) {
|
|
42
15
|
throw new TypeError("web-skill function name must not be empty.");
|
|
@@ -44,33 +17,28 @@ class WebSkillBuilderImpl implements WebSkillBuilder {
|
|
|
44
17
|
if (normalizedName === "_meta") {
|
|
45
18
|
throw new TypeError('web-skill function name "_meta" is reserved.');
|
|
46
19
|
}
|
|
47
|
-
|
|
48
20
|
const existing = this.skill.functions.find((definition) => definition.name === normalizedName);
|
|
49
21
|
if (existing) {
|
|
50
22
|
throw new Error(
|
|
51
|
-
`web-skill "${this.skill.key}" already contains a function named "${normalizedName}"
|
|
23
|
+
`web-skill "${this.skill.key}" already contains a function named "${normalizedName}".`
|
|
52
24
|
);
|
|
53
25
|
}
|
|
54
|
-
|
|
55
26
|
this.skill.functions.push({
|
|
56
27
|
func,
|
|
57
28
|
name: normalizedName,
|
|
58
|
-
description: options.description?.trim() ||
|
|
29
|
+
description: options.description?.trim() || void 0,
|
|
59
30
|
inputSchema: options.inputSchema,
|
|
60
|
-
outputSchema: options.outputSchema
|
|
31
|
+
outputSchema: options.outputSchema
|
|
61
32
|
});
|
|
62
|
-
|
|
63
33
|
return this;
|
|
64
34
|
}
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
newSkill(options: NewWebSkillOptions = {}): WebSkillBuilder {
|
|
35
|
+
};
|
|
36
|
+
var WebSkillGeneratorImpl = class {
|
|
37
|
+
skills = [];
|
|
38
|
+
usedKeys = /* @__PURE__ */ new Set();
|
|
39
|
+
usedNames = /* @__PURE__ */ new Set();
|
|
40
|
+
usedSlugs = /* @__PURE__ */ new Set();
|
|
41
|
+
newSkill(options = {}) {
|
|
74
42
|
const skillIndex = this.skills.length + 1;
|
|
75
43
|
const fallbackName = `web-skill-${skillIndex}`;
|
|
76
44
|
const requestedName = options.name?.trim();
|
|
@@ -78,108 +46,87 @@ class WebSkillGeneratorImpl implements WebSkillGenerator {
|
|
|
78
46
|
const requestedIdentifier = requestedName || requestedTitle || fallbackName;
|
|
79
47
|
const requestedKeyBase = requestedName || requestedTitle || `webSkill${skillIndex}`;
|
|
80
48
|
const requestedTitleBase = requestedTitle || requestedName || fallbackName;
|
|
81
|
-
|
|
82
49
|
const slug = ensureUniqueString(slugifySkillSegment(requestedIdentifier), this.usedSlugs);
|
|
83
50
|
const keyBase = toSkillKey(requestedKeyBase);
|
|
84
51
|
const key = ensureUniqueString(keyBase, this.usedKeys, (index) => `${keyBase}${index + 1}`);
|
|
85
52
|
const nameBase = requestedName || slug;
|
|
86
53
|
const name = ensureUniqueString(nameBase, this.usedNames);
|
|
87
54
|
const title = requestedTitle || titleFromName(requestedTitleBase);
|
|
88
|
-
|
|
89
|
-
const skill: MutableWebSkillDefinition = {
|
|
55
|
+
const skill = {
|
|
90
56
|
description: options.description?.trim() || null,
|
|
91
57
|
functions: [],
|
|
92
58
|
key,
|
|
93
59
|
name,
|
|
94
60
|
slug,
|
|
95
|
-
title
|
|
61
|
+
title
|
|
96
62
|
};
|
|
97
|
-
|
|
98
63
|
this.skills.push(skill);
|
|
99
64
|
return new WebSkillBuilderImpl(skill);
|
|
100
65
|
}
|
|
101
|
-
|
|
102
|
-
getSkills(): ResolvedWebSkillDefinition[] {
|
|
66
|
+
getSkills() {
|
|
103
67
|
return this.skills.map((skill) => ({
|
|
104
68
|
description: skill.description,
|
|
105
69
|
key: skill.key,
|
|
106
70
|
name: skill.name,
|
|
107
71
|
slug: skill.slug,
|
|
108
72
|
title: skill.title,
|
|
109
|
-
functions: skill.functions.map
|
|
73
|
+
functions: skill.functions.map((definition) => ({
|
|
110
74
|
name: definition.name,
|
|
111
|
-
description: definition.description ??
|
|
75
|
+
description: definition.description ?? void 0,
|
|
112
76
|
inputSchema: definition.inputSchema,
|
|
113
|
-
outputSchema: definition.outputSchema
|
|
114
|
-
}))
|
|
77
|
+
outputSchema: definition.outputSchema
|
|
78
|
+
}))
|
|
115
79
|
}));
|
|
116
80
|
}
|
|
117
|
-
|
|
118
|
-
install(target?: Window): WebSkillsWindowShape {
|
|
81
|
+
install(target) {
|
|
119
82
|
const windowTarget = target ?? resolveWindowTarget();
|
|
120
|
-
const registry =
|
|
121
|
-
|
|
83
|
+
const registry = windowTarget._web_skills ??= {};
|
|
122
84
|
for (const skill of this.skills) {
|
|
123
|
-
const entry
|
|
124
|
-
const metadata
|
|
85
|
+
const entry = {};
|
|
86
|
+
const metadata = {
|
|
125
87
|
description: skill.description,
|
|
126
88
|
functions: skill.functions.map((definition) => ({
|
|
127
89
|
description: definition.description ?? null,
|
|
128
90
|
hasInputSchema: Boolean(definition.inputSchema),
|
|
129
91
|
hasOutputSchema: Boolean(definition.outputSchema),
|
|
130
|
-
name: definition.name
|
|
92
|
+
name: definition.name
|
|
131
93
|
})),
|
|
132
94
|
key: skill.key,
|
|
133
95
|
name: skill.name,
|
|
134
|
-
title: skill.title
|
|
96
|
+
title: skill.title
|
|
135
97
|
};
|
|
136
|
-
|
|
137
98
|
entry._meta = metadata;
|
|
138
|
-
|
|
139
99
|
for (const definition of skill.functions) {
|
|
140
100
|
entry[definition.name] = wrapFunction(skill.key, definition);
|
|
141
101
|
}
|
|
142
|
-
|
|
143
|
-
registry[skill.key] = entry as WebSkillWindowEntry;
|
|
102
|
+
registry[skill.key] = entry;
|
|
144
103
|
}
|
|
145
|
-
|
|
146
104
|
return registry;
|
|
147
105
|
}
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
function resolveWindowTarget(): Window {
|
|
106
|
+
};
|
|
107
|
+
function resolveWindowTarget() {
|
|
151
108
|
if (typeof window === "undefined") {
|
|
152
109
|
throw new Error("web-skill install() requires a browser window target.");
|
|
153
110
|
}
|
|
154
|
-
|
|
155
111
|
return window;
|
|
156
112
|
}
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
skillKey: string,
|
|
160
|
-
definition: WebSkillFunctionDefinition<any, any>,
|
|
161
|
-
): WebSkillWindowFunction {
|
|
162
|
-
return async (input: unknown) => {
|
|
113
|
+
function wrapFunction(skillKey, definition) {
|
|
114
|
+
return async (input) => {
|
|
163
115
|
const parsedInput = parseWithSchema(definition.inputSchema, input);
|
|
164
116
|
const result = await definition.func(parsedInput);
|
|
165
117
|
return parseWithSchema(definition.outputSchema, result);
|
|
166
118
|
};
|
|
167
119
|
}
|
|
168
|
-
|
|
169
|
-
function parseWithSchema(schema: ZodTypeAny | undefined, value: unknown): unknown {
|
|
120
|
+
function parseWithSchema(schema, value) {
|
|
170
121
|
if (!schema) {
|
|
171
122
|
return value;
|
|
172
123
|
}
|
|
173
|
-
|
|
174
124
|
return schema.parse(value);
|
|
175
125
|
}
|
|
176
|
-
|
|
177
|
-
export function createWebSkillGenerator(): WebSkillGenerator {
|
|
126
|
+
function createWebSkillGenerator() {
|
|
178
127
|
return new WebSkillGeneratorImpl();
|
|
179
128
|
}
|
|
180
129
|
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
}
|
|
185
|
-
}
|
|
130
|
+
export { createWebSkillGenerator };
|
|
131
|
+
//# sourceMappingURL=index.js.map
|
|
132
|
+
//# sourceMappingURL=index.js.map
|