@vertesia/build-tools 1.5.0-dev.20260722.120446Z → 1.5.0-dev.20260804.124748Z
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 +297 -266
- package/lib/bin/build.js +26 -1
- package/lib/bin/build.js.map +1 -1
- package/lib/bin/config.d.ts +12 -0
- package/lib/bin/config.d.ts.map +1 -1
- package/lib/bin/config.js +25 -0
- package/lib/bin/config.js.map +1 -1
- package/lib/core/skill-markdown/load-catalog.d.ts +30 -0
- package/lib/core/skill-markdown/load-catalog.d.ts.map +1 -0
- package/lib/core/skill-markdown/load-catalog.js +69 -0
- package/lib/core/skill-markdown/load-catalog.js.map +1 -0
- package/lib/core/skill-markdown/preprocess.d.ts +127 -0
- package/lib/core/skill-markdown/preprocess.d.ts.map +1 -0
- package/lib/core/skill-markdown/preprocess.js +455 -0
- package/lib/core/skill-markdown/preprocess.js.map +1 -0
- package/lib/core/skill-markdown/schema-validator.d.ts +109 -0
- package/lib/core/skill-markdown/schema-validator.d.ts.map +1 -0
- package/lib/core/skill-markdown/schema-validator.js +420 -0
- package/lib/core/skill-markdown/schema-validator.js.map +1 -0
- package/lib/core/transformers/index.d.ts +1 -1
- package/lib/core/transformers/index.d.ts.map +1 -1
- package/lib/core/transformers/index.js +1 -1
- package/lib/core/transformers/index.js.map +1 -1
- package/lib/core/transformers/skill.d.ts +15 -1
- package/lib/core/transformers/skill.d.ts.map +1 -1
- package/lib/core/transformers/skill.js +82 -60
- package/lib/core/transformers/skill.js.map +1 -1
- package/lib/import-transform/detector.d.ts +19 -6
- package/lib/import-transform/detector.d.ts.map +1 -1
- package/lib/import-transform/detector.js +73 -24
- package/lib/import-transform/detector.js.map +1 -1
- package/lib/import-transform/index.d.ts.map +1 -1
- package/lib/import-transform/index.js +10 -1
- package/lib/import-transform/index.js.map +1 -1
- package/lib/import-transform/patterns.d.ts +7 -8
- package/lib/import-transform/patterns.d.ts.map +1 -1
- package/lib/import-transform/patterns.js +7 -8
- package/lib/import-transform/patterns.js.map +1 -1
- package/lib/index.d.ts +7 -3
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +9 -3
- package/lib/index.js.map +1 -1
- package/lib/vite/dev-server.d.ts +10 -0
- package/lib/vite/dev-server.d.ts.map +1 -1
- package/lib/vite/dev-server.js +36 -4
- package/lib/vite/dev-server.js.map +1 -1
- package/package.json +9 -12
- package/src/bin/build.ts +31 -2
- package/src/bin/config.ts +27 -0
- package/src/core/skill-markdown/load-catalog.ts +100 -0
- package/src/core/skill-markdown/preprocess.ts +632 -0
- package/src/core/skill-markdown/schema-validator.ts +517 -0
- package/src/core/transformers/index.ts +3 -0
- package/src/core/transformers/skill.ts +116 -53
- package/src/import-transform/detector.ts +78 -26
- package/src/import-transform/index.ts +12 -2
- package/src/import-transform/patterns.ts +7 -12
- package/src/index.ts +35 -2
- package/src/vite/dev-server.ts +52 -4
package/README.md
CHANGED
|
@@ -1,15 +1,22 @@
|
|
|
1
1
|
# @vertesia/build-tools
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Custom import syntaxes for Vertesia packages — `?skill`, `?skills`, `?template`, `?templates`,
|
|
4
|
+
`?prompt`, `?raw`, and bare `SKILL.md` / `TEMPLATE.md` — resolved at build time into real
|
|
5
|
+
JavaScript modules, with schema validation.
|
|
4
6
|
|
|
5
|
-
|
|
7
|
+
Ships three entry points:
|
|
6
8
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
-
|
|
10
|
-
-
|
|
11
|
-
-
|
|
12
|
-
|
|
9
|
+
| Entry point | Used for |
|
|
10
|
+
| ----------- | -------- |
|
|
11
|
+
| `vertesia-build` CLI | Build-time. Runs as a post-`tsc` step over the emitted `lib/`. |
|
|
12
|
+
| `@vertesia/build-tools/vite` | Dev-time. Same transformers applied to sources at request time. |
|
|
13
|
+
| `@vertesia/build-tools` | Programmatic. `transformImports()`, the transformers, the skill preprocessor. |
|
|
14
|
+
|
|
15
|
+
> **Not a bundler plugin.** Earlier versions of this package were a Rollup plugin
|
|
16
|
+
> (`vertesiaImportPlugin`). It is now a standalone post-`tsc` transformer: it reads the JavaScript
|
|
17
|
+
> `tsc` already emitted, writes generated modules beside it, and rewrites the importing files in
|
|
18
|
+
> place. Nothing here depends on Rollup, Rolldown, webpack or Vite at build time — the output is
|
|
19
|
+
> plain ESM that any bundler can consume afterwards.
|
|
13
20
|
|
|
14
21
|
## Installation
|
|
15
22
|
|
|
@@ -17,349 +24,374 @@ A flexible Rollup plugin for transforming imports with custom compilers and vali
|
|
|
17
24
|
pnpm add -D @vertesia/build-tools
|
|
18
25
|
```
|
|
19
26
|
|
|
20
|
-
## Quick
|
|
21
|
-
|
|
22
|
-
### Using Preset Transformers
|
|
27
|
+
## Quick start
|
|
23
28
|
|
|
24
|
-
|
|
25
|
-
// rollup.config.js
|
|
26
|
-
import { vertesiaImportPlugin, skillTransformer, rawTransformer } from '@vertesia/build-tools';
|
|
29
|
+
Add a `vertesia-build` block to your `package.json` and run the CLI after `tsc`:
|
|
27
30
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
})
|
|
41
|
-
]
|
|
42
|
-
};
|
|
31
|
+
```json
|
|
32
|
+
{
|
|
33
|
+
"scripts": {
|
|
34
|
+
"build": "tsc -p tsconfig.json && vertesia-build"
|
|
35
|
+
},
|
|
36
|
+
"vertesia-build": {
|
|
37
|
+
"libDir": "./lib",
|
|
38
|
+
"srcDir": "./src",
|
|
39
|
+
"transformers": ["skill", "skills", "raw"],
|
|
40
|
+
"assetsDir": "./dist"
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
43
|
```
|
|
44
44
|
|
|
45
|
-
|
|
45
|
+
Then use the import syntaxes in your source:
|
|
46
46
|
|
|
47
47
|
```typescript
|
|
48
|
-
//
|
|
48
|
+
// A single skill, from a Markdown file with YAML frontmatter
|
|
49
49
|
import codeReview from './skills/code-review.md?skill';
|
|
50
50
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
51
|
+
codeReview.name; // 'code_review'
|
|
52
|
+
codeReview.title; // 'Code Review Assistant'
|
|
53
|
+
codeReview.description; // 'Reviews a diff for …'
|
|
54
|
+
codeReview.instructions; // the Markdown body
|
|
55
|
+
codeReview.content_type; // 'md' | 'jst'
|
|
56
|
+
|
|
57
|
+
// Every SKILL.md in the sibling directories, as an array
|
|
58
|
+
import allSkills from './skills/all?skills';
|
|
56
59
|
|
|
57
|
-
//
|
|
60
|
+
// Any file as a string
|
|
58
61
|
import template from './template.html?raw';
|
|
59
|
-
console.log(template); // Raw HTML string
|
|
60
62
|
```
|
|
61
63
|
|
|
62
|
-
|
|
64
|
+
`transformers` is required, so every preset is opted into explicitly and a typo fails the build
|
|
65
|
+
rather than silently leaving imports untransformed.
|
|
63
66
|
|
|
64
|
-
###
|
|
67
|
+
### Vite dev mode
|
|
65
68
|
|
|
66
|
-
|
|
69
|
+
```typescript
|
|
70
|
+
// vite.config.ts
|
|
71
|
+
import { defineConfig } from 'vite';
|
|
72
|
+
import { vertesiaDevServerPlugin } from '@vertesia/build-tools/vite';
|
|
67
73
|
|
|
68
|
-
|
|
74
|
+
export default defineConfig({
|
|
75
|
+
plugins: [vertesiaDevServerPlugin()],
|
|
76
|
+
});
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
Defaults to all built-in transformers; pass `{ transformers: ['skill', 'raw'] }` to restrict the
|
|
80
|
+
set. Asset copying and widget bundling are build-time concerns and are skipped in dev.
|
|
81
|
+
|
|
82
|
+
`apiServerPlugin` from the same entry point mounts a Hono tool server as Vite middleware under
|
|
83
|
+
`/api`, with the dev-server plugin already included.
|
|
84
|
+
|
|
85
|
+
## Transformers
|
|
86
|
+
|
|
87
|
+
| Name | Matches | Produces |
|
|
88
|
+
| ---- | ------- | -------- |
|
|
89
|
+
| `skill` | `*.md?skill`, `*/SKILL.md` | `SkillDefinition` object |
|
|
90
|
+
| `skills` | `<dir>/<name>?skills` | Array of `SkillDefinition`, one per `SKILL.md` in the subdirectories |
|
|
91
|
+
| `template` | `*.md?template`, `*/TEMPLATE.md` | `RenderingTemplateDefinition` |
|
|
92
|
+
| `templates` | `<dir>/<name>?templates` | Array of rendering templates |
|
|
93
|
+
| `prompt` | `*?prompt` | `PromptDefinition` |
|
|
94
|
+
| `raw` | `*?raw` | The file contents as a string |
|
|
95
|
+
|
|
96
|
+
The two collection transformers are *virtual*: there is no file at `./all?skills`, the name before
|
|
97
|
+
the query is simply the generated module's name. That name is required, so two collections in the
|
|
98
|
+
same directory cannot collide.
|
|
99
|
+
|
|
100
|
+
## The skill transformer
|
|
101
|
+
|
|
102
|
+
### Input
|
|
69
103
|
|
|
70
|
-
**Input:** `my-skill.md`
|
|
71
104
|
```markdown
|
|
72
105
|
---
|
|
73
|
-
name:
|
|
106
|
+
name: my_skill
|
|
74
107
|
title: My Skill
|
|
75
108
|
description: A helpful skill
|
|
76
109
|
content_type: md
|
|
110
|
+
tools: [tool_one, tool_two]
|
|
111
|
+
supporting_tools: [tool_three]
|
|
77
112
|
context_triggers:
|
|
78
|
-
|
|
79
|
-
tools: [tool1, tool2]
|
|
113
|
+
keywords: [skill, helper]
|
|
80
114
|
---
|
|
81
115
|
|
|
82
116
|
# My Skill
|
|
83
117
|
|
|
84
|
-
|
|
118
|
+
The instructions the model receives.
|
|
85
119
|
```
|
|
86
120
|
|
|
87
|
-
**
|
|
121
|
+
Frontmatter is validated with a **strict** Zod schema — an unknown key is a build error, not a
|
|
122
|
+
silently ignored one. `name` and `description` are required; `content_type` defaults to `md`.
|
|
123
|
+
|
|
124
|
+
`supporting_tools` unlock exactly as `tools` do — the two are merged into `tools` on output, so no
|
|
125
|
+
runtime path sees the distinction. The split exists for validation: consumers that check whether a
|
|
126
|
+
skill documents what it unlocks skip the supporting list, which is meant for grants that carry their
|
|
127
|
+
own description and need no usage guidance.
|
|
128
|
+
|
|
129
|
+
`context_triggers` and `execution` each accept a nested form (as above) or a flat legacy form
|
|
130
|
+
(`keywords:`, `tools:`, `data_patterns:` / `language:`, `packages:`, `system_packages:` at the top
|
|
131
|
+
level). When `execution` is present, the first fenced code block in the body is extracted as
|
|
132
|
+
`execution.template`.
|
|
133
|
+
|
|
134
|
+
### Output
|
|
135
|
+
|
|
88
136
|
```typescript
|
|
89
137
|
{
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
scripts: ['helper.js', 'script.py'], // If .js/.py files exist in skill dir
|
|
100
|
-
widgets: ['chart', 'user-select'] // If .tsx files exist in skill dir
|
|
138
|
+
name: 'my_skill',
|
|
139
|
+
title: 'My Skill',
|
|
140
|
+
description: 'A helpful skill',
|
|
141
|
+
instructions: '# My Skill\n\nThe instructions the model receives.',
|
|
142
|
+
content_type: 'md',
|
|
143
|
+
context_triggers: { keywords: ['skill', 'helper'] },
|
|
144
|
+
tools: ['tool_one', 'tool_two', 'tool_three'],
|
|
145
|
+
scripts: ['helper.js'], // present only if discovered
|
|
146
|
+
widgets: ['chart'], // present only if discovered
|
|
101
147
|
}
|
|
102
148
|
```
|
|
103
149
|
|
|
104
|
-
|
|
150
|
+
Typed as `SkillDefinition`, exported from the package. The output schema is `passthrough`, so
|
|
151
|
+
fields added by `properties.ts` survive validation.
|
|
105
152
|
|
|
106
|
-
|
|
107
|
-
- Script files (`.js`, `.py`) in the skill directory → added to `scripts` array
|
|
108
|
-
- Widget files (`.tsx`) in the skill directory → added to `widgets` array (without extension)
|
|
153
|
+
### Asset discovery
|
|
109
154
|
|
|
110
|
-
|
|
155
|
+
Files sitting beside the skill are picked up automatically:
|
|
111
156
|
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
instructions: string; // Required: Skill instructions (markdown)
|
|
119
|
-
content_type: 'md' | 'jst'; // Required: Content type
|
|
120
|
-
input_schema?: { // Optional: JSON Schema for parameters
|
|
121
|
-
type: 'object';
|
|
122
|
-
properties?: Record<string, any>;
|
|
123
|
-
required?: string[];
|
|
124
|
-
};
|
|
125
|
-
context_triggers?: { // Optional: Auto-injection triggers
|
|
126
|
-
keywords?: string[]; // Keywords to trigger this skill
|
|
127
|
-
tool_names?: string[]; // Tools that suggest this skill
|
|
128
|
-
data_patterns?: string[]; // Regex patterns for data matching
|
|
129
|
-
};
|
|
130
|
-
execution?: { // Optional: Code execution config
|
|
131
|
-
language: string; // Programming language
|
|
132
|
-
packages?: string[]; // Required packages
|
|
133
|
-
system_packages?: string[]; // System-level packages
|
|
134
|
-
template?: string; // Code template
|
|
135
|
-
};
|
|
136
|
-
tools?: string[]; // Optional: Related tool names
|
|
137
|
-
scripts?: string[]; // Optional: Script files in skill dir
|
|
138
|
-
widgets?: string[]; // Optional: Widget names in skill dir
|
|
139
|
-
isEnabled?: (context: any) => Promise<boolean>; // Optional: Runtime filter function
|
|
140
|
-
}
|
|
157
|
+
```text
|
|
158
|
+
my-skill/
|
|
159
|
+
├── SKILL.md # frontmatter + instructions
|
|
160
|
+
├── properties.ts # runtime properties (optional)
|
|
161
|
+
├── helper.js # → skill.scripts, copied to {assetsDir}/scripts/
|
|
162
|
+
└── chart.tsx # → skill.widgets, bundled to {assetsDir}/{widgetsDir}/
|
|
141
163
|
```
|
|
142
164
|
|
|
143
|
-
|
|
165
|
+
`.js` and `.py` files become `scripts` and are copied verbatim. `.tsx` files become `widgets` and
|
|
166
|
+
are bundled with esbuild. Both are skipped entirely when `assetsDir` is `false`.
|
|
167
|
+
|
|
168
|
+
### Runtime properties (`properties.ts`)
|
|
144
169
|
|
|
145
|
-
For
|
|
170
|
+
For anything that cannot be expressed in YAML — functions, most of all — add a `properties.ts`
|
|
171
|
+
next to the `SKILL.md`:
|
|
146
172
|
|
|
147
173
|
```typescript
|
|
148
174
|
// my-skill/properties.ts
|
|
149
175
|
import type { ToolUseContext } from '@vertesia/tools-sdk';
|
|
150
176
|
|
|
151
177
|
export default {
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
// You can override any frontmatter property
|
|
158
|
-
description: 'Dynamically set description',
|
|
159
|
-
|
|
160
|
-
// Add any other SkillDefinition properties
|
|
178
|
+
isEnabled: async (context: ToolUseContext): Promise<boolean> => {
|
|
179
|
+
return context.project?.settings?.myFeature === true;
|
|
180
|
+
},
|
|
181
|
+
description: 'Overrides the frontmatter description',
|
|
161
182
|
};
|
|
162
183
|
```
|
|
163
184
|
|
|
164
|
-
**
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
4. Rollup automatically transpiles `properties.ts` to `properties.js` (via TypeScript plugin)
|
|
169
|
-
5. Runtime validation ensures `isEnabled` (if present) is a function
|
|
170
|
-
6. Build fails with clear errors if validation fails
|
|
185
|
+
The default export is a `Partial<SkillDefinition>` and its properties **override** frontmatter. When
|
|
186
|
+
the file exists, the generated chunk imports `./properties.js` — the JavaScript `tsc` emitted from
|
|
187
|
+
it — and spreads it over the skill object, so the merge happens at runtime rather than at build
|
|
188
|
+
time. A generated guard throws if `isEnabled` is present but is not a function.
|
|
171
189
|
|
|
172
|
-
|
|
173
|
-
```
|
|
174
|
-
my-skill/
|
|
175
|
-
├── SKILL.md # Declarative properties (frontmatter + markdown)
|
|
176
|
-
├── properties.ts # Runtime properties (functions, overrides)
|
|
177
|
-
├── helper.js # Script files (auto-discovered)
|
|
178
|
-
└── chart.tsx # Widget files (auto-discovered)
|
|
179
|
-
```
|
|
190
|
+
## Skill Markdown preprocessing
|
|
180
191
|
|
|
181
|
-
|
|
192
|
+
Skill bodies routinely name tools and other skills, and embed example payloads. Left as prose,
|
|
193
|
+
those drift out of sync with the tool definitions they describe and nothing catches it. The
|
|
194
|
+
preprocessor makes the references explicit so the build can verify them.
|
|
182
195
|
|
|
183
|
-
|
|
196
|
+
Four constructs, all optional:
|
|
184
197
|
|
|
185
|
-
|
|
198
|
+
| Written | Rendered | Verified |
|
|
199
|
+
| ------- | -------- | -------- |
|
|
200
|
+
| `{@tool fetch_document}` | `` `fetch_document` `` | tool exists, name unambiguous |
|
|
201
|
+
| `{@skill web_search}` | `` `learn_web_search` `` | skill exists, name unambiguous |
|
|
202
|
+
| `{@param fetch_document.format}` | `` `format` `` | that tool's schema declares the field |
|
|
203
|
+
| ` ```json tool=fetch_document ` | plain ` ```json ` fence | payload validates against the tool's schema |
|
|
186
204
|
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
205
|
+
````markdown
|
|
206
|
+
Call {@tool fetch_document} to load the object — {@param fetch_document.format} selects the
|
|
207
|
+
representation — then read it with {@skill artifacts}.
|
|
208
|
+
|
|
209
|
+
```json tool=fetch_document
|
|
210
|
+
{ "id": "abc123", "format": "text" }
|
|
192
211
|
```
|
|
212
|
+
````
|
|
193
213
|
|
|
194
|
-
|
|
214
|
+
A `{@param …}` path is spelled like a `dispatch` descriptor: dots nest and `[]` walks an array, so
|
|
215
|
+
`{@param batch_execute.inputs[].input}` resolves. Only the path is rendered.
|
|
195
216
|
|
|
196
|
-
|
|
217
|
+
Everything fails closed: an unknown tool, an ambiguous name, an unterminated `{@`, a `tool=` tag on
|
|
218
|
+
a non-JSON fence, a duplicate tag, or a payload the schema rejects all stop the build with the file
|
|
219
|
+
and the offending name in the message. Inline code spans and untagged fences are left untouched.
|
|
197
220
|
|
|
198
|
-
|
|
199
|
-
import { vertesiaImportPlugin } from '@vertesia/build-tools';
|
|
200
|
-
import { z } from 'zod';
|
|
221
|
+
### Wiring the catalog
|
|
201
222
|
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
name: z.string(),
|
|
205
|
-
type: z.enum(['form', 'modal', 'dialog']),
|
|
206
|
-
fields: z.array(z.object({
|
|
207
|
-
name: z.string(),
|
|
208
|
-
type: z.string()
|
|
209
|
-
}))
|
|
210
|
-
});
|
|
223
|
+
The preprocessor is pure — it never reads a registry itself. The consuming package names a module
|
|
224
|
+
that supplies one:
|
|
211
225
|
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
schema: InteractionSchema,
|
|
222
|
-
|
|
223
|
-
// Transform function
|
|
224
|
-
transform: (content, filePath) => {
|
|
225
|
-
const json = JSON.parse(content);
|
|
226
|
-
|
|
227
|
-
// Add computed fields
|
|
228
|
-
json.timestamp = Date.now();
|
|
229
|
-
json.source = filePath;
|
|
230
|
-
|
|
231
|
-
return {
|
|
232
|
-
data: json
|
|
233
|
-
};
|
|
234
|
-
}
|
|
235
|
-
}
|
|
236
|
-
]
|
|
237
|
-
})
|
|
238
|
-
]
|
|
239
|
-
};
|
|
226
|
+
```json
|
|
227
|
+
{
|
|
228
|
+
"vertesia-build": {
|
|
229
|
+
"libDir": "./lib",
|
|
230
|
+
"srcDir": "./src",
|
|
231
|
+
"transformers": ["skill", "skills", "raw"],
|
|
232
|
+
"skillCatalog": "./lib/skill-catalog.js"
|
|
233
|
+
}
|
|
234
|
+
}
|
|
240
235
|
```
|
|
241
236
|
|
|
242
|
-
|
|
237
|
+
That module exports the catalog (arrays are accepted anywhere a set is):
|
|
243
238
|
|
|
244
|
-
|
|
239
|
+
```typescript
|
|
240
|
+
export const tools = new Set(['fetch_document', 'batch_execute']);
|
|
241
|
+
export const skills = new Set(['web_search', 'artifacts']);
|
|
242
|
+
|
|
243
|
+
// Optional
|
|
244
|
+
export const ambiguousTools = new Set<string>(); // names with >1 provider — always an error
|
|
245
|
+
export const ambiguousSkills = new Set<string>();
|
|
246
|
+
export const unvalidatableTools = new Set<string>(); // known, but no schema available here
|
|
247
|
+
export const validateExample = createSchemaExampleValidator(entries); // returns string[] of errors
|
|
248
|
+
export const validateField = createSchemaFieldValidator(entries); // resolves {@param …} paths
|
|
249
|
+
export const skillToolPrefix = 'learn_'; // default
|
|
250
|
+
export const exampleLanguages = new Set(['json']); // default
|
|
251
|
+
```
|
|
245
252
|
|
|
246
|
-
|
|
253
|
+
`createSchemaExampleValidator` (also exported from this package) validates a payload against the
|
|
254
|
+
tool's AJV schema, and additionally resolves *dispatcher* fields — a `string` parameter that carries
|
|
255
|
+
another tool's name, such as `batch_execute.tool_name` — which JSON Schema alone cannot check.
|
|
256
|
+
`createSchemaFieldValidator` walks a `{@param …}` path through the same schemas, descending into
|
|
257
|
+
`anyOf`/`oneOf`/`allOf` branches and following local `$ref`s (resolved against the innermost
|
|
258
|
+
embedded resource, so a nested `$defs` block wins), and reports the declared fields alongside an
|
|
259
|
+
unknown one. A tool with no schema, a tool absent from the entries, and a path crossing an
|
|
260
|
+
unresolvable reference are all errors rather than passes; so is a catalog that omits
|
|
261
|
+
`validateField` while a skill uses `{@param …}`.
|
|
247
262
|
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
- `config.scriptsDir` - Directory for script files relative to assetsDir (default: `'scripts'`)
|
|
252
|
-
- `config.widgetsDir` - Directory for widget files relative to assetsDir (default: `'widgets'`)
|
|
263
|
+
If `skillCatalog` is configured but `skill` is not among the `transformers`, the build fails. If a
|
|
264
|
+
skill body uses any of the constructs while **no** catalog is configured, the build also
|
|
265
|
+
fails, rather than shipping a raw `{@tool …}` to the model.
|
|
253
266
|
|
|
254
|
-
|
|
267
|
+
## Configuration reference
|
|
255
268
|
|
|
256
|
-
|
|
257
|
-
- When `assetsDir` is configured, script files (`.js`, `.py`) discovered in skill directories are automatically copied to `{assetsDir}/{scriptsDir}/`
|
|
258
|
-
- Widget files (`.tsx`) are tracked in the skill definition but not copied (compile them separately)
|
|
259
|
-
- Set `assetsDir: false` to disable asset copying
|
|
269
|
+
All paths are resolved relative to the package directory.
|
|
260
270
|
|
|
261
|
-
|
|
271
|
+
| Key | Type | Default | Meaning |
|
|
272
|
+
| --- | ---- | ------- | ------- |
|
|
273
|
+
| `libDir` | string | *required* | Root of the compiled output to transform. |
|
|
274
|
+
| `srcDir` | string | *required* | Root of the sources, mirroring `libDir`. |
|
|
275
|
+
| `transformers` | string[] | *required* | Names from the table above. Non-empty. |
|
|
276
|
+
| `assetsDir` | string \| false | `libDir` | Where scripts and widgets are emitted; `false` disables both. |
|
|
277
|
+
| `widgetsDir` | string | `'widgets'` | Sub-directory of `assetsDir` for widget bundles. |
|
|
278
|
+
| `widgetConfig` | object | — | Options forwarded to the esbuild widget bundler, e.g. `{ "minify": true }`. |
|
|
279
|
+
| `skillCatalog` | string | — | Module supplying `{ tools, skills, … }` for the preprocessor. |
|
|
262
280
|
|
|
263
|
-
|
|
281
|
+
## Programmatic API
|
|
264
282
|
|
|
265
|
-
|
|
266
|
-
interface TransformerRule {
|
|
267
|
-
pattern: RegExp; // Pattern to match imports
|
|
268
|
-
transform: TransformFunction; // Transform function
|
|
269
|
-
schema?: z.ZodType<any>; // Optional Zod schema
|
|
270
|
-
options?: Record<string, unknown>; // Optional custom options
|
|
271
|
-
}
|
|
272
|
-
```
|
|
273
|
-
|
|
274
|
-
### `TransformFunction`
|
|
283
|
+
### `transformImports(options)`
|
|
275
284
|
|
|
276
|
-
|
|
285
|
+
Runs the pipeline directly, with the same options as the config block:
|
|
277
286
|
|
|
278
287
|
```typescript
|
|
279
|
-
|
|
280
|
-
content: string,
|
|
281
|
-
filePath: string
|
|
282
|
-
) => TransformResult | Promise<TransformResult>;
|
|
283
|
-
|
|
284
|
-
interface TransformResult {
|
|
285
|
-
data: unknown; // Data to export (serialized to JSON)
|
|
286
|
-
imports?: string[]; // Optional imports to inject
|
|
287
|
-
code?: string; // Optional custom code generation
|
|
288
|
-
}
|
|
289
|
-
```
|
|
290
|
-
|
|
291
|
-
## Advanced Usage
|
|
288
|
+
import { transformImports } from '@vertesia/build-tools';
|
|
292
289
|
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
transform: (content, filePath) => {
|
|
301
|
-
return {
|
|
302
|
-
data: null,
|
|
303
|
-
code: `
|
|
304
|
-
export function render() {
|
|
305
|
-
return ${JSON.stringify(content)};
|
|
306
|
-
}
|
|
307
|
-
export const filePath = ${JSON.stringify(filePath)};
|
|
308
|
-
`
|
|
309
|
-
};
|
|
310
|
-
}
|
|
311
|
-
}
|
|
290
|
+
const result = await transformImports({
|
|
291
|
+
libDir: './lib',
|
|
292
|
+
srcDir: './src',
|
|
293
|
+
transformers: [skillTransformer, rawTransformer],
|
|
294
|
+
assetsDir: './dist',
|
|
295
|
+
});
|
|
296
|
+
// → { filesProcessed, chunksEmitted, assetsCopied, widgetsCompiled }
|
|
312
297
|
```
|
|
313
298
|
|
|
314
|
-
|
|
299
|
+
Note that `transformers` here takes resolved `TransformerRule` objects, not names; use
|
|
300
|
+
`resolveTransformerNames()` to go from one to the other.
|
|
315
301
|
|
|
316
|
-
|
|
302
|
+
### `preprocessSkillMarkdown(markdown, options)`
|
|
317
303
|
|
|
318
|
-
|
|
319
|
-
{
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
const config = parseYaml(content);
|
|
323
|
-
return {
|
|
324
|
-
data: config,
|
|
325
|
-
imports: [
|
|
326
|
-
"import { validateConfig } from './validator.js';",
|
|
327
|
-
"validateConfig(config);"
|
|
328
|
-
]
|
|
329
|
-
};
|
|
330
|
-
}
|
|
331
|
-
}
|
|
332
|
-
```
|
|
304
|
+
The resolver on its own. Never throws and reads no files — it returns
|
|
305
|
+
`{ markdown, references, examples, errors }` so callers decide what to do with problems.
|
|
306
|
+
`assertSkillMarkdown(markdown, options, source)` is the fail-closed wrapper that throws once,
|
|
307
|
+
listing every problem found.
|
|
333
308
|
|
|
334
|
-
|
|
309
|
+
### Custom transformers
|
|
335
310
|
|
|
336
|
-
|
|
311
|
+
A transformer is a pattern plus a function:
|
|
337
312
|
|
|
338
313
|
```typescript
|
|
339
|
-
import
|
|
314
|
+
import { transformImports } from '@vertesia/build-tools';
|
|
315
|
+
import { z } from 'zod';
|
|
340
316
|
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
317
|
+
const InteractionSchema = z.object({
|
|
318
|
+
name: z.string(),
|
|
319
|
+
type: z.enum(['form', 'modal', 'dialog']),
|
|
320
|
+
});
|
|
321
|
+
|
|
322
|
+
await transformImports({
|
|
323
|
+
libDir: './lib',
|
|
324
|
+
srcDir: './src',
|
|
325
|
+
transformers: [
|
|
326
|
+
{
|
|
327
|
+
pattern: /\.interaction\.json$/,
|
|
328
|
+
schema: InteractionSchema, // optional, validated at build time
|
|
329
|
+
transform: (content, filePath) => ({
|
|
330
|
+
data: { ...JSON.parse(content), source: filePath },
|
|
331
|
+
}),
|
|
332
|
+
},
|
|
333
|
+
],
|
|
334
|
+
});
|
|
344
335
|
```
|
|
345
336
|
|
|
346
|
-
|
|
337
|
+
`transform` returns a `TransformResult`:
|
|
338
|
+
|
|
339
|
+
| Field | Meaning |
|
|
340
|
+
| ----- | ------- |
|
|
341
|
+
| `data` | Value to export as the module default (serialized to JSON). |
|
|
342
|
+
| `code` | Custom module source, used *instead* of the JSON export. |
|
|
343
|
+
| `imports` | Extra import lines to inject at the top of the generated module. |
|
|
344
|
+
| `assets` | Files to copy into `assetsDir`. |
|
|
345
|
+
| `widgets` | Widget entries to bundle. |
|
|
346
|
+
|
|
347
|
+
Set `virtual: true` on the rule when the specifier does not name a real file, as the collection
|
|
348
|
+
transformers do.
|
|
349
|
+
|
|
350
|
+
## How it works
|
|
351
|
+
|
|
352
|
+
1. **Scan** — walk `libDir` for `.js` files containing a query-import marker.
|
|
353
|
+
2. **Detect** — lex each file with `es-module-lexer` and match the specifiers against the
|
|
354
|
+
transformers. A real lexer rather than a regex, because a regex matches anything that *looks*
|
|
355
|
+
like a specifier: a doc comment mentioning `` `?skill` ``, or a plain constant holding a path,
|
|
356
|
+
were both picked up as imports.
|
|
357
|
+
3. **Resolve** — map the specifier back to its source asset under `srcDir`.
|
|
358
|
+
4. **Emit** — run the transformer, validate against the rule's Zod schema if it has one, and write
|
|
359
|
+
the generated module as a sibling chunk in `libDir`.
|
|
360
|
+
5. **Rewrite** — splice the new chunk's path over the original specifier, in place.
|
|
361
|
+
6. **Recurse** — emitted chunks are re-scanned, so a `?skills` collection chunk that imports
|
|
362
|
+
`SKILL.md` siblings is itself transformed.
|
|
363
|
+
7. **Finish** — copy discovered assets and bundle discovered widgets with esbuild.
|
|
364
|
+
|
|
365
|
+
A file that cannot be lexed stops the build with `Failed to parse imports in <file>: …`. It only
|
|
366
|
+
reached the queue because it contains a marker, so a swallowed failure would mean a real import
|
|
367
|
+
ships untransformed.
|
|
368
|
+
|
|
369
|
+
## Error handling
|
|
370
|
+
|
|
371
|
+
Failures name the file and the specific problem. Frontmatter and output-schema failures list every
|
|
372
|
+
offending field:
|
|
373
|
+
|
|
374
|
+
```text
|
|
375
|
+
Invalid frontmatter in /abs/src/skills/bad/SKILL.md:
|
|
376
|
+
- description: Invalid input: expected string, received undefined
|
|
377
|
+
- frontmatter: Unrecognized key: "descriptoin"
|
|
378
|
+
```
|
|
347
379
|
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
3. **Transformation:** Runs the transform function on file content
|
|
351
|
-
4. **Validation:** If schema provided, validates the result with Zod
|
|
352
|
-
5. **Code Generation:** Generates JavaScript module with the data
|
|
353
|
-
6. **Build Fails:** If validation fails, build stops with clear error messages
|
|
380
|
+
Preprocessor failures are collected and reported together, with line numbers, rather than one per
|
|
381
|
+
run:
|
|
354
382
|
|
|
355
|
-
|
|
383
|
+
```text
|
|
384
|
+
Skill markdown errors in /abs/src/skills/fetch/SKILL.md:
|
|
385
|
+
- line 12: '{@tool fetch_documnet}' refers to a tool no provider registers
|
|
386
|
+
- line 31: example / must NOT have additional properties ('document_id')
|
|
387
|
+
- line 44: example is tagged 'tool=fetch_document' on a 'bash' fence; only json fences can be validated
|
|
388
|
+
```
|
|
356
389
|
|
|
357
|
-
|
|
390
|
+
Configuration failures are prefixed with the CLI name and exit non-zero:
|
|
358
391
|
|
|
359
|
-
```
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
- description: String must contain at least 1 character(s)
|
|
392
|
+
```text
|
|
393
|
+
vertesia-build: skillCatalog is configured but "skill" is not in vertesia-build.transformers.
|
|
394
|
+
vertesia-build: "vertesia-build.libDir" must be a non-empty string.
|
|
363
395
|
```
|
|
364
396
|
|
|
365
397
|
## License
|
|
@@ -368,6 +400,5 @@ Apache-2.0
|
|
|
368
400
|
|
|
369
401
|
## Repository
|
|
370
402
|
|
|
371
|
-
https://github.com/vertesia/composableai
|
|
372
|
-
|
|
373
|
-
Part of the Vertesia LLM Studio monorepo.
|
|
403
|
+
<https://github.com/vertesia/composableai> — `packages/build-tools`, part of the Vertesia LLM Studio
|
|
404
|
+
monorepo.
|