@vertesia/build-tools 1.2.0 → 1.4.0-dev.20260614.160504Z

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.
Files changed (220) hide show
  1. package/README.md +3 -3
  2. package/lib/bin/build.d.ts +35 -0
  3. package/lib/bin/build.d.ts.map +1 -0
  4. package/lib/bin/build.js +79 -0
  5. package/lib/bin/build.js.map +1 -0
  6. package/lib/bin/config.d.ts +24 -0
  7. package/lib/bin/config.d.ts.map +1 -0
  8. package/lib/bin/config.js +91 -0
  9. package/lib/bin/config.js.map +1 -0
  10. package/lib/core/compilers/widget.d.ts +27 -0
  11. package/lib/core/compilers/widget.d.ts.map +1 -0
  12. package/lib/core/compilers/widget.js +37 -0
  13. package/lib/core/compilers/widget.js.map +1 -0
  14. package/lib/{types → core}/parsers/frontmatter.d.ts +1 -1
  15. package/lib/core/parsers/frontmatter.d.ts.map +1 -0
  16. package/lib/{esm → core}/parsers/frontmatter.js +1 -1
  17. package/lib/core/parsers/frontmatter.js.map +1 -0
  18. package/lib/core/transformers/index.d.ts +10 -0
  19. package/lib/core/transformers/index.d.ts.map +1 -0
  20. package/lib/core/transformers/index.js +10 -0
  21. package/lib/core/transformers/index.js.map +1 -0
  22. package/lib/{types/presets → core/transformers}/prompt.d.ts +7 -21
  23. package/lib/core/transformers/prompt.d.ts.map +1 -0
  24. package/lib/{esm/presets → core/transformers}/prompt.js +17 -14
  25. package/lib/core/transformers/prompt.js.map +1 -0
  26. package/lib/core/transformers/raw.d.ts.map +1 -0
  27. package/lib/{esm/presets → core/transformers}/raw.js +2 -2
  28. package/lib/core/transformers/raw.js.map +1 -0
  29. package/lib/core/transformers/skill-collection.d.ts.map +1 -0
  30. package/lib/{esm/presets → core/transformers}/skill-collection.js +5 -12
  31. package/lib/core/transformers/skill-collection.js.map +1 -0
  32. package/lib/core/transformers/skill.d.ts +111 -0
  33. package/lib/core/transformers/skill.d.ts.map +1 -0
  34. package/lib/{esm/presets → core/transformers}/skill.js +70 -51
  35. package/lib/core/transformers/skill.js.map +1 -0
  36. package/lib/core/transformers/template-collection.d.ts.map +1 -0
  37. package/lib/{esm/presets → core/transformers}/template-collection.js +5 -12
  38. package/lib/core/transformers/template-collection.js.map +1 -0
  39. package/lib/{types/presets → core/transformers}/template.d.ts +7 -22
  40. package/lib/core/transformers/template.d.ts.map +1 -0
  41. package/lib/{esm/presets → core/transformers}/template.js +16 -11
  42. package/lib/core/transformers/template.js.map +1 -0
  43. package/lib/{types → core}/types.d.ts +5 -61
  44. package/lib/core/types.d.ts.map +1 -0
  45. package/lib/core/types.js +6 -0
  46. package/lib/{cjs → core}/types.js.map +1 -1
  47. package/lib/core/utils/asset-copy.d.ts.map +1 -0
  48. package/lib/core/utils/asset-copy.js.map +1 -0
  49. package/lib/core/utils/asset-discovery.d.ts.map +1 -0
  50. package/lib/{esm → core}/utils/asset-discovery.js +4 -4
  51. package/lib/core/utils/asset-discovery.js.map +1 -0
  52. package/lib/core/utils/template-asset-discovery.d.ts.map +1 -0
  53. package/lib/{esm → core}/utils/template-asset-discovery.js +3 -7
  54. package/lib/core/utils/template-asset-discovery.js.map +1 -0
  55. package/lib/import-transform/builtins.d.ts +21 -0
  56. package/lib/import-transform/builtins.d.ts.map +1 -0
  57. package/lib/import-transform/builtins.js +50 -0
  58. package/lib/import-transform/builtins.js.map +1 -0
  59. package/lib/import-transform/chunk-emitter.d.ts +24 -0
  60. package/lib/import-transform/chunk-emitter.d.ts.map +1 -0
  61. package/lib/import-transform/chunk-emitter.js +35 -0
  62. package/lib/import-transform/chunk-emitter.js.map +1 -0
  63. package/lib/import-transform/detector.d.ts +24 -0
  64. package/lib/import-transform/detector.d.ts.map +1 -0
  65. package/lib/import-transform/detector.js +34 -0
  66. package/lib/import-transform/detector.js.map +1 -0
  67. package/lib/import-transform/index.d.ts +47 -0
  68. package/lib/import-transform/index.d.ts.map +1 -0
  69. package/lib/import-transform/index.js +115 -0
  70. package/lib/import-transform/index.js.map +1 -0
  71. package/lib/import-transform/patterns.d.ts +25 -0
  72. package/lib/import-transform/patterns.d.ts.map +1 -0
  73. package/lib/import-transform/patterns.js +27 -0
  74. package/lib/import-transform/patterns.js.map +1 -0
  75. package/lib/import-transform/resolver.d.ts +23 -0
  76. package/lib/import-transform/resolver.d.ts.map +1 -0
  77. package/lib/import-transform/resolver.js +30 -0
  78. package/lib/import-transform/resolver.js.map +1 -0
  79. package/lib/import-transform/rewriter.d.ts +21 -0
  80. package/lib/import-transform/rewriter.d.ts.map +1 -0
  81. package/lib/import-transform/rewriter.js +30 -0
  82. package/lib/import-transform/rewriter.js.map +1 -0
  83. package/lib/import-transform/scanner.d.ts +17 -0
  84. package/lib/import-transform/scanner.d.ts.map +1 -0
  85. package/lib/import-transform/scanner.js +46 -0
  86. package/lib/import-transform/scanner.js.map +1 -0
  87. package/lib/index.d.ts +39 -0
  88. package/lib/index.d.ts.map +1 -0
  89. package/lib/index.js +43 -0
  90. package/lib/index.js.map +1 -0
  91. package/lib/vite/api-server.d.ts +54 -0
  92. package/lib/vite/api-server.d.ts.map +1 -0
  93. package/lib/vite/api-server.js +94 -0
  94. package/lib/vite/api-server.js.map +1 -0
  95. package/lib/vite/dev-server.d.ts +42 -0
  96. package/lib/vite/dev-server.d.ts.map +1 -0
  97. package/lib/vite/dev-server.js +111 -0
  98. package/lib/vite/dev-server.js.map +1 -0
  99. package/lib/vite/index.d.ts +15 -0
  100. package/lib/vite/index.d.ts.map +1 -0
  101. package/lib/vite/index.js +15 -0
  102. package/lib/vite/index.js.map +1 -0
  103. package/package.json +38 -28
  104. package/src/bin/build.ts +83 -0
  105. package/src/bin/config.ts +113 -0
  106. package/src/core/compilers/widget.ts +69 -0
  107. package/src/{parsers → core/parsers}/frontmatter.ts +2 -2
  108. package/src/core/transformers/index.ts +27 -0
  109. package/src/{presets → core/transformers}/prompt.ts +35 -32
  110. package/src/{presets → core/transformers}/raw.ts +2 -2
  111. package/src/{presets → core/transformers}/skill-collection.ts +5 -12
  112. package/src/{presets → core/transformers}/skill.ts +119 -99
  113. package/src/{presets → core/transformers}/template-collection.ts +76 -83
  114. package/src/{presets → core/transformers}/template.ts +121 -116
  115. package/src/core/types.ts +71 -0
  116. package/src/{utils → core/utils}/asset-copy.ts +3 -2
  117. package/src/{utils → core/utils}/asset-discovery.ts +5 -5
  118. package/src/{utils → core/utils}/template-asset-discovery.ts +70 -77
  119. package/src/import-transform/builtins.ts +56 -0
  120. package/src/import-transform/chunk-emitter.ts +60 -0
  121. package/src/import-transform/detector.ts +56 -0
  122. package/src/import-transform/index.ts +171 -0
  123. package/src/import-transform/patterns.ts +34 -0
  124. package/src/import-transform/resolver.ts +57 -0
  125. package/src/import-transform/rewriter.ts +48 -0
  126. package/src/import-transform/scanner.ts +55 -0
  127. package/src/index.ts +67 -42
  128. package/src/vite/api-server.ts +142 -0
  129. package/src/vite/dev-server.ts +128 -0
  130. package/src/vite/index.ts +15 -0
  131. package/lib/build-tools.js +0 -2031
  132. package/lib/build-tools.js.map +0 -1
  133. package/lib/cjs/index.js +0 -43
  134. package/lib/cjs/index.js.map +0 -1
  135. package/lib/cjs/package.json +0 -3
  136. package/lib/cjs/parsers/frontmatter.js +0 -25
  137. package/lib/cjs/parsers/frontmatter.js.map +0 -1
  138. package/lib/cjs/plugin.js +0 -150
  139. package/lib/cjs/plugin.js.map +0 -1
  140. package/lib/cjs/presets/index.js +0 -25
  141. package/lib/cjs/presets/index.js.map +0 -1
  142. package/lib/cjs/presets/prompt.js +0 -185
  143. package/lib/cjs/presets/prompt.js.map +0 -1
  144. package/lib/cjs/presets/raw.js +0 -25
  145. package/lib/cjs/presets/raw.js.map +0 -1
  146. package/lib/cjs/presets/skill-collection.js +0 -83
  147. package/lib/cjs/presets/skill-collection.js.map +0 -1
  148. package/lib/cjs/presets/skill.js +0 -272
  149. package/lib/cjs/presets/skill.js.map +0 -1
  150. package/lib/cjs/presets/template-collection.js +0 -80
  151. package/lib/cjs/presets/template-collection.js.map +0 -1
  152. package/lib/cjs/presets/template.js +0 -105
  153. package/lib/cjs/presets/template.js.map +0 -1
  154. package/lib/cjs/types.js +0 -6
  155. package/lib/cjs/utils/asset-copy.js +0 -61
  156. package/lib/cjs/utils/asset-copy.js.map +0 -1
  157. package/lib/cjs/utils/asset-discovery.js +0 -100
  158. package/lib/cjs/utils/asset-discovery.js.map +0 -1
  159. package/lib/cjs/utils/template-asset-discovery.js +0 -63
  160. package/lib/cjs/utils/template-asset-discovery.js.map +0 -1
  161. package/lib/cjs/utils/widget-compiler.js +0 -115
  162. package/lib/cjs/utils/widget-compiler.js.map +0 -1
  163. package/lib/cjs/vite.js +0 -45
  164. package/lib/cjs/vite.js.map +0 -1
  165. package/lib/esm/index.js +0 -26
  166. package/lib/esm/index.js.map +0 -1
  167. package/lib/esm/parsers/frontmatter.js.map +0 -1
  168. package/lib/esm/plugin.js +0 -144
  169. package/lib/esm/plugin.js.map +0 -1
  170. package/lib/esm/presets/index.js +0 -10
  171. package/lib/esm/presets/index.js.map +0 -1
  172. package/lib/esm/presets/prompt.js.map +0 -1
  173. package/lib/esm/presets/raw.js.map +0 -1
  174. package/lib/esm/presets/skill-collection.js.map +0 -1
  175. package/lib/esm/presets/skill.js.map +0 -1
  176. package/lib/esm/presets/template-collection.js.map +0 -1
  177. package/lib/esm/presets/template.js.map +0 -1
  178. package/lib/esm/types.js +0 -5
  179. package/lib/esm/types.js.map +0 -1
  180. package/lib/esm/utils/asset-copy.js.map +0 -1
  181. package/lib/esm/utils/asset-discovery.js.map +0 -1
  182. package/lib/esm/utils/template-asset-discovery.js.map +0 -1
  183. package/lib/esm/utils/widget-compiler.js +0 -76
  184. package/lib/esm/utils/widget-compiler.js.map +0 -1
  185. package/lib/esm/vite.js +0 -42
  186. package/lib/esm/vite.js.map +0 -1
  187. package/lib/types/index.d.ts +0 -24
  188. package/lib/types/index.d.ts.map +0 -1
  189. package/lib/types/parsers/frontmatter.d.ts.map +0 -1
  190. package/lib/types/plugin.d.ts +0 -10
  191. package/lib/types/plugin.d.ts.map +0 -1
  192. package/lib/types/presets/index.d.ts +0 -10
  193. package/lib/types/presets/index.d.ts.map +0 -1
  194. package/lib/types/presets/prompt.d.ts.map +0 -1
  195. package/lib/types/presets/raw.d.ts.map +0 -1
  196. package/lib/types/presets/skill-collection.d.ts.map +0 -1
  197. package/lib/types/presets/skill.d.ts +0 -361
  198. package/lib/types/presets/skill.d.ts.map +0 -1
  199. package/lib/types/presets/template-collection.d.ts.map +0 -1
  200. package/lib/types/presets/template.d.ts.map +0 -1
  201. package/lib/types/types.d.ts.map +0 -1
  202. package/lib/types/utils/asset-copy.d.ts.map +0 -1
  203. package/lib/types/utils/asset-discovery.d.ts.map +0 -1
  204. package/lib/types/utils/template-asset-discovery.d.ts.map +0 -1
  205. package/lib/types/utils/widget-compiler.d.ts +0 -15
  206. package/lib/types/utils/widget-compiler.d.ts.map +0 -1
  207. package/lib/types/vite.d.ts +0 -32
  208. package/lib/types/vite.d.ts.map +0 -1
  209. package/src/plugin.ts +0 -166
  210. package/src/presets/index.ts +0 -10
  211. package/src/types.ts +0 -140
  212. package/src/utils/widget-compiler.ts +0 -98
  213. package/src/vite.ts +0 -45
  214. /package/lib/{types/presets → core/transformers}/raw.d.ts +0 -0
  215. /package/lib/{types/presets → core/transformers}/skill-collection.d.ts +0 -0
  216. /package/lib/{types/presets → core/transformers}/template-collection.d.ts +0 -0
  217. /package/lib/{types → core}/utils/asset-copy.d.ts +0 -0
  218. /package/lib/{esm → core}/utils/asset-copy.js +0 -0
  219. /package/lib/{types → core}/utils/asset-discovery.d.ts +0 -0
  220. /package/lib/{types → core}/utils/template-asset-discovery.d.ts +0 -0
