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 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 source-first and works best in TypeScript apps that already use Vite and Zod.
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 check
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":"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","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"]}
@@ -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 type { ZodTypeAny } from "zod";
1
+ import { ensureUniqueString, slugifySkillSegment, toSkillKey, titleFromName } from './chunk-YVQDAY47.js';
2
+ export { buildWebSkillLinkTags, generateSkillMarkdown, renderZodSchema, webSkillVitePlugin } from './chunk-YVQDAY47.js';
2
3
 
3
- import type {
4
- AddWebSkillFunctionOptions,
5
- NewWebSkillOptions,
6
- ResolvedWebSkillDefinition,
7
- ResolvedWebSkillFunctionDefinition,
8
- WebSkillBuilder,
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() || undefined,
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
- class WebSkillGeneratorImpl implements WebSkillGenerator {
68
- private readonly skills: MutableWebSkillDefinition[] = [];
69
- private readonly usedKeys = new Set<string>();
70
- private readonly usedNames = new Set<string>();
71
- private readonly usedSlugs = new Set<string>();
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<ResolvedWebSkillFunctionDefinition>((definition) => ({
73
+ functions: skill.functions.map((definition) => ({
110
74
  name: definition.name,
111
- description: definition.description ?? undefined,
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 = (windowTarget._web_skills ??= {});
121
-
83
+ const registry = windowTarget._web_skills ??= {};
122
84
  for (const skill of this.skills) {
123
- const entry: Partial<WebSkillWindowEntry> = {};
124
- const metadata: WebSkillMetadata = {
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
- function wrapFunction(
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
- declare global {
182
- interface Window {
183
- _web_skills?: WebSkillsWindowShape;
184
- }
185
- }
130
+ export { createWebSkillGenerator };
131
+ //# sourceMappingURL=index.js.map
132
+ //# sourceMappingURL=index.js.map