1import path from 'path';
2import { cleanDir, ensureDir, writeFile, generateYamlFrontmatter, replacePlaceholders, prefixSkillReferences } from '../utils.js';
3
4/**
5 * Shared transformer logic for all providers.
6 *
7 * @param {Object} config - Provider-specific configuration
8 * @param {string} config.provider - Provider key for placeholders (e.g., 'claude-code')
9 * @param {string} config.displayName - Display name for logging (e.g., 'Claude Code')
10 * @param {string} config.configDir - Dot-directory name (e.g., '.claude')
11 * @param {Function} config.buildFrontmatter - (skill, skillName) => frontmatter object
12 * @param {Function} [config.transformBody] - Optional (body, skill) => transformed body
13 * @param {Array} skills - All skills
14 * @param {string} distDir - Distribution output directory
15 * @param {Object} options - Optional settings (prefix, outputSuffix)
16 */
17export function transformProvider(config, skills, distDir, options = {}) {
18 const { provider, displayName, configDir, buildFrontmatter, transformBody } = config;
19 const { prefix = '', outputSuffix = '' } = options;
20 const providerDir = path.join(distDir, `${provider}${outputSuffix}`);
21 const skillsDir = path.join(providerDir, `${configDir}/skills`);
22
23 cleanDir(providerDir);
24 ensureDir(skillsDir);
25
26 const allSkillNames = skills.map(s => s.name);
27 const commandNames = skills.filter(s => s.userInvokable).map(s => `${prefix}${s.name}`);
28 let refCount = 0;
29 let scriptCount = 0;
30
31 for (const skill of skills) {
32 const skillName = `${prefix}${skill.name}`;
33 const skillDir = path.join(skillsDir, skillName);
34
35 const frontmatterObj = buildFrontmatter(skill, skillName);
36 const frontmatter = generateYamlFrontmatter(frontmatterObj);
37
38 let skillBody = replacePlaceholders(skill.body, provider, commandNames);
39
40 // Replace {{scripts_path}} with provider-aware path to skill's scripts directory
41 const scriptsPath = provider === 'claude-code'
42 ? '${CLAUDE_PLUGIN_ROOT}/scripts'
43 : `${configDir}/skills/${skillName}/scripts`;
44 skillBody = skillBody.replace(/\{\{scripts_path\}\}/g, scriptsPath);
45
46 if (prefix) skillBody = prefixSkillReferences(skillBody, prefix, allSkillNames);
47 if (transformBody) skillBody = transformBody(skillBody, skill);
48
49 const content = `${frontmatter}\n\n${skillBody}`;
50 writeFile(path.join(skillDir, 'SKILL.md'), content);
51
52 // Copy reference files if they exist
53 if (skill.references && skill.references.length > 0) {
54 const refDir = path.join(skillDir, 'reference');
55 ensureDir(refDir);
56 for (const ref of skill.references) {
57 writeFile(
58 path.join(refDir, `${ref.name}.md`),
59 replacePlaceholders(ref.content, provider)
60 );
61 refCount++;
62 }
63 }
64
65 // Copy script files if they exist
66 if (skill.scripts && skill.scripts.length > 0) {
67 const scriptsOutDir = path.join(skillDir, 'scripts');
68 ensureDir(scriptsOutDir);
69 for (const script of skill.scripts) {
70 writeFile(path.join(scriptsOutDir, script.name), script.content);
71 scriptCount++;
72 }
73 }
74 }
75
76 const userInvokableCount = skills.filter(s => s.userInvokable).length;
77 const refInfo = refCount > 0 ? ` (${refCount} reference files)` : '';
78 const scriptInfo = scriptCount > 0 ? ` (${scriptCount} script files)` : '';
79 const prefixInfo = prefix ? ` [${prefix}prefixed]` : '';
80 console.log(`✓ ${displayName}${prefixInfo}: ${skills.length} skills (${userInvokableCount} user-invokable)${refInfo}${scriptInfo}`);
81}