skiller 0.7.1 → 0.7.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/dist/core/SkillsProcessor.js +76 -14
- package/dist/lib.js +6 -4
- package/package.json +1 -1
|
@@ -39,6 +39,7 @@ exports.discoverSkills = discoverSkills;
|
|
|
39
39
|
exports.getSkillsGitignorePaths = getSkillsGitignorePaths;
|
|
40
40
|
exports.propagateSkills = propagateSkills;
|
|
41
41
|
exports.copySkillFoldersFromRules = copySkillFoldersFromRules;
|
|
42
|
+
exports.copyMdcFilesFromRules = copyMdcFilesFromRules;
|
|
42
43
|
const path = __importStar(require("path"));
|
|
43
44
|
const fs = __importStar(require("fs/promises"));
|
|
44
45
|
const yaml = __importStar(require("js-yaml"));
|
|
@@ -140,8 +141,15 @@ async function syncMdcToSkillMd(skillsDir, verbose, dryRun) {
|
|
|
140
141
|
}
|
|
141
142
|
try {
|
|
142
143
|
if (siblingMdcContent !== null && skillMdContent === null) {
|
|
143
|
-
// Case 1: Sibling .mdc exists but no SKILL.md
|
|
144
|
+
// Case 1: Sibling .mdc exists but no SKILL.md
|
|
144
145
|
const { frontmatter: mdcFrontmatter } = (0, FrontmatterParser_1.parseFrontmatter)(siblingMdcContent);
|
|
146
|
+
// Skip SKILL.md generation for .mdc files with alwaysApply: true
|
|
147
|
+
// These are Cursor-style rules, not Claude Code skills
|
|
148
|
+
if (mdcFrontmatter?.alwaysApply === true) {
|
|
149
|
+
(0, constants_1.logVerboseInfo)(`Skipping SKILL.md generation for ${skillName} (alwaysApply rule)`, verbose, dryRun);
|
|
150
|
+
continue;
|
|
151
|
+
}
|
|
152
|
+
// Generate SKILL.md with @reference (absolute path)
|
|
145
153
|
const skillFrontmatter = {
|
|
146
154
|
name: skillName,
|
|
147
155
|
description: mdcFrontmatter?.description || `Skill: ${skillName}`,
|
|
@@ -150,14 +158,14 @@ async function syncMdcToSkillMd(skillsDir, verbose, dryRun) {
|
|
|
150
158
|
${yaml.dump(skillFrontmatter, { lineWidth: -1, noRefs: true }).trim()}
|
|
151
159
|
---
|
|
152
160
|
|
|
153
|
-
|
|
161
|
+
@.claude/skills/${skillName}/${skillName}.mdc
|
|
154
162
|
`;
|
|
155
163
|
if (dryRun) {
|
|
156
164
|
(0, constants_1.logVerboseInfo)(`DRY RUN: Would generate ${skillName}/SKILL.md with @reference`, verbose, dryRun);
|
|
157
165
|
}
|
|
158
166
|
else {
|
|
159
167
|
await fs.writeFile(skillMdPath, newSkillMd, 'utf8');
|
|
160
|
-
(0, constants_1.logVerboseInfo)(`Generated ${skillName}/SKILL.md with
|
|
168
|
+
(0, constants_1.logVerboseInfo)(`Generated ${skillName}/SKILL.md with @.claude/skills/${skillName}/${skillName}.mdc reference`, verbose, dryRun);
|
|
161
169
|
}
|
|
162
170
|
synced.push(skillName);
|
|
163
171
|
}
|
|
@@ -167,22 +175,32 @@ ${yaml.dump(skillFrontmatter, { lineWidth: -1, noRefs: true }).trim()}
|
|
|
167
175
|
const refCheck = isReferenceBody(skillBody);
|
|
168
176
|
if (refCheck.isReference) {
|
|
169
177
|
// Case 2: SKILL.md is @reference → source file is truth
|
|
170
|
-
|
|
178
|
+
// Check for both relative and absolute sibling reference patterns
|
|
179
|
+
const isRelativeSiblingRef = refCheck.referencePath === `./${skillName}.mdc`;
|
|
180
|
+
const isAbsoluteSiblingRef = refCheck.referencePath ===
|
|
181
|
+
`.claude/skills/${skillName}/${skillName}.mdc`;
|
|
182
|
+
if (isRelativeSiblingRef || isAbsoluteSiblingRef) {
|
|
171
183
|
// Sibling reference pattern - validate/update frontmatter if .mdc changed
|
|
172
184
|
if (siblingMdcContent !== null) {
|
|
173
185
|
const { frontmatter: mdcFrontmatter } = (0, FrontmatterParser_1.parseFrontmatter)(siblingMdcContent);
|
|
174
186
|
// Update SKILL.md frontmatter if description changed in .mdc
|
|
175
|
-
if
|
|
176
|
-
|
|
187
|
+
// Also migrate from relative to absolute path if needed
|
|
188
|
+
const needsUpdate = (mdcFrontmatter?.description &&
|
|
189
|
+
mdcFrontmatter.description !==
|
|
190
|
+
skillFrontmatter?.description) ||
|
|
191
|
+
isRelativeSiblingRef; // Migrate old relative refs to absolute
|
|
192
|
+
if (needsUpdate) {
|
|
177
193
|
const newFrontmatter = {
|
|
178
194
|
name: skillFrontmatter?.name || skillName,
|
|
179
|
-
description: mdcFrontmatter
|
|
195
|
+
description: mdcFrontmatter?.description ||
|
|
196
|
+
skillFrontmatter?.description ||
|
|
197
|
+
`Skill: ${skillName}`,
|
|
180
198
|
};
|
|
181
199
|
const newSkillMd = `---
|
|
182
200
|
${yaml.dump(newFrontmatter, { lineWidth: -1, noRefs: true }).trim()}
|
|
183
201
|
---
|
|
184
202
|
|
|
185
|
-
|
|
203
|
+
@.claude/skills/${skillName}/${skillName}.mdc
|
|
186
204
|
`;
|
|
187
205
|
if (dryRun) {
|
|
188
206
|
(0, constants_1.logVerboseInfo)(`DRY RUN: Would update ${skillName}/SKILL.md frontmatter from .mdc`, verbose, dryRun);
|
|
@@ -215,8 +233,7 @@ ${yaml.dump(newFrontmatter, { lineWidth: -1, noRefs: true }).trim()}
|
|
|
215
233
|
const { frontmatter: refFrontmatter, body: refBody } = (0, FrontmatterParser_1.parseFrontmatter)(referencedContent);
|
|
216
234
|
// Create sibling .mdc with the content
|
|
217
235
|
let mdcContent;
|
|
218
|
-
if (refFrontmatter &&
|
|
219
|
-
Object.keys(refFrontmatter).length > 0) {
|
|
236
|
+
if (refFrontmatter && Object.keys(refFrontmatter).length > 0) {
|
|
220
237
|
const mdcFrontmatterData = {};
|
|
221
238
|
if (refFrontmatter.description) {
|
|
222
239
|
mdcFrontmatterData.description = refFrontmatter.description;
|
|
@@ -242,7 +259,7 @@ ${refBody}
|
|
|
242
259
|
else {
|
|
243
260
|
mdcContent = referencedContent;
|
|
244
261
|
}
|
|
245
|
-
// Update SKILL.md to point to sibling .mdc
|
|
262
|
+
// Update SKILL.md to point to sibling .mdc (absolute path)
|
|
246
263
|
const newFrontmatter = {
|
|
247
264
|
name: skillFrontmatter?.name || skillName,
|
|
248
265
|
description: refFrontmatter?.description ||
|
|
@@ -253,7 +270,7 @@ ${refBody}
|
|
|
253
270
|
${yaml.dump(newFrontmatter, { lineWidth: -1, noRefs: true }).trim()}
|
|
254
271
|
---
|
|
255
272
|
|
|
256
|
-
|
|
273
|
+
@.claude/skills/${skillName}/${skillName}.mdc
|
|
257
274
|
`;
|
|
258
275
|
if (dryRun) {
|
|
259
276
|
(0, constants_1.logVerboseInfo)(`DRY RUN: Would migrate ${skillName} from ${refCheck.referencePath} to sibling pattern`, verbose, dryRun);
|
|
@@ -290,7 +307,7 @@ ${skillBody}
|
|
|
290
307
|
else {
|
|
291
308
|
mdcContent = skillBody;
|
|
292
309
|
}
|
|
293
|
-
// Update SKILL.md to @reference
|
|
310
|
+
// Update SKILL.md to @reference (absolute path)
|
|
294
311
|
const newSkillFrontmatter = {
|
|
295
312
|
name: skillFrontmatter?.name || skillName,
|
|
296
313
|
description: skillFrontmatter?.description || `Skill: ${skillName}`,
|
|
@@ -299,7 +316,7 @@ ${skillBody}
|
|
|
299
316
|
${yaml.dump(newSkillFrontmatter, { lineWidth: -1, noRefs: true }).trim()}
|
|
300
317
|
---
|
|
301
318
|
|
|
302
|
-
|
|
319
|
+
@.claude/skills/${skillName}/${skillName}.mdc
|
|
303
320
|
`;
|
|
304
321
|
if (dryRun) {
|
|
305
322
|
(0, constants_1.logVerboseInfo)(`DRY RUN: Would generate ${skillName}/${skillName}.mdc and update SKILL.md`, verbose, dryRun);
|
|
@@ -465,3 +482,48 @@ async function copySkillFoldersFromRules(skillerDir, verbose, dryRun) {
|
|
|
465
482
|
}
|
|
466
483
|
(0, constants_1.logVerboseInfo)(`Copied ${skillFolders.length} skill folder(s) from rules to skills`, verbose, dryRun);
|
|
467
484
|
}
|
|
485
|
+
/**
|
|
486
|
+
* Copies standalone .mdc files from .claude/rules to .claude/skills/name/name.mdc.
|
|
487
|
+
* These are rule files (not skill folders) that should be available in the skills directory.
|
|
488
|
+
* No SKILL.md is generated - these remain as .mdc files only.
|
|
489
|
+
*/
|
|
490
|
+
async function copyMdcFilesFromRules(skillerDir, verbose, dryRun) {
|
|
491
|
+
const rulesDir = path.join(skillerDir, 'rules');
|
|
492
|
+
const skillsDir = path.join(skillerDir, 'skills');
|
|
493
|
+
const copiedNames = [];
|
|
494
|
+
// Check if rules directory exists
|
|
495
|
+
try {
|
|
496
|
+
await fs.access(rulesDir);
|
|
497
|
+
}
|
|
498
|
+
catch {
|
|
499
|
+
return copiedNames;
|
|
500
|
+
}
|
|
501
|
+
const entries = await fs.readdir(rulesDir, { withFileTypes: true });
|
|
502
|
+
// Find .mdc files at rules root (not in subdirectories)
|
|
503
|
+
const mdcFiles = entries.filter((e) => e.isFile() && e.name.endsWith('.mdc'));
|
|
504
|
+
for (const mdcFile of mdcFiles) {
|
|
505
|
+
const skillName = path.basename(mdcFile.name, '.mdc');
|
|
506
|
+
const sourcePath = path.join(rulesDir, mdcFile.name);
|
|
507
|
+
const targetDir = path.join(skillsDir, skillName);
|
|
508
|
+
const targetPath = path.join(targetDir, mdcFile.name);
|
|
509
|
+
try {
|
|
510
|
+
if (dryRun) {
|
|
511
|
+
(0, constants_1.logVerboseInfo)(`DRY RUN: Would copy ${mdcFile.name} from rules to skills/${skillName}/${mdcFile.name}`, verbose, dryRun);
|
|
512
|
+
}
|
|
513
|
+
else {
|
|
514
|
+
await fs.mkdir(targetDir, { recursive: true });
|
|
515
|
+
const content = await fs.readFile(sourcePath, 'utf8');
|
|
516
|
+
await fs.writeFile(targetPath, content, 'utf8');
|
|
517
|
+
(0, constants_1.logVerboseInfo)(`Copied ${mdcFile.name} from rules to skills/${skillName}/${mdcFile.name}`, verbose, dryRun);
|
|
518
|
+
}
|
|
519
|
+
copiedNames.push(skillName);
|
|
520
|
+
}
|
|
521
|
+
catch (err) {
|
|
522
|
+
(0, constants_1.logWarn)(`Failed to copy ${mdcFile.name}: ${err.message}`, dryRun);
|
|
523
|
+
}
|
|
524
|
+
}
|
|
525
|
+
if (copiedNames.length > 0) {
|
|
526
|
+
(0, constants_1.logVerboseInfo)(`Copied ${copiedNames.length} .mdc file(s) from rules to skills`, verbose, dryRun);
|
|
527
|
+
}
|
|
528
|
+
return copiedNames;
|
|
529
|
+
}
|
package/dist/lib.js
CHANGED
|
@@ -102,11 +102,12 @@ async function applyAllAgentConfigs(projectRoot, includedAgents, configPath, cli
|
|
|
102
102
|
(0, constants_1.logVerbose)(`Selected ${selectedAgents.length} agents: ${selectedAgents.map((a) => a.getName()).join(', ')}`, verbose);
|
|
103
103
|
// Propagate skills (or cleanup if disabled) - do this for each nested directory
|
|
104
104
|
const skillsEnabledResolved = resolveSkillsEnabled(skillsEnabled, rootConfig.skills?.enabled);
|
|
105
|
-
const { propagateSkills, copySkillFoldersFromRules } = await Promise.resolve().then(() => __importStar(require('./core/SkillsProcessor')));
|
|
106
|
-
// Copy skill folders from rules to skills
|
|
105
|
+
const { propagateSkills, copySkillFoldersFromRules, copyMdcFilesFromRules, } = await Promise.resolve().then(() => __importStar(require('./core/SkillsProcessor')));
|
|
106
|
+
// Copy skill folders and .mdc files from rules to skills
|
|
107
107
|
if (skillsEnabledResolved) {
|
|
108
108
|
for (const configEntry of hierarchicalConfigs) {
|
|
109
109
|
await copySkillFoldersFromRules(configEntry.skillerDir, verbose, dryRun);
|
|
110
|
+
await copyMdcFilesFromRules(configEntry.skillerDir, verbose, dryRun);
|
|
110
111
|
}
|
|
111
112
|
}
|
|
112
113
|
// Propagate skills for each nested .claude directory (or cleanup if disabled)
|
|
@@ -130,10 +131,11 @@ async function applyAllAgentConfigs(projectRoot, includedAgents, configPath, cli
|
|
|
130
131
|
(0, constants_1.logVerbose)(`Selected ${selectedAgents.length} agents: ${selectedAgents.map((a) => a.getName()).join(', ')}`, verbose);
|
|
131
132
|
// Propagate skills (or cleanup if disabled)
|
|
132
133
|
const skillsEnabledResolved = resolveSkillsEnabled(skillsEnabled, singleConfig.config.skills?.enabled);
|
|
133
|
-
const { propagateSkills, copySkillFoldersFromRules } = await Promise.resolve().then(() => __importStar(require('./core/SkillsProcessor')));
|
|
134
|
-
// Copy skill folders from rules to skills
|
|
134
|
+
const { propagateSkills, copySkillFoldersFromRules, copyMdcFilesFromRules, } = await Promise.resolve().then(() => __importStar(require('./core/SkillsProcessor')));
|
|
135
|
+
// Copy skill folders and .mdc files from rules to skills
|
|
135
136
|
if (skillsEnabledResolved) {
|
|
136
137
|
await copySkillFoldersFromRules(singleConfig.skillerDir, verbose, dryRun);
|
|
138
|
+
await copyMdcFilesFromRules(singleConfig.skillerDir, verbose, dryRun);
|
|
137
139
|
}
|
|
138
140
|
// Always call propagateSkills - it handles cleanup when disabled
|
|
139
141
|
await propagateSkills(projectRoot, selectedAgents, skillsEnabledResolved, verbose, dryRun, singleConfig.skillerDir);
|