@vertesia/build-tools 0.80.0 → 0.80.2
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/lib/build-tools.js +1122 -8
- package/lib/build-tools.js.map +1 -1
- package/lib/cjs/index.js +6 -1
- package/lib/cjs/index.js.map +1 -1
- package/lib/cjs/plugin.js +14 -6
- package/lib/cjs/plugin.js.map +1 -1
- package/lib/cjs/presets/index.js +8 -1
- package/lib/cjs/presets/index.js.map +1 -1
- package/lib/cjs/presets/prompt.js +185 -0
- package/lib/cjs/presets/prompt.js.map +1 -0
- package/lib/cjs/presets/skill-collection.js +83 -0
- package/lib/cjs/presets/skill-collection.js.map +1 -0
- package/lib/esm/index.js +1 -1
- package/lib/esm/index.js.map +1 -1
- package/lib/esm/plugin.js +14 -6
- package/lib/esm/plugin.js.map +1 -1
- package/lib/esm/presets/index.js +2 -0
- package/lib/esm/presets/index.js.map +1 -1
- package/lib/esm/presets/prompt.js +181 -0
- package/lib/esm/presets/prompt.js.map +1 -0
- package/lib/esm/presets/skill-collection.js +77 -0
- package/lib/esm/presets/skill-collection.js.map +1 -0
- package/lib/types/index.d.ts +1 -1
- package/lib/types/index.d.ts.map +1 -1
- package/lib/types/plugin.d.ts.map +1 -1
- package/lib/types/presets/index.d.ts +2 -0
- package/lib/types/presets/index.d.ts.map +1 -1
- package/lib/types/presets/prompt.d.ts +63 -0
- package/lib/types/presets/prompt.d.ts.map +1 -0
- package/lib/types/presets/skill-collection.d.ts +26 -0
- package/lib/types/presets/skill-collection.d.ts.map +1 -0
- package/lib/types/types.d.ts +2 -0
- package/lib/types/types.d.ts.map +1 -1
- package/package.json +4 -2
- package/src/index.ts +8 -1
- package/src/plugin.ts +14 -6
- package/src/presets/index.ts +2 -0
- package/src/presets/prompt.ts +227 -0
- package/src/presets/skill-collection.ts +86 -0
- package/src/types.ts +3 -0
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Skill collection transformer for directory-based skill imports
|
|
3
|
+
* Scans a directory for subdirectories containing SKILL.md files
|
|
4
|
+
*/
|
|
5
|
+
import { readdirSync, statSync, existsSync } from 'node:fs';
|
|
6
|
+
import path from 'node:path';
|
|
7
|
+
/**
|
|
8
|
+
* Skill collection transformer preset
|
|
9
|
+
* Transforms directory imports with ?skills suffix into an array of skill imports
|
|
10
|
+
*
|
|
11
|
+
* Matches:
|
|
12
|
+
* - ./all?skills (recommended - generates all.js in the directory)
|
|
13
|
+
* - ./_skills?skills (generates _skills.js in the directory)
|
|
14
|
+
* - Any path ending with a filename and ?skills
|
|
15
|
+
*
|
|
16
|
+
* NOTE: A filename before ?skills is REQUIRED to avoid naming conflicts.
|
|
17
|
+
* The filename becomes the output module name.
|
|
18
|
+
*
|
|
19
|
+
* @example
|
|
20
|
+
* ```typescript
|
|
21
|
+
* import skills from './all?skills';
|
|
22
|
+
* // Scans current directory for subdirectories with SKILL.md
|
|
23
|
+
* // Generates all.js containing array of all skills
|
|
24
|
+
* ```
|
|
25
|
+
*/
|
|
26
|
+
export const skillCollectionTransformer = {
|
|
27
|
+
pattern: /\/[^/?]+\?skills$/,
|
|
28
|
+
virtual: true, // Indicates this doesn't transform a real file
|
|
29
|
+
transform: (_content, filePath) => {
|
|
30
|
+
// Remove ?skills suffix and the filename to get directory path
|
|
31
|
+
// Example: /path/code/all?skills -> /path/code/all -> /path/code/
|
|
32
|
+
const pathWithoutQuery = filePath.replace(/\?skills$/, '');
|
|
33
|
+
const dirPath = path.dirname(pathWithoutQuery);
|
|
34
|
+
if (!existsSync(dirPath)) {
|
|
35
|
+
throw new Error(`Directory not found: ${dirPath}`);
|
|
36
|
+
}
|
|
37
|
+
if (!statSync(dirPath).isDirectory()) {
|
|
38
|
+
throw new Error(`Not a directory: ${dirPath}`);
|
|
39
|
+
}
|
|
40
|
+
// Scan for subdirectories containing SKILL.md
|
|
41
|
+
const entries = readdirSync(dirPath);
|
|
42
|
+
const imports = [];
|
|
43
|
+
const names = [];
|
|
44
|
+
for (const entry of entries) {
|
|
45
|
+
const entryPath = path.join(dirPath, entry);
|
|
46
|
+
try {
|
|
47
|
+
if (statSync(entryPath).isDirectory()) {
|
|
48
|
+
const skillFile = path.join(entryPath, 'SKILL.md');
|
|
49
|
+
if (existsSync(skillFile)) {
|
|
50
|
+
// Generate unique identifier from directory name
|
|
51
|
+
const identifier = `Skill_${entry.replace(/[^a-zA-Z0-9_]/g, '_')}`;
|
|
52
|
+
imports.push(`import ${identifier} from './${entry}/SKILL.md';`);
|
|
53
|
+
names.push(identifier);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
catch (err) {
|
|
58
|
+
// Skip entries that can't be read
|
|
59
|
+
continue;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
if (names.length === 0) {
|
|
63
|
+
console.warn(`No SKILL.md files found in subdirectories of ${dirPath}`);
|
|
64
|
+
}
|
|
65
|
+
// Generate code that imports all skills and exports as array
|
|
66
|
+
const code = [
|
|
67
|
+
...imports,
|
|
68
|
+
'',
|
|
69
|
+
`export default [${names.join(', ')}];`
|
|
70
|
+
].join('\n');
|
|
71
|
+
return {
|
|
72
|
+
data: null, // Not used when custom code is provided
|
|
73
|
+
code
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
};
|
|
77
|
+
//# sourceMappingURL=skill-collection.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"skill-collection.js","sourceRoot":"","sources":["../../../src/presets/skill-collection.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,WAAW,EAAE,QAAQ,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAC5D,OAAO,IAAI,MAAM,WAAW,CAAC;AAG7B;;;;;;;;;;;;;;;;;;GAkBG;AACH,MAAM,CAAC,MAAM,0BAA0B,GAAsB;IACzD,OAAO,EAAE,mBAAmB;IAC5B,OAAO,EAAE,IAAI,EAAE,+CAA+C;IAC9D,SAAS,EAAE,CAAC,QAAgB,EAAE,QAAgB,EAAE,EAAE;QAC9C,+DAA+D;QAC/D,kEAAkE;QAClE,MAAM,gBAAgB,GAAG,QAAQ,CAAC,OAAO,CAAC,WAAW,EAAE,EAAE,CAAC,CAAC;QAC3D,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC,gBAAgB,CAAC,CAAC;QAE/C,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,EAAE,CAAC;YACvB,MAAM,IAAI,KAAK,CAAC,wBAAwB,OAAO,EAAE,CAAC,CAAC;QACvD,CAAC;QAED,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,WAAW,EAAE,EAAE,CAAC;YACnC,MAAM,IAAI,KAAK,CAAC,oBAAoB,OAAO,EAAE,CAAC,CAAC;QACnD,CAAC;QAED,8CAA8C;QAC9C,MAAM,OAAO,GAAG,WAAW,CAAC,OAAO,CAAC,CAAC;QACrC,MAAM,OAAO,GAAa,EAAE,CAAC;QAC7B,MAAM,KAAK,GAAa,EAAE,CAAC;QAE3B,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;YAC1B,MAAM,SAAS,GAAG,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC;YAE5C,IAAI,CAAC;gBACD,IAAI,QAAQ,CAAC,SAAS,CAAC,CAAC,WAAW,EAAE,EAAE,CAAC;oBACpC,MAAM,SAAS,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,UAAU,CAAC,CAAC;oBACnD,IAAI,UAAU,CAAC,SAAS,CAAC,EAAE,CAAC;wBACxB,iDAAiD;wBACjD,MAAM,UAAU,GAAG,SAAS,KAAK,CAAC,OAAO,CAAC,gBAAgB,EAAE,GAAG,CAAC,EAAE,CAAC;wBACnE,OAAO,CAAC,IAAI,CAAC,UAAU,UAAU,YAAY,KAAK,aAAa,CAAC,CAAC;wBACjE,KAAK,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;oBAC3B,CAAC;gBACL,CAAC;YACL,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBACX,kCAAkC;gBAClC,SAAS;YACb,CAAC;QACL,CAAC;QAED,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACrB,OAAO,CAAC,IAAI,CAAC,gDAAgD,OAAO,EAAE,CAAC,CAAC;QAC5E,CAAC;QAED,6DAA6D;QAC7D,MAAM,IAAI,GAAG;YACT,GAAG,OAAO;YACV,EAAE;YACF,mBAAmB,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI;SAC1C,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAEb,OAAO;YACH,IAAI,EAAE,IAAI,EAAE,wCAAwC;YACpD,IAAI;SACP,CAAC;IACN,CAAC;CACJ,CAAC"}
|
package/lib/types/index.d.ts
CHANGED
|
@@ -19,6 +19,6 @@
|
|
|
19
19
|
*/
|
|
20
20
|
export { vertesiaImportPlugin } from './plugin.js';
|
|
21
21
|
export type { PluginConfig, TransformerRule, TransformerPreset, TransformFunction, TransformResult, AssetFile, WidgetConfig } from './types.js';
|
|
22
|
-
export { skillTransformer, rawTransformer, SkillDefinitionSchema, type SkillDefinition, type SkillContentType } from './presets/index.js';
|
|
22
|
+
export { skillTransformer, rawTransformer, skillCollectionTransformer, promptTransformer, SkillDefinitionSchema, PromptDefinitionSchema, type SkillDefinition, type SkillContentType, type PromptDefinition, type PromptContentType, PromptRole, TemplateType } from './presets/index.js';
|
|
23
23
|
export { parseFrontmatter, type FrontmatterResult } from './parsers/frontmatter.js';
|
|
24
24
|
//# sourceMappingURL=index.d.ts.map
|
package/lib/types/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAGH,OAAO,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAC;AAGnD,YAAY,EACR,YAAY,EACZ,eAAe,EACf,iBAAiB,EACjB,iBAAiB,EACjB,eAAe,EACf,SAAS,EACT,YAAY,EACf,MAAM,YAAY,CAAC;AAGpB,OAAO,EACH,gBAAgB,EAChB,cAAc,EACd,qBAAqB,EACrB,KAAK,eAAe,EACpB,KAAK,gBAAgB,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAGH,OAAO,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAC;AAGnD,YAAY,EACR,YAAY,EACZ,eAAe,EACf,iBAAiB,EACjB,iBAAiB,EACjB,eAAe,EACf,SAAS,EACT,YAAY,EACf,MAAM,YAAY,CAAC;AAGpB,OAAO,EACH,gBAAgB,EAChB,cAAc,EACd,0BAA0B,EAC1B,iBAAiB,EACjB,qBAAqB,EACrB,sBAAsB,EACtB,KAAK,eAAe,EACpB,KAAK,gBAAgB,EACrB,KAAK,gBAAgB,EACrB,KAAK,iBAAiB,EACtB,UAAU,EACV,YAAY,EACf,MAAM,oBAAoB,CAAC;AAG5B,OAAO,EAAE,gBAAgB,EAAE,KAAK,iBAAiB,EAAE,MAAM,0BAA0B,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"plugin.d.ts","sourceRoot":"","sources":["../../src/plugin.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAGrC,OAAO,KAAK,EAAE,YAAY,EAA8B,MAAM,YAAY,CAAC;AAK3E;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,YAAY,GAAG,MAAM,
|
|
1
|
+
{"version":3,"file":"plugin.d.ts","sourceRoot":"","sources":["../../src/plugin.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAGrC,OAAO,KAAK,EAAE,YAAY,EAA8B,MAAM,YAAY,CAAC;AAK3E;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,YAAY,GAAG,MAAM,CAsJjE"}
|
|
@@ -2,5 +2,7 @@
|
|
|
2
2
|
* Preset transformers for common use cases
|
|
3
3
|
*/
|
|
4
4
|
export { skillTransformer, SkillDefinitionSchema, type SkillDefinition, type SkillContentType } from './skill.js';
|
|
5
|
+
export { skillCollectionTransformer } from './skill-collection.js';
|
|
5
6
|
export { rawTransformer } from './raw.js';
|
|
7
|
+
export { promptTransformer, PromptDefinitionSchema, type PromptDefinition, type PromptContentType, PromptRole, TemplateType } from './prompt.js';
|
|
6
8
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/presets/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,gBAAgB,EAAE,qBAAqB,EAAE,KAAK,eAAe,EAAE,KAAK,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAClH,OAAO,EAAE,cAAc,EAAE,MAAM,UAAU,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/presets/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,gBAAgB,EAAE,qBAAqB,EAAE,KAAK,eAAe,EAAE,KAAK,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAClH,OAAO,EAAE,0BAA0B,EAAE,MAAM,uBAAuB,CAAC;AACnE,OAAO,EAAE,cAAc,EAAE,MAAM,UAAU,CAAC;AAC1C,OAAO,EAAE,iBAAiB,EAAE,sBAAsB,EAAE,KAAK,gBAAgB,EAAE,KAAK,iBAAiB,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC"}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Prompt transformer preset for template files with frontmatter
|
|
3
|
+
* Supports .jst, .hbs, and plain text files
|
|
4
|
+
*/
|
|
5
|
+
import { z } from 'zod';
|
|
6
|
+
import type { TransformerPreset } from '../types.js';
|
|
7
|
+
import { TemplateType } from '@vertesia/common';
|
|
8
|
+
import { PromptRole } from '@llumiverse/common';
|
|
9
|
+
/**
|
|
10
|
+
* Re-export types for backwards compatibility
|
|
11
|
+
*/
|
|
12
|
+
export { TemplateType, PromptRole };
|
|
13
|
+
/**
|
|
14
|
+
* Template type alias
|
|
15
|
+
*/
|
|
16
|
+
export type PromptContentType = TemplateType;
|
|
17
|
+
/**
|
|
18
|
+
* MUST be kept in sync with @vertesia/common InCodePrompt
|
|
19
|
+
* Zod schema for prompt definition
|
|
20
|
+
*/
|
|
21
|
+
export declare const PromptDefinitionSchema: z.ZodObject<{
|
|
22
|
+
role: z.ZodNativeEnum<typeof PromptRole>;
|
|
23
|
+
content: z.ZodString;
|
|
24
|
+
content_type: z.ZodNativeEnum<typeof TemplateType>;
|
|
25
|
+
schema: z.ZodOptional<z.ZodAny>;
|
|
26
|
+
name: z.ZodOptional<z.ZodString>;
|
|
27
|
+
externalId: z.ZodOptional<z.ZodString>;
|
|
28
|
+
}, "strip", z.ZodTypeAny, {
|
|
29
|
+
content_type: TemplateType;
|
|
30
|
+
content: string;
|
|
31
|
+
role: PromptRole;
|
|
32
|
+
schema?: any;
|
|
33
|
+
name?: string | undefined;
|
|
34
|
+
externalId?: string | undefined;
|
|
35
|
+
}, {
|
|
36
|
+
content_type: TemplateType;
|
|
37
|
+
content: string;
|
|
38
|
+
role: PromptRole;
|
|
39
|
+
schema?: any;
|
|
40
|
+
name?: string | undefined;
|
|
41
|
+
externalId?: string | undefined;
|
|
42
|
+
}>;
|
|
43
|
+
/**
|
|
44
|
+
* TypeScript type inferred from the Zod schema
|
|
45
|
+
*/
|
|
46
|
+
export type PromptDefinition = z.infer<typeof PromptDefinitionSchema>;
|
|
47
|
+
/**
|
|
48
|
+
* Prompt transformer preset
|
|
49
|
+
* Transforms template files with ?prompt suffix into prompt definition objects
|
|
50
|
+
*
|
|
51
|
+
* Supported file types:
|
|
52
|
+
* - .jst (JavaScript template literals) → content_type: 'jst'
|
|
53
|
+
* - .hbs (Handlebars templates) → content_type: 'handlebars'
|
|
54
|
+
* - .txt or other → content_type: 'text'
|
|
55
|
+
*
|
|
56
|
+
* @example
|
|
57
|
+
* ```typescript
|
|
58
|
+
* import PROMPT from './prompt.hbs?prompt';
|
|
59
|
+
* // PROMPT is an InCodePrompt object
|
|
60
|
+
* ```
|
|
61
|
+
*/
|
|
62
|
+
export declare const promptTransformer: TransformerPreset;
|
|
63
|
+
//# sourceMappingURL=prompt.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"prompt.d.ts","sourceRoot":"","sources":["../../../src/presets/prompt.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAGrD,OAAO,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAChD,OAAO,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAEhD;;GAEG;AACH,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,CAAC;AAEpC;;GAEG;AACH,MAAM,MAAM,iBAAiB,GAAG,YAAY,CAAC;AAkB7C;;;GAGG;AACH,eAAO,MAAM,sBAAsB;;;;;;;;;;;;;;;;;;;;;EAOjC,CAAC;AAEH;;GAEG;AACH,MAAM,MAAM,gBAAgB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,sBAAsB,CAAC,CAAC;AAiGtE;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,iBAAiB,EAAE,iBA4D/B,CAAC"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Skill collection transformer for directory-based skill imports
|
|
3
|
+
* Scans a directory for subdirectories containing SKILL.md files
|
|
4
|
+
*/
|
|
5
|
+
import type { TransformerPreset } from '../types.js';
|
|
6
|
+
/**
|
|
7
|
+
* Skill collection transformer preset
|
|
8
|
+
* Transforms directory imports with ?skills suffix into an array of skill imports
|
|
9
|
+
*
|
|
10
|
+
* Matches:
|
|
11
|
+
* - ./all?skills (recommended - generates all.js in the directory)
|
|
12
|
+
* - ./_skills?skills (generates _skills.js in the directory)
|
|
13
|
+
* - Any path ending with a filename and ?skills
|
|
14
|
+
*
|
|
15
|
+
* NOTE: A filename before ?skills is REQUIRED to avoid naming conflicts.
|
|
16
|
+
* The filename becomes the output module name.
|
|
17
|
+
*
|
|
18
|
+
* @example
|
|
19
|
+
* ```typescript
|
|
20
|
+
* import skills from './all?skills';
|
|
21
|
+
* // Scans current directory for subdirectories with SKILL.md
|
|
22
|
+
* // Generates all.js containing array of all skills
|
|
23
|
+
* ```
|
|
24
|
+
*/
|
|
25
|
+
export declare const skillCollectionTransformer: TransformerPreset;
|
|
26
|
+
//# sourceMappingURL=skill-collection.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"skill-collection.d.ts","sourceRoot":"","sources":["../../../src/presets/skill-collection.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAIH,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAErD;;;;;;;;;;;;;;;;;;GAkBG;AACH,eAAO,MAAM,0BAA0B,EAAE,iBAyDxC,CAAC"}
|
package/lib/types/types.d.ts
CHANGED
|
@@ -46,6 +46,8 @@ export interface TransformerRule {
|
|
|
46
46
|
transform: TransformFunction;
|
|
47
47
|
/** Optional: Zod schema for validation */
|
|
48
48
|
schema?: z.ZodType<any>;
|
|
49
|
+
/** Optional: If true, the transformer generates virtual modules (no file to read) */
|
|
50
|
+
virtual?: boolean;
|
|
49
51
|
/** Optional: additional options for this transformer */
|
|
50
52
|
options?: Record<string, unknown>;
|
|
51
53
|
}
|
package/lib/types/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/types.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AACrC,OAAO,KAAK,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAE7B;;GAEG;AACH,MAAM,WAAW,SAAS;IACtB,kCAAkC;IAClC,UAAU,EAAE,MAAM,CAAC;IAEnB,wDAAwD;IACxD,QAAQ,EAAE,MAAM,CAAC;IAEjB,oCAAoC;IACpC,IAAI,EAAE,QAAQ,CAAC;CAClB;AAED;;GAEG;AACH,MAAM,WAAW,eAAe;IAC5B,sDAAsD;IACtD,IAAI,EAAE,OAAO,CAAC;IAEd,gFAAgF;IAChF,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IAEnB,uEAAuE;IACvE,IAAI,CAAC,EAAE,MAAM,CAAC;IAEd,+CAA+C;IAC/C,MAAM,CAAC,EAAE,SAAS,EAAE,CAAC;IAErB,gDAAgD;IAChD,OAAO,CAAC,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CACnD;AAED;;GAEG;AACH,MAAM,MAAM,iBAAiB,GAAG,CAC5B,OAAO,EAAE,MAAM,EACf,QAAQ,EAAE,MAAM,KACf,eAAe,GAAG,OAAO,CAAC,eAAe,CAAC,CAAC;AAEhD;;GAEG;AACH,MAAM,WAAW,eAAe;IAC5B,uEAAuE;IACvE,OAAO,EAAE,MAAM,CAAC;IAEhB,iDAAiD;IACjD,SAAS,EAAE,iBAAiB,CAAC;IAE7B,0CAA0C;IAC1C,MAAM,CAAC,EAAE,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;IAExB,wDAAwD;IACxD,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACrC;AAED;;GAEG;AACH,MAAM,WAAW,YAAY;IACzB;;;OAGG;IACH,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;IAEpB;;;OAGG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAElB;;OAEG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAErC;;;OAGG;IACH,MAAM,CAAC,EAAE,OAAO,CAAC;CACpB;AAED;;GAEG;AACH,MAAM,WAAW,YAAY;IACzB,0CAA0C;IAC1C,YAAY,EAAE,eAAe,EAAE,CAAC;IAEhC;;;;;OAKG;IACH,SAAS,CAAC,EAAE,MAAM,GAAG,KAAK,CAAC;IAE3B;;;OAGG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;IAEpB;;;OAGG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;IAEpB;;;OAGG;IACH,YAAY,CAAC,EAAE,YAAY,CAAC;CAC/B;AAED;;GAEG;AACH,MAAM,MAAM,iBAAiB,GAAG,eAAe,CAAC;AAEhD;;GAEG;AACH,MAAM,MAAM,oBAAoB,GAAG,CAAC,MAAM,EAAE,YAAY,KAAK,MAAM,CAAC"}
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/types.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AACrC,OAAO,KAAK,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAE7B;;GAEG;AACH,MAAM,WAAW,SAAS;IACtB,kCAAkC;IAClC,UAAU,EAAE,MAAM,CAAC;IAEnB,wDAAwD;IACxD,QAAQ,EAAE,MAAM,CAAC;IAEjB,oCAAoC;IACpC,IAAI,EAAE,QAAQ,CAAC;CAClB;AAED;;GAEG;AACH,MAAM,WAAW,eAAe;IAC5B,sDAAsD;IACtD,IAAI,EAAE,OAAO,CAAC;IAEd,gFAAgF;IAChF,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IAEnB,uEAAuE;IACvE,IAAI,CAAC,EAAE,MAAM,CAAC;IAEd,+CAA+C;IAC/C,MAAM,CAAC,EAAE,SAAS,EAAE,CAAC;IAErB,gDAAgD;IAChD,OAAO,CAAC,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CACnD;AAED;;GAEG;AACH,MAAM,MAAM,iBAAiB,GAAG,CAC5B,OAAO,EAAE,MAAM,EACf,QAAQ,EAAE,MAAM,KACf,eAAe,GAAG,OAAO,CAAC,eAAe,CAAC,CAAC;AAEhD;;GAEG;AACH,MAAM,WAAW,eAAe;IAC5B,uEAAuE;IACvE,OAAO,EAAE,MAAM,CAAC;IAEhB,iDAAiD;IACjD,SAAS,EAAE,iBAAiB,CAAC;IAE7B,0CAA0C;IAC1C,MAAM,CAAC,EAAE,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;IAExB,qFAAqF;IACrF,OAAO,CAAC,EAAE,OAAO,CAAC;IAElB,wDAAwD;IACxD,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACrC;AAED;;GAEG;AACH,MAAM,WAAW,YAAY;IACzB;;;OAGG;IACH,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;IAEpB;;;OAGG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAElB;;OAEG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAErC;;;OAGG;IACH,MAAM,CAAC,EAAE,OAAO,CAAC;CACpB;AAED;;GAEG;AACH,MAAM,WAAW,YAAY;IACzB,0CAA0C;IAC1C,YAAY,EAAE,eAAe,EAAE,CAAC;IAEhC;;;;;OAKG;IACH,SAAS,CAAC,EAAE,MAAM,GAAG,KAAK,CAAC;IAE3B;;;OAGG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;IAEpB;;;OAGG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;IAEpB;;;OAGG;IACH,YAAY,CAAC,EAAE,YAAY,CAAC;CAC/B;AAED;;GAEG;AACH,MAAM,MAAM,iBAAiB,GAAG,eAAe,CAAC;AAEhD;;GAEG;AACH,MAAM,MAAM,oBAAoB,GAAG,CAAC,MAAM,EAAE,YAAY,KAAK,MAAM,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vertesia/build-tools",
|
|
3
|
-
"version": "0.80.
|
|
3
|
+
"version": "0.80.2",
|
|
4
4
|
"description": "Build tools for Vertesia projects - Rollup and Vite plugins for transforming imports, bundling skills, and compiling widgets",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./lib/esm/index.js",
|
|
@@ -28,7 +28,9 @@
|
|
|
28
28
|
},
|
|
29
29
|
"dependencies": {
|
|
30
30
|
"gray-matter": "^4.0.3",
|
|
31
|
-
"zod": "^3.24.1"
|
|
31
|
+
"zod": "^3.24.1",
|
|
32
|
+
"@vertesia/common": "0.81.0",
|
|
33
|
+
"@llumiverse/common": "0.24.0"
|
|
32
34
|
},
|
|
33
35
|
"peerDependencies": {
|
|
34
36
|
"rollup": "^4.0.0"
|
package/src/index.ts
CHANGED
|
@@ -36,9 +36,16 @@ export type {
|
|
|
36
36
|
export {
|
|
37
37
|
skillTransformer,
|
|
38
38
|
rawTransformer,
|
|
39
|
+
skillCollectionTransformer,
|
|
40
|
+
promptTransformer,
|
|
39
41
|
SkillDefinitionSchema,
|
|
42
|
+
PromptDefinitionSchema,
|
|
40
43
|
type SkillDefinition,
|
|
41
|
-
type SkillContentType
|
|
44
|
+
type SkillContentType,
|
|
45
|
+
type PromptDefinition,
|
|
46
|
+
type PromptContentType,
|
|
47
|
+
PromptRole,
|
|
48
|
+
TemplateType
|
|
42
49
|
} from './presets/index.js';
|
|
43
50
|
|
|
44
51
|
// Utilities
|
package/src/plugin.ts
CHANGED
|
@@ -39,7 +39,13 @@ export function vertesiaImportPlugin(config: PluginConfig): Plugin {
|
|
|
39
39
|
// Handle relative imports
|
|
40
40
|
if (source.startsWith('.') && importer) {
|
|
41
41
|
const cleanSource = source.replace(transformer.pattern, '');
|
|
42
|
-
|
|
42
|
+
// Strip query parameters from importer to get the file path
|
|
43
|
+
const cleanImporter = importer.indexOf('?') >= 0
|
|
44
|
+
? importer.substring(0, importer.indexOf('?'))
|
|
45
|
+
: importer;
|
|
46
|
+
// Always use dirname to get the directory containing the importer
|
|
47
|
+
const baseDir = path.dirname(cleanImporter);
|
|
48
|
+
const resolved = path.resolve(baseDir, cleanSource);
|
|
43
49
|
// Return with the pattern suffix to identify it in load
|
|
44
50
|
const suffix = source.match(transformer.pattern)?.[0] || '';
|
|
45
51
|
return resolved + suffix;
|
|
@@ -75,8 +81,10 @@ export function vertesiaImportPlugin(config: PluginConfig): Plugin {
|
|
|
75
81
|
}
|
|
76
82
|
|
|
77
83
|
try {
|
|
78
|
-
// Read file content
|
|
79
|
-
const content =
|
|
84
|
+
// Read file content (skip for virtual transforms)
|
|
85
|
+
const content = matchedTransformer.virtual
|
|
86
|
+
? ''
|
|
87
|
+
: readFileSync(cleanId, 'utf-8');
|
|
80
88
|
|
|
81
89
|
// Transform the content
|
|
82
90
|
const result = await matchedTransformer.transform(content, cleanId);
|
|
@@ -105,12 +113,12 @@ export function vertesiaImportPlugin(config: PluginConfig): Plugin {
|
|
|
105
113
|
}
|
|
106
114
|
|
|
107
115
|
// Generate code
|
|
116
|
+
const imports = result.imports ? result.imports.join('\n') + '\n\n' : '';
|
|
108
117
|
if (result.code) {
|
|
109
|
-
// Custom code provided
|
|
110
|
-
return result.code;
|
|
118
|
+
// Custom code provided - prepend imports
|
|
119
|
+
return imports + result.code;
|
|
111
120
|
} else {
|
|
112
121
|
// Default: export data (escape if string, otherwise stringify as JSON)
|
|
113
|
-
const imports = result.imports ? result.imports.join('\n') + '\n\n' : '';
|
|
114
122
|
const dataJson = JSON.stringify(result.data, null, 2);
|
|
115
123
|
return `${imports}export default ${dataJson};`;
|
|
116
124
|
}
|
package/src/presets/index.ts
CHANGED
|
@@ -3,4 +3,6 @@
|
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
5
|
export { skillTransformer, SkillDefinitionSchema, type SkillDefinition, type SkillContentType } from './skill.js';
|
|
6
|
+
export { skillCollectionTransformer } from './skill-collection.js';
|
|
6
7
|
export { rawTransformer } from './raw.js';
|
|
8
|
+
export { promptTransformer, PromptDefinitionSchema, type PromptDefinition, type PromptContentType, PromptRole, TemplateType } from './prompt.js';
|
|
@@ -0,0 +1,227 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Prompt transformer preset for template files with frontmatter
|
|
3
|
+
* Supports .jst, .hbs, and plain text files
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { z } from 'zod';
|
|
7
|
+
import type { TransformerPreset } from '../types.js';
|
|
8
|
+
import { parseFrontmatter } from '../parsers/frontmatter.js';
|
|
9
|
+
import path from 'path';
|
|
10
|
+
import { TemplateType } from '@vertesia/common';
|
|
11
|
+
import { PromptRole } from '@llumiverse/common';
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Re-export types for backwards compatibility
|
|
15
|
+
*/
|
|
16
|
+
export { TemplateType, PromptRole };
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Template type alias
|
|
20
|
+
*/
|
|
21
|
+
export type PromptContentType = TemplateType;
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Zod schema for prompt frontmatter validation
|
|
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();
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* MUST be kept in sync with @vertesia/common InCodePrompt
|
|
41
|
+
* Zod schema for prompt definition
|
|
42
|
+
*/
|
|
43
|
+
export const PromptDefinitionSchema = z.object({
|
|
44
|
+
role: z.nativeEnum(PromptRole),
|
|
45
|
+
content: z.string(),
|
|
46
|
+
content_type: z.nativeEnum(TemplateType),
|
|
47
|
+
schema: z.any().optional(),
|
|
48
|
+
name: z.string().optional(),
|
|
49
|
+
externalId: z.string().optional(),
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* TypeScript type inferred from the Zod schema
|
|
54
|
+
*/
|
|
55
|
+
export type PromptDefinition = z.infer<typeof PromptDefinitionSchema>;
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Normalize schema path for import
|
|
59
|
+
* - Adds './' prefix if not a relative path
|
|
60
|
+
* - Replaces .ts with .js
|
|
61
|
+
* - Adds .js if no extension
|
|
62
|
+
*
|
|
63
|
+
* @param schemaPath - Original schema path from frontmatter
|
|
64
|
+
* @returns Normalized path for ES module import
|
|
65
|
+
*/
|
|
66
|
+
function normalizeSchemaPath(schemaPath: string): string {
|
|
67
|
+
let normalized = schemaPath.trim();
|
|
68
|
+
|
|
69
|
+
// Add './' prefix if not already a relative path
|
|
70
|
+
if (!normalized.startsWith('.')) {
|
|
71
|
+
normalized = './' + normalized;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// Get the extension
|
|
75
|
+
const ext = path.extname(normalized);
|
|
76
|
+
|
|
77
|
+
if (ext === '.ts') {
|
|
78
|
+
// Replace .ts with .js
|
|
79
|
+
normalized = normalized.slice(0, -3) + '.js';
|
|
80
|
+
} else if (!ext) {
|
|
81
|
+
// No extension, add .js
|
|
82
|
+
normalized = normalized + '.js';
|
|
83
|
+
}
|
|
84
|
+
// If extension is already .js or something else, leave as is
|
|
85
|
+
|
|
86
|
+
return normalized;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Infer content type from file extension
|
|
91
|
+
*
|
|
92
|
+
* @param filePath - Path to the prompt file
|
|
93
|
+
* @returns Inferred content type
|
|
94
|
+
*/
|
|
95
|
+
function inferContentType(filePath: string): TemplateType {
|
|
96
|
+
const ext = path.extname(filePath).toLowerCase();
|
|
97
|
+
|
|
98
|
+
switch (ext) {
|
|
99
|
+
case '.jst':
|
|
100
|
+
return TemplateType.jst;
|
|
101
|
+
case '.hbs':
|
|
102
|
+
return TemplateType.handlebars;
|
|
103
|
+
default:
|
|
104
|
+
return TemplateType.text;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* Build a PromptDefinition from frontmatter and content
|
|
110
|
+
*
|
|
111
|
+
* @param frontmatter - Parsed frontmatter object
|
|
112
|
+
* @param content - Prompt content (body of the file)
|
|
113
|
+
* @param filePath - Path to the prompt file (for content type inference)
|
|
114
|
+
* @returns Prompt definition object and optional imports
|
|
115
|
+
*/
|
|
116
|
+
function buildPromptDefinition(
|
|
117
|
+
frontmatter: Record<string, any>,
|
|
118
|
+
content: string,
|
|
119
|
+
filePath: string
|
|
120
|
+
): { prompt: PromptDefinition; imports?: string[]; schemaImportName?: string } {
|
|
121
|
+
// Determine content type from frontmatter or file extension
|
|
122
|
+
const content_type: TemplateType =
|
|
123
|
+
frontmatter.content_type || inferContentType(filePath);
|
|
124
|
+
|
|
125
|
+
const prompt: PromptDefinition = {
|
|
126
|
+
role: frontmatter.role,
|
|
127
|
+
content,
|
|
128
|
+
content_type,
|
|
129
|
+
};
|
|
130
|
+
|
|
131
|
+
// Add optional fields
|
|
132
|
+
if (frontmatter.name) {
|
|
133
|
+
prompt.name = frontmatter.name;
|
|
134
|
+
}
|
|
135
|
+
if (frontmatter.externalId) {
|
|
136
|
+
prompt.externalId = frontmatter.externalId;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
// Handle schema import if specified
|
|
140
|
+
let imports: string[] | undefined;
|
|
141
|
+
let schemaImportName: string | undefined;
|
|
142
|
+
|
|
143
|
+
if (frontmatter.schema) {
|
|
144
|
+
const normalizedPath = normalizeSchemaPath(frontmatter.schema);
|
|
145
|
+
schemaImportName = '__promptSchema';
|
|
146
|
+
imports = [`import ${schemaImportName} from '${normalizedPath}';`];
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
return { prompt, imports, schemaImportName };
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
/**
|
|
153
|
+
* Prompt transformer preset
|
|
154
|
+
* Transforms template files with ?prompt suffix into prompt definition objects
|
|
155
|
+
*
|
|
156
|
+
* Supported file types:
|
|
157
|
+
* - .jst (JavaScript template literals) → content_type: 'jst'
|
|
158
|
+
* - .hbs (Handlebars templates) → content_type: 'handlebars'
|
|
159
|
+
* - .txt or other → content_type: 'text'
|
|
160
|
+
*
|
|
161
|
+
* @example
|
|
162
|
+
* ```typescript
|
|
163
|
+
* import PROMPT from './prompt.hbs?prompt';
|
|
164
|
+
* // PROMPT is an InCodePrompt object
|
|
165
|
+
* ```
|
|
166
|
+
*/
|
|
167
|
+
export const promptTransformer: TransformerPreset = {
|
|
168
|
+
pattern: /\?prompt$/,
|
|
169
|
+
schema: PromptDefinitionSchema,
|
|
170
|
+
transform: (content: string, filePath: string) => {
|
|
171
|
+
const { frontmatter, content: promptContent } = parseFrontmatter(content);
|
|
172
|
+
|
|
173
|
+
// Validate frontmatter
|
|
174
|
+
const frontmatterValidation = PromptFrontmatterSchema.safeParse(frontmatter);
|
|
175
|
+
if (!frontmatterValidation.success) {
|
|
176
|
+
const errors = frontmatterValidation.error.errors
|
|
177
|
+
.map((err) => {
|
|
178
|
+
const path = err.path.length > 0 ? err.path.join('.') : 'frontmatter';
|
|
179
|
+
return ` - ${path}: ${err.message}`;
|
|
180
|
+
})
|
|
181
|
+
.join('\n');
|
|
182
|
+
throw new Error(
|
|
183
|
+
`Invalid frontmatter in ${filePath}:\n${errors}`
|
|
184
|
+
);
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
// Build prompt definition
|
|
188
|
+
const { prompt, imports, schemaImportName } = buildPromptDefinition(
|
|
189
|
+
frontmatter,
|
|
190
|
+
promptContent,
|
|
191
|
+
filePath
|
|
192
|
+
);
|
|
193
|
+
|
|
194
|
+
// If schema is specified, generate custom code with schema reference
|
|
195
|
+
if (schemaImportName) {
|
|
196
|
+
// Build the code manually to avoid JSON.stringify issues with schema reference
|
|
197
|
+
const lines = [
|
|
198
|
+
'export default {',
|
|
199
|
+
` role: "${prompt.role}",`,
|
|
200
|
+
` content: ${JSON.stringify(prompt.content)},`,
|
|
201
|
+
` content_type: "${prompt.content_type}",`,
|
|
202
|
+
` schema: ${schemaImportName}`,
|
|
203
|
+
];
|
|
204
|
+
|
|
205
|
+
if (prompt.name) {
|
|
206
|
+
lines.splice(4, 0, ` name: ${JSON.stringify(prompt.name)},`);
|
|
207
|
+
}
|
|
208
|
+
if (prompt.externalId) {
|
|
209
|
+
lines.splice(4, 0, ` externalId: ${JSON.stringify(prompt.externalId)},`);
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
lines.push('};');
|
|
213
|
+
const code = lines.join('\n');
|
|
214
|
+
|
|
215
|
+
return {
|
|
216
|
+
data: prompt,
|
|
217
|
+
imports,
|
|
218
|
+
code,
|
|
219
|
+
};
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
// Standard case without schema
|
|
223
|
+
return {
|
|
224
|
+
data: prompt,
|
|
225
|
+
};
|
|
226
|
+
}
|
|
227
|
+
};
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Skill collection transformer for directory-based skill imports
|
|
3
|
+
* Scans a directory for subdirectories containing SKILL.md files
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { readdirSync, statSync, existsSync } from 'node:fs';
|
|
7
|
+
import path from 'node:path';
|
|
8
|
+
import type { TransformerPreset } from '../types.js';
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Skill collection transformer preset
|
|
12
|
+
* Transforms directory imports with ?skills suffix into an array of skill imports
|
|
13
|
+
*
|
|
14
|
+
* Matches:
|
|
15
|
+
* - ./all?skills (recommended - generates all.js in the directory)
|
|
16
|
+
* - ./_skills?skills (generates _skills.js in the directory)
|
|
17
|
+
* - Any path ending with a filename and ?skills
|
|
18
|
+
*
|
|
19
|
+
* NOTE: A filename before ?skills is REQUIRED to avoid naming conflicts.
|
|
20
|
+
* The filename becomes the output module name.
|
|
21
|
+
*
|
|
22
|
+
* @example
|
|
23
|
+
* ```typescript
|
|
24
|
+
* import skills from './all?skills';
|
|
25
|
+
* // Scans current directory for subdirectories with SKILL.md
|
|
26
|
+
* // Generates all.js containing array of all skills
|
|
27
|
+
* ```
|
|
28
|
+
*/
|
|
29
|
+
export const skillCollectionTransformer: TransformerPreset = {
|
|
30
|
+
pattern: /\/[^/?]+\?skills$/,
|
|
31
|
+
virtual: true, // Indicates this doesn't transform a real file
|
|
32
|
+
transform: (_content: string, filePath: string) => {
|
|
33
|
+
// Remove ?skills suffix and the filename to get directory path
|
|
34
|
+
// Example: /path/code/all?skills -> /path/code/all -> /path/code/
|
|
35
|
+
const pathWithoutQuery = filePath.replace(/\?skills$/, '');
|
|
36
|
+
const dirPath = path.dirname(pathWithoutQuery);
|
|
37
|
+
|
|
38
|
+
if (!existsSync(dirPath)) {
|
|
39
|
+
throw new Error(`Directory not found: ${dirPath}`);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
if (!statSync(dirPath).isDirectory()) {
|
|
43
|
+
throw new Error(`Not a directory: ${dirPath}`);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// Scan for subdirectories containing SKILL.md
|
|
47
|
+
const entries = readdirSync(dirPath);
|
|
48
|
+
const imports: string[] = [];
|
|
49
|
+
const names: string[] = [];
|
|
50
|
+
|
|
51
|
+
for (const entry of entries) {
|
|
52
|
+
const entryPath = path.join(dirPath, entry);
|
|
53
|
+
|
|
54
|
+
try {
|
|
55
|
+
if (statSync(entryPath).isDirectory()) {
|
|
56
|
+
const skillFile = path.join(entryPath, 'SKILL.md');
|
|
57
|
+
if (existsSync(skillFile)) {
|
|
58
|
+
// Generate unique identifier from directory name
|
|
59
|
+
const identifier = `Skill_${entry.replace(/[^a-zA-Z0-9_]/g, '_')}`;
|
|
60
|
+
imports.push(`import ${identifier} from './${entry}/SKILL.md';`);
|
|
61
|
+
names.push(identifier);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
} catch (err) {
|
|
65
|
+
// Skip entries that can't be read
|
|
66
|
+
continue;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
if (names.length === 0) {
|
|
71
|
+
console.warn(`No SKILL.md files found in subdirectories of ${dirPath}`);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// Generate code that imports all skills and exports as array
|
|
75
|
+
const code = [
|
|
76
|
+
...imports,
|
|
77
|
+
'',
|
|
78
|
+
`export default [${names.join(', ')}];`
|
|
79
|
+
].join('\n');
|
|
80
|
+
|
|
81
|
+
return {
|
|
82
|
+
data: null, // Not used when custom code is provided
|
|
83
|
+
code
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
};
|
package/src/types.ts
CHANGED
|
@@ -60,6 +60,9 @@ export interface TransformerRule {
|
|
|
60
60
|
/** Optional: Zod schema for validation */
|
|
61
61
|
schema?: z.ZodType<any>;
|
|
62
62
|
|
|
63
|
+
/** Optional: If true, the transformer generates virtual modules (no file to read) */
|
|
64
|
+
virtual?: boolean;
|
|
65
|
+
|
|
63
66
|
/** Optional: additional options for this transformer */
|
|
64
67
|
options?: Record<string, unknown>;
|
|
65
68
|
}
|