package/package.json CHANGED
@@ -1,10 +1,13 @@
1
1
  {
2
2
  "name": "@vertesia/build-tools",
3
- "version": "1.2.0",
4
- "description": "Build tools for Vertesia projects - Rollup and Vite plugins for transforming imports, bundling skills, and compiling widgets",
3
+ "version": "1.4.0-dev.20260614.160504Z",
4
+ "description": "Build tools for Vertesia projects - import transformers (skill / template / prompt / raw), esbuild widget bundler, vertesia-build CLI, and a Vite dev plugin",
5
5
  "type": "module",
6
- "main": "./lib/esm/index.js",
7
- "types": "./lib/types/index.d.ts",
6
+ "main": "./lib/index.js",
7
+ "types": "./lib/index.d.ts",
8
+ "bin": {
9
+ "vertesia-build": "lib/bin/build.js"
10
+ },
8
11
  "files": [
9
12
  "lib",
10
13
  "src"
@@ -12,38 +15,45 @@
12
15
  "license": "Apache-2.0",
13
16
  "exports": {
14
17
  ".": {
15
- "types": "./lib/types/index.d.ts",
16
- "import": "./lib/esm/index.js",
17
- "require": "./lib/cjs/index.js"
18
+ "types": "./lib/index.d.ts",
19
+ "default": "./lib/index.js"
18
20
  },
19
21
  "./vite": {
20
- "types": "./lib/types/vite.d.ts",
21
- "import": "./lib/esm/vite.js",
22
- "require": "./lib/cjs/vite.js"
22
+ "types": "./lib/vite/index.d.ts",
23
+ "default": "./lib/vite/index.js"
23
24
  }
24
25
  },
25
26
  "devDependencies": {
27
+ "@hono/node-server": "^2.0.4",
28
+ "@types/node": "^24.12.4",
29
+ "typescript": "^6.0.3",
30
+ "vite": "^8.0.16",
31
+ "vitest": "^4.1.8",
32
+ "@vertesia/tsconfig": "0.1.0"
33
+ },
34
+ "dependencies": {
26
35
  "@rollup/plugin-commonjs": "^28.0.3",
36
+ "@rollup/plugin-json": "^6.1.0",
27
37
  "@rollup/plugin-node-resolve": "^16.0.1",
28
38
  "@rollup/plugin-terser": "^0.4.4",
29
39
  "@rollup/plugin-typescript": "^12.1.2",
30
- "@types/node": "^24.1.0",
31
- "rollup": "^4.59.0",
32
- "ts-dual-module": "^0.6.3",
33
- "typescript": "^6.0.2",
34
- "vitest": "^4.0.16"
35
- },
36
- "dependencies": {
40
+ "esbuild": "^0.28.0",
37
41
  "gray-matter": "^4.0.3",
38
- "zod": "^3.24.1",
39
- "@llumiverse/common": "1.1.1-dev.20260505.151157Z",
40
- "@vertesia/common": "1.2.0"
42
+ "zod": "^4.4.3",
43
+ "@vertesia/common": "1.4.0-dev.20260614.160504Z",
44
+ "@llumiverse/common": "1.3.0"
41
45
  },
42
46
  "peerDependencies": {
43
- "rollup": "^4.59.0"
47
+ "@hono/node-server": "^2.0.0",
48
+ "vite": "^8.0.0"
44
49
  },
45
- "ts_dual_module": {
46
- "outDir": "lib"
50
+ "peerDependenciesMeta": {
51
+ "@hono/node-server": {
52
+ "optional": true
53
+ },
54
+ "vite": {
55
+ "optional": true
56
+ }
47
57
  },
48
58
  "repository": {
49
59
  "type": "git",
@@ -52,14 +62,12 @@
52
62
  },
53
63
  "keywords": [
54
64
  "vertesia",
55
- "rollup",
56
- "rollup-plugin",
57
65
  "vite",
58
66
  "vite-plugin",
59
67
  "build-tools",
60
68
  "imports",
61
69
  "transform",
62
- "compiler",
70
+ "esbuild",
63
71
  "skill",
64
72
  "markdown",
65
73
  "frontmatter",
@@ -69,8 +77,10 @@
69
77
  "validation"
70
78
  ],
71
79
  "scripts": {
80
+ "lint": "biome lint src",
72
81
  "test": "vitest run",
73
- "build": "pnpm exec tsmod build && pnpm exec rollup -c",
74
- "clean": "rimraf ./node_modules ./lib ./tsconfig.tsbuildinfo"
82
+ "typecheck:test": "tsc -p tsconfig.test.json --noEmit",
83
+ "build": "rm -rf ./lib ./tsconfig.tsbuildinfo && tsc && chmod +x ./lib/bin/build.js",
84
+ "clean": "rm -rf ./node_modules ./lib ./tsconfig.tsbuildinfo"
75
85
  }
76
86
  }
@@ -0,0 +1,83 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * `vertesia-build` — Vertesia plugin build CLI.
5
+ *
6
+ * Today this runs the post-`tsc` finalization step: import transformation
7
+ * (`?skill` / `?raw` / `?prompt` / `?template` / `?skills` / `?templates`
8
+ * and bare `SKILL.md` / `TEMPLATE.md` imports), asset copying, and esbuild
9
+ * widget bundling.
10
+ *
11
+ * Reads its configuration from the consuming package's `package.json` under
12
+ * the `vertesia-build` key, then delegates to `transformImports` in
13
+ * `@vertesia/build-tools`.
14
+ *
15
+ * Usage in a plugin's package.json:
16
+ *
17
+ * {
18
+ * "scripts": {
19
+ * "build:server": "tsc -p tsconfig.tool-server.json && vertesia-build"
20
+ * },
21
+ * "vertesia-build": {
22
+ * "libDir": "./lib",
23
+ * "srcDir": "./src/tool-server",
24
+ * "transformers": ["skill", "skills", "template", "templates", "prompt", "raw"],
25
+ * "assetsDir": "./dist",
26
+ * "widgetsDir": "widgets",
27
+ * "widgetConfig": { "minify": false }
28
+ * }
29
+ * }
30
+ *
31
+ * Available transformer names: skill, skills, template, templates, prompt, raw.
32
+ * The `transformers` field is required so consumers explicitly opt in to each
33
+ * preset (and so missing or misspelled names fail loudly at build time).
34
+ */
35
+
36
+ import { readFileSync } from 'node:fs';
37
+ import path from 'node:path';
38
+ import { transformImports } from '../import-transform/index.js';
39
+ import { resolveConfig, VertesiaBuildConfigError } from './config.js';
40
+
41
+ function fail(message: string): never {
42
+ console.error(`vertesia-build: ${message}`);
43
+ process.exit(1);
44
+ }
45
+
46
+ function readPackageJson(cwd: string): Record<string, unknown> {
47
+ const pkgPath = path.join(cwd, 'package.json');
48
+ let raw: string;
49
+ try {
50
+ raw = readFileSync(pkgPath, 'utf-8');
51
+ } catch (error) {
52
+ fail(`could not read ${pkgPath}: ${(error as Error).message}`);
53
+ }
54
+ try {
55
+ return JSON.parse(raw) as Record<string, unknown>;
56
+ } catch (error) {
57
+ fail(`could not parse ${pkgPath}: ${(error as Error).message}`);
58
+ }
59
+ }
60
+
61
+ async function main(): Promise<void> {
62
+ const cwd = process.cwd();
63
+ const pkg = readPackageJson(cwd);
64
+ let options;
65
+ try {
66
+ options = resolveConfig(pkg, cwd);
67
+ } catch (error) {
68
+ if (error instanceof VertesiaBuildConfigError) {
69
+ fail(error.message);
70
+ }
71
+ throw error;
72
+ }
73
+ const result = await transformImports(options);
74
+ console.log(
75
+ `vertesia-build: files=${result.filesProcessed} chunks=${result.chunksEmitted} ` +
76
+ `assets=${result.assetsCopied} widgets=${result.widgetsCompiled}`,
77
+ );
78
+ }
79
+
80
+ main().catch((error) => {
81
+ console.error(`vertesia-build: ${(error as Error).stack ?? (error as Error).message}`);
82
+ process.exit(1);
83
+ });
@@ -0,0 +1,113 @@
1
+ /**
2
+ * Pure config-parsing logic for the `vertesia-build` CLI.
3
+ *
4
+ * Lives in its own module so it can be unit-tested without spawning a
5
+ * subprocess. Errors are surfaced as thrown exceptions — the CLI entry
6
+ * point (`build.ts`) catches them and translates to `process.exit(1)`
7
+ * with a clear message.
8
+ */
9
+
10
+ import path from 'node:path';
11
+ import { resolveTransformerNames } from '../import-transform/builtins.js';
12
+ import type { TransformImportsOptions } from '../import-transform/index.js';
13
+
14
+ export const CONFIG_KEY = 'vertesia-build';
15
+
16
+ export class VertesiaBuildConfigError extends Error {
17
+ constructor(message: string) {
18
+ super(message);
19
+ this.name = 'VertesiaBuildConfigError';
20
+ }
21
+ }
22
+
23
+ interface RawConfig {
24
+ libDir?: unknown;
25
+ srcDir?: unknown;
26
+ transformers?: unknown;
27
+ assetsDir?: unknown;
28
+ widgetsDir?: unknown;
29
+ widgetConfig?: unknown;
30
+ }
31
+
32
+ /**
33
+ * Parse and validate the `vertesia-build` block of a package.json.
34
+ *
35
+ * @param pkg Parsed contents of the consuming `package.json`.
36
+ * @param cwd Working directory used to resolve relative paths in the config.
37
+ * @returns Resolved options suitable for passing to `transformImports`.
38
+ * @throws {VertesiaBuildConfigError} when the config is missing, malformed,
39
+ * or references unknown transformers.
40
+ */
41
+ export function resolveConfig(pkg: Record<string, unknown>, cwd: string): TransformImportsOptions {
42
+ const raw = pkg[CONFIG_KEY];
43
+
44
+ if (raw === undefined) {
45
+ throw new VertesiaBuildConfigError(`missing "${CONFIG_KEY}" key in package.json at ${cwd}.`);
46
+ }
47
+ if (typeof raw !== 'object' || raw === null || Array.isArray(raw)) {
48
+ throw new VertesiaBuildConfigError(`"${CONFIG_KEY}" must be an object in package.json.`);
49
+ }
50
+ const cfg = raw as RawConfig;
51
+
52
+ if (typeof cfg.libDir !== 'string' || cfg.libDir.length === 0) {
53
+ throw new VertesiaBuildConfigError(`"${CONFIG_KEY}.libDir" must be a non-empty string.`);
54
+ }
55
+ if (typeof cfg.srcDir !== 'string' || cfg.srcDir.length === 0) {
56
+ throw new VertesiaBuildConfigError(`"${CONFIG_KEY}.srcDir" must be a non-empty string.`);
57
+ }
58
+ if (!Array.isArray(cfg.transformers) || cfg.transformers.length === 0) {
59
+ throw new VertesiaBuildConfigError(
60
+ `"${CONFIG_KEY}.transformers" must be a non-empty array of transformer names.`,
61
+ );
62
+ }
63
+ const names: string[] = [];
64
+ for (const entry of cfg.transformers) {
65
+ if (typeof entry !== 'string' || entry.length === 0) {
66
+ throw new VertesiaBuildConfigError(
67
+ `every entry in "${CONFIG_KEY}.transformers" must be a non-empty string.`,
68
+ );
69
+ }
70
+ names.push(entry);
71
+ }
72
+
73
+ let transformers: TransformImportsOptions['transformers'];
74
+ try {
75
+ transformers = resolveTransformerNames(names);
76
+ } catch (error) {
77
+ // resolveTransformerNames throws plain Error; rewrap so callers can
78
+ // identify config-level failures uniformly.
79
+ throw new VertesiaBuildConfigError((error as Error).message);
80
+ }
81
+
82
+ const resolved: TransformImportsOptions = {
83
+ libDir: path.resolve(cwd, cfg.libDir),
84
+ srcDir: path.resolve(cwd, cfg.srcDir),
85
+ transformers,
86
+ };
87
+
88
+ if (cfg.assetsDir !== undefined) {
89
+ if (cfg.assetsDir === false) {
90
+ resolved.assetsDir = false;
91
+ } else if (typeof cfg.assetsDir === 'string' && cfg.assetsDir.length > 0) {
92
+ resolved.assetsDir = path.resolve(cwd, cfg.assetsDir);
93
+ } else {
94
+ throw new VertesiaBuildConfigError(`"${CONFIG_KEY}.assetsDir" must be a string path or false.`);
95
+ }
96
+ }
97
+
98
+ if (cfg.widgetsDir !== undefined) {
99
+ if (typeof cfg.widgetsDir !== 'string' || cfg.widgetsDir.length === 0) {
100
+ throw new VertesiaBuildConfigError(`"${CONFIG_KEY}.widgetsDir" must be a non-empty string when set.`);
101
+ }
102
+ resolved.widgetsDir = cfg.widgetsDir;
103
+ }
104
+
105
+ if (cfg.widgetConfig !== undefined) {
106
+ if (typeof cfg.widgetConfig !== 'object' || cfg.widgetConfig === null || Array.isArray(cfg.widgetConfig)) {
107
+ throw new VertesiaBuildConfigError(`"${CONFIG_KEY}.widgetConfig" must be an object when set.`);
108
+ }
109
+ resolved.widgetConfig = cfg.widgetConfig as TransformImportsOptions['widgetConfig'];
110
+ }
111
+
112
+ return resolved;
113
+ }
@@ -0,0 +1,69 @@
1
+ /**
2
+ * Widget bundler using esbuild.
3
+ *
4
+ * Takes already-compiled JavaScript widget entries (produced by `tsc` from
5
+ * `.tsx` sources) and emits a single-file ESM bundle with React-family
6
+ * packages left as external imports.
7
+ *
8
+ * No TypeScript / JSX transformation happens here — `tsc` does that during
9
+ * the main build step. This module is a pure module concatenator.
10
+ */
11
+
12
+ import path from 'node:path';
13
+ import { build } from 'esbuild';
14
+
15
+ const DEFAULT_EXTERNALS = ['react', 'react-dom', 'react/jsx-runtime', 'react/jsx-dev-runtime', 'react-dom/client'];
16
+
17
+ export interface WidgetCompilerConfig {
18
+ /** External package names that should not be bundled. */
19
+ external?: string[];
20
+
21
+ /** Minify the output. Default: false */
22
+ minify?: boolean;
23
+
24
+ /** Emit source maps. Default: true */
25
+ sourcemap?: boolean | 'inline' | 'external';
26
+ }
27
+
28
+ export interface WidgetInput {
29
+ /** Widget name (used for the output file name, without extension). */
30
+ name: string;
31
+
32
+ /** Absolute path to the already-compiled `.js` entry to bundle. */
33
+ entry: string;
34
+ }
35
+
36
+ export async function compileWidget(
37
+ widget: WidgetInput,
38
+ outputDir: string,
39
+ config: WidgetCompilerConfig = {},
40
+ ): Promise<string> {
41
+ const { external = DEFAULT_EXTERNALS, minify = false, sourcemap = true } = config;
42
+ const outfile = path.join(outputDir, `${widget.name}.js`);
43
+
44
+ await build({
45
+ entryPoints: [widget.entry],
46
+ outfile,
47
+ bundle: true,
48
+ format: 'esm',
49
+ platform: 'browser',
50
+ external,
51
+ minify,
52
+ sourcemap,
53
+ logLevel: 'silent',
54
+ });
55
+
56
+ return outfile;
57
+ }
58
+
59
+ export async function compileWidgets(
60
+ widgets: WidgetInput[],
61
+ outputDir: string,
62
+ config: WidgetCompilerConfig = {},
63
+ ): Promise<number> {
64
+ if (widgets.length === 0) {
65
+ return 0;
66
+ }
67
+ await Promise.all(widgets.map((widget) => compileWidget(widget, outputDir, config)));
68
+ return widgets.length;
69
+ }
@@ -6,7 +6,7 @@ import matter from 'gray-matter';
6
6
 
7
7
  export interface FrontmatterResult {
8
8
  /** Parsed frontmatter data */
9
- frontmatter: Record<string, any>;
9
+ frontmatter: Record<string, unknown>;
10
10
 
11
11
  /** Content without frontmatter */
12
12
  content: string;
@@ -27,6 +27,6 @@ export function parseFrontmatter(content: string): FrontmatterResult {
27
27
  return {
28
28
  frontmatter: result.data,
29
29
  content: result.content,
30
- original: content
30
+ original: content,
31
31
  };
32
32
  }
@@ -0,0 +1,27 @@
1
+ /**
2
+ * Preset transformers for common use cases
3
+ */
4
+
5
+ export {
6
+ type PromptContentType,
7
+ type PromptDefinition,
8
+ PromptDefinitionSchema,
9
+ PromptRole,
10
+ promptTransformer,
11
+ TemplateType,
12
+ } from './prompt.js';
13
+ export { rawTransformer } from './raw.js';
14
+ export {
15
+ type SkillContentType,
16
+ type SkillDefinition,
17
+ SkillDefinitionSchema,
18
+ SkillPropertiesSchema,
19
+ skillTransformer,
20
+ } from './skill.js';
21
+ export { skillCollectionTransformer } from './skill-collection.js';
22
+ export {
23
+ type RenderingTemplateDefinition,
24
+ RenderingTemplateDefinitionSchema,
25
+ templateTransformer,
26
+ } from './template.js';
27
+ export { templateCollectionTransformer } from './template-collection.js';
@@ -3,17 +3,17 @@
3
3
  * Supports .jst, .hbs, and plain text files
4
4
  */
5
5
 
6
+ import path from 'node:path';
7
+ import { PromptRole } from '@llumiverse/common';
8
+ import { type JSONSchema, TemplateType } from '@vertesia/common';
6
9
  import { z } from 'zod';
7
- import type { TransformerPreset } from '../types.js';
8
10
  import { parseFrontmatter } from '../parsers/frontmatter.js';
9
- import path from 'path';
10
- import { TemplateType } from '@vertesia/common';
11
- import { PromptRole } from '@llumiverse/common';
11
+ import type { TransformerPreset } from '../types.js';
12
12
 
13
13
  /**
14
14
  * Re-export types for backwards compatibility
15
15
  */
16
- export { TemplateType, PromptRole };
16
+ export { PromptRole, TemplateType };
17
17
 
18
18
  /**
19
19
  * Template type alias
@@ -23,18 +23,20 @@ export type PromptContentType = TemplateType;
23
23
  /**
24
24
  * Zod schema for prompt frontmatter validation
25
25
  */
26
- const PromptFrontmatterSchema = z.object({
27
- // Required fields
28
- role: z.nativeEnum(PromptRole, {
29
- errorMap: () => ({ message: 'Role must be one of: safety, system, user, assistant, negative' })
30
- }),
31
-
32
- // Optional fields
33
- content_type: z.nativeEnum(TemplateType).optional(),
34
- schema: z.string().optional(),
35
- name: z.string().optional(),
36
- externalId: z.string().optional(),
37
- }).strict();
26
+ const PromptFrontmatterSchema = z
27
+ .object({
28
+ // Required fields
29
+ role: z.nativeEnum(PromptRole, {
30
+ error: 'Role must be one of: safety, system, user, assistant, negative',
31
+ }),
32
+
33
+ // Optional fields
34
+ content_type: z.nativeEnum(TemplateType).optional(),
35
+ schema: z.string().optional(),
36
+ name: z.string().optional(),
37
+ externalId: z.string().optional(),
38
+ })
39
+ .strict();
38
40
 
39
41
  /**
40
42
  * MUST be kept in sync with @vertesia/common InCodePrompt
@@ -44,7 +46,7 @@ export const PromptDefinitionSchema = z.object({
44
46
  role: z.nativeEnum(PromptRole),
45
47
  content: z.string(),
46
48
  content_type: z.nativeEnum(TemplateType),
47
- schema: z.any().optional(),
49
+ schema: z.custom<JSONSchema>().optional(),
48
50
  name: z.string().optional(),
49
51
  externalId: z.string().optional(),
50
52
  });
@@ -54,6 +56,8 @@ export const PromptDefinitionSchema = z.object({
54
56
  */
55
57
  export type PromptDefinition = z.infer<typeof PromptDefinitionSchema>;
56
58
 
59
+ type PromptFrontmatter = z.infer<typeof PromptFrontmatterSchema>;
60
+
57
61
  /**
58
62
  * Normalize schema path for import
59
63
  * - Adds './' prefix if not a relative path
@@ -68,7 +72,7 @@ function normalizeSchemaPath(schemaPath: string): string {
68
72
 
69
73
  // Add './' prefix if not already a relative path
70
74
  if (!normalized.startsWith('.')) {
71
- normalized = './' + normalized;
75
+ normalized = `./${normalized}`;
72
76
  }
73
77
 
74
78
  // Get the extension
@@ -76,10 +80,10 @@ function normalizeSchemaPath(schemaPath: string): string {
76
80
 
77
81
  if (ext === '.ts') {
78
82
  // Replace .ts with .js
79
- normalized = normalized.slice(0, -3) + '.js';
83
+ normalized = `${normalized.slice(0, -3)}.js`;
80
84
  } else if (!ext) {
81
85
  // No extension, add .js
82
- normalized = normalized + '.js';
86
+ normalized = `${normalized}.js`;
83
87
  }
84
88
  // If extension is already .js or something else, leave as is
85
89
 
@@ -114,13 +118,12 @@ function inferContentType(filePath: string): TemplateType {
114
118
  * @returns Prompt definition object and optional imports
115
119
  */
116
120
  function buildPromptDefinition(
117
- frontmatter: Record<string, any>,
121
+ frontmatter: PromptFrontmatter,
118
122
  content: string,
119
- filePath: string
123
+ filePath: string,
120
124
  ): { prompt: PromptDefinition; imports?: string[]; schemaImportName?: string } {
121
125
  // Determine content type from frontmatter or file extension
122
- const content_type: TemplateType =
123
- frontmatter.content_type || inferContentType(filePath);
126
+ const content_type: TemplateType = frontmatter.content_type || inferContentType(filePath);
124
127
 
125
128
  const prompt: PromptDefinition = {
126
129
  role: frontmatter.role,
@@ -173,22 +176,22 @@ export const promptTransformer: TransformerPreset = {
173
176
  // Validate frontmatter
174
177
  const frontmatterValidation = PromptFrontmatterSchema.safeParse(frontmatter);
175
178
  if (!frontmatterValidation.success) {
176
- const errors = frontmatterValidation.error.errors
179
+ const errors = frontmatterValidation.error.issues
177
180
  .map((err) => {
178
181
  const path = err.path.length > 0 ? err.path.join('.') : 'frontmatter';
179
182
  return ` - ${path}: ${err.message}`;
180
183
  })
181
184
  .join('\n');
182
- throw new Error(
183
- `Invalid frontmatter in ${filePath}:\n${errors}`
184
- );
185
+ throw new Error(`Invalid frontmatter in ${filePath}:\n${errors}`);
185
186
  }
186
187
 
188
+ const validatedFrontmatter = frontmatterValidation.data;
189
+
187
190
  // Build prompt definition
188
191
  const { prompt, imports, schemaImportName } = buildPromptDefinition(
189
- frontmatter,
192
+ validatedFrontmatter,
190
193
  promptContent,
191
- filePath
194
+ filePath,
192
195
  );
193
196
 
194
197
  // If schema is specified, generate custom code with schema reference
@@ -223,5 +226,5 @@ export const promptTransformer: TransformerPreset = {
223
226
  return {
224
227
  data: prompt,
225
228
  };
226
- }
229
+ },
227
230
  };
@@ -18,7 +18,7 @@ export const rawTransformer: TransformerPreset = {
18
18
  pattern: /\?raw$/,
19
19
  transform: (content: string) => {
20
20
  return {
21
- data: content
21
+ data: content,
22
22
  };
23
- }
23
+ },
24
24
  };
@@ -3,7 +3,7 @@
3
3
  * Scans a directory for subdirectories containing SKILL.md files
4
4
  */
5
5
 
6
- import { readdirSync, statSync, existsSync } from 'node:fs';
6
+ import { existsSync, readdirSync, statSync } from 'node:fs';
7
7
  import path from 'node:path';
8
8
  import type { TransformerPreset } from '../types.js';
9
9
 
@@ -61,10 +61,7 @@ export const skillCollectionTransformer: TransformerPreset = {
61
61
  names.push(identifier);
62
62
  }
63
63
  }
64
- } catch (err) {
65
- // Skip entries that can't be read
66
- continue;
67
- }
64
+ } catch {}
68
65
  }
69
66
 
70
67
  if (names.length === 0) {
@@ -72,15 +69,11 @@ export const skillCollectionTransformer: TransformerPreset = {
72
69
  }
73
70
 
74
71
  // Generate code that imports all skills and exports as array
75
- const code = [
76
- ...imports,
77
- '',
78
- `export default [${names.join(', ')}];`
79
- ].join('\n');
72
+ const code = [...imports, '', `export default [${names.join(', ')}];`].join('\n');
80
73
 
81
74
  return {
82
75
  data: null, // Not used when custom code is provided
83
- code
76
+ code,
84
77
  };
85
- }
78
+ },
86
79
  };