skiller 0.7.0 → 0.7.1
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/FrontmatterParser.js +0 -4
- package/dist/core/SkillsProcessor.js +189 -129
- package/package.json +1 -1
|
@@ -139,10 +139,6 @@ function extractFrontmatter(parsed, body) {
|
|
|
139
139
|
if (typeof parsed.alwaysApply === 'boolean') {
|
|
140
140
|
frontmatter.alwaysApply = parsed.alwaysApply;
|
|
141
141
|
}
|
|
142
|
-
// Extract synced (for skill sync detection)
|
|
143
|
-
if (typeof parsed.synced === 'boolean') {
|
|
144
|
-
frontmatter.synced = parsed.synced;
|
|
145
|
-
}
|
|
146
142
|
// Extract name (for SKILL.md)
|
|
147
143
|
if (typeof parsed.name === 'string') {
|
|
148
144
|
frontmatter.name = parsed.name;
|
|
@@ -33,6 +33,7 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
33
33
|
};
|
|
34
34
|
})();
|
|
35
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.isReferenceBody = isReferenceBody;
|
|
36
37
|
exports.syncMdcToSkillMd = syncMdcToSkillMd;
|
|
37
38
|
exports.discoverSkills = discoverSkills;
|
|
38
39
|
exports.getSkillsGitignorePaths = getSkillsGitignorePaths;
|
|
@@ -44,16 +45,34 @@ const yaml = __importStar(require("js-yaml"));
|
|
|
44
45
|
const constants_1 = require("../constants");
|
|
45
46
|
const SkillsUtils_1 = require("./SkillsUtils");
|
|
46
47
|
const FrontmatterParser_1 = require("./FrontmatterParser");
|
|
48
|
+
/**
|
|
49
|
+
* Check if SKILL.md body is just a reference (single non-empty line starting with @).
|
|
50
|
+
* This replaces the previous synced: true frontmatter detection.
|
|
51
|
+
*/
|
|
52
|
+
function isReferenceBody(body) {
|
|
53
|
+
const lines = body.split('\n').filter((line) => line.trim().length > 0);
|
|
54
|
+
if (lines.length === 1 && lines[0].trim().startsWith('@')) {
|
|
55
|
+
return {
|
|
56
|
+
isReference: true,
|
|
57
|
+
referencePath: lines[0].trim().slice(1), // Remove @ prefix
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
return { isReference: false };
|
|
61
|
+
}
|
|
47
62
|
/**
|
|
48
63
|
* Bidirectional sync between .mdc files and SKILL.md in the skills directory.
|
|
49
64
|
*
|
|
50
|
-
* Sync logic:
|
|
51
|
-
* 1. If .mdc exists but no SKILL.md → generate SKILL.md with
|
|
52
|
-
* 2. If SKILL.md
|
|
53
|
-
* 3. If SKILL.md
|
|
65
|
+
* Sync logic (using @reference pattern instead of synced: true):
|
|
66
|
+
* 1. If sibling .mdc exists (name/name.mdc) but no SKILL.md → generate SKILL.md with @./name.mdc
|
|
67
|
+
* 2. If SKILL.md body is @reference → referenced file is source of truth
|
|
68
|
+
* 3. If SKILL.md has full content → generate sibling .mdc, update SKILL.md to @./name.mdc
|
|
54
69
|
*
|
|
55
70
|
* File structure:
|
|
56
|
-
* - .claude/skills/foo.mdc → .claude/skills/foo/SKILL.md
|
|
71
|
+
* - .claude/skills/foo/foo.mdc → .claude/skills/foo/SKILL.md (with @./foo.mdc body)
|
|
72
|
+
*
|
|
73
|
+
* Backward compatibility:
|
|
74
|
+
* - .claude/skills/foo.mdc at root → migrates to sibling pattern
|
|
75
|
+
* - @.claude/rules/name.mdc → recognized as reference (pre-0.7 pattern)
|
|
57
76
|
*/
|
|
58
77
|
async function syncMdcToSkillMd(skillsDir, verbose, dryRun) {
|
|
59
78
|
const synced = [];
|
|
@@ -66,15 +85,51 @@ async function syncMdcToSkillMd(skillsDir, verbose, dryRun) {
|
|
|
66
85
|
return { synced, warnings };
|
|
67
86
|
}
|
|
68
87
|
const entries = await fs.readdir(skillsDir, { withFileTypes: true });
|
|
69
|
-
// Find .mdc files at
|
|
70
|
-
const
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
for (const mdcFile of mdcFiles) {
|
|
88
|
+
// Find .mdc files at skills root (for backward compatibility/migration)
|
|
89
|
+
const rootMdcFiles = entries.filter((e) => e.isFile() && e.name.endsWith('.mdc'));
|
|
90
|
+
// First, migrate any root .mdc files to sibling pattern
|
|
91
|
+
for (const mdcFile of rootMdcFiles) {
|
|
74
92
|
const skillName = path.basename(mdcFile.name, '.mdc');
|
|
75
|
-
const
|
|
93
|
+
const rootMdcPath = path.join(skillsDir, mdcFile.name);
|
|
94
|
+
const skillFolderPath = path.join(skillsDir, skillName);
|
|
95
|
+
const siblingMdcPath = path.join(skillFolderPath, mdcFile.name);
|
|
96
|
+
try {
|
|
97
|
+
// Create skill folder if needed
|
|
98
|
+
if (!dryRun) {
|
|
99
|
+
await fs.mkdir(skillFolderPath, { recursive: true });
|
|
100
|
+
}
|
|
101
|
+
// Move .mdc to sibling location
|
|
102
|
+
if (dryRun) {
|
|
103
|
+
(0, constants_1.logVerboseInfo)(`DRY RUN: Would migrate ${mdcFile.name} to ${skillName}/${mdcFile.name}`, verbose, dryRun);
|
|
104
|
+
}
|
|
105
|
+
else {
|
|
106
|
+
const mdcContent = await fs.readFile(rootMdcPath, 'utf8');
|
|
107
|
+
await fs.writeFile(siblingMdcPath, mdcContent, 'utf8');
|
|
108
|
+
await fs.unlink(rootMdcPath);
|
|
109
|
+
(0, constants_1.logVerboseInfo)(`Migrated ${mdcFile.name} to ${skillName}/${mdcFile.name}`, verbose, dryRun);
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
catch (err) {
|
|
113
|
+
warnings.push(`Failed to migrate ${skillName}.mdc: ${err.message}`);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
// Re-read entries after migration
|
|
117
|
+
const updatedEntries = await fs.readdir(skillsDir, { withFileTypes: true });
|
|
118
|
+
const updatedSkillFolders = updatedEntries.filter((e) => e.isDirectory());
|
|
119
|
+
// Process skill folders
|
|
120
|
+
for (const folder of updatedSkillFolders) {
|
|
121
|
+
const skillName = folder.name;
|
|
76
122
|
const skillFolderPath = path.join(skillsDir, skillName);
|
|
77
123
|
const skillMdPath = path.join(skillFolderPath, constants_1.SKILL_MD_FILENAME);
|
|
124
|
+
const siblingMdcPath = path.join(skillFolderPath, `${skillName}.mdc`);
|
|
125
|
+
// Check if sibling .mdc exists
|
|
126
|
+
let siblingMdcContent = null;
|
|
127
|
+
try {
|
|
128
|
+
siblingMdcContent = await fs.readFile(siblingMdcPath, 'utf8');
|
|
129
|
+
}
|
|
130
|
+
catch {
|
|
131
|
+
// No sibling .mdc
|
|
132
|
+
}
|
|
78
133
|
// Check if SKILL.md exists
|
|
79
134
|
let skillMdContent = null;
|
|
80
135
|
try {
|
|
@@ -84,175 +139,180 @@ async function syncMdcToSkillMd(skillsDir, verbose, dryRun) {
|
|
|
84
139
|
// No SKILL.md
|
|
85
140
|
}
|
|
86
141
|
try {
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
// Case 1: No SKILL.md exists → generate from .mdc with synced: true
|
|
142
|
+
if (siblingMdcContent !== null && skillMdContent === null) {
|
|
143
|
+
// Case 1: Sibling .mdc exists but no SKILL.md → generate SKILL.md with @reference
|
|
144
|
+
const { frontmatter: mdcFrontmatter } = (0, FrontmatterParser_1.parseFrontmatter)(siblingMdcContent);
|
|
91
145
|
const skillFrontmatter = {
|
|
92
146
|
name: skillName,
|
|
93
147
|
description: mdcFrontmatter?.description || `Skill: ${skillName}`,
|
|
94
|
-
synced: true,
|
|
95
148
|
};
|
|
96
149
|
const newSkillMd = `---
|
|
97
150
|
${yaml.dump(skillFrontmatter, { lineWidth: -1, noRefs: true }).trim()}
|
|
98
151
|
---
|
|
99
152
|
|
|
100
|
-
|
|
153
|
+
@./${skillName}.mdc
|
|
101
154
|
`;
|
|
102
155
|
if (dryRun) {
|
|
103
|
-
(0, constants_1.logVerboseInfo)(`DRY RUN: Would generate ${skillName}/SKILL.md
|
|
156
|
+
(0, constants_1.logVerboseInfo)(`DRY RUN: Would generate ${skillName}/SKILL.md with @reference`, verbose, dryRun);
|
|
104
157
|
}
|
|
105
158
|
else {
|
|
106
|
-
await fs.mkdir(skillFolderPath, { recursive: true });
|
|
107
159
|
await fs.writeFile(skillMdPath, newSkillMd, 'utf8');
|
|
108
|
-
(0, constants_1.logVerboseInfo)(`Generated ${skillName}/SKILL.md
|
|
160
|
+
(0, constants_1.logVerboseInfo)(`Generated ${skillName}/SKILL.md with @./${skillName}.mdc reference`, verbose, dryRun);
|
|
109
161
|
}
|
|
110
162
|
synced.push(skillName);
|
|
111
163
|
}
|
|
112
|
-
else {
|
|
113
|
-
// SKILL.md exists - check if it
|
|
164
|
+
else if (skillMdContent !== null) {
|
|
165
|
+
// SKILL.md exists - check if it's a reference
|
|
114
166
|
const { frontmatter: skillFrontmatter, body: skillBody } = (0, FrontmatterParser_1.parseFrontmatter)(skillMdContent);
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
167
|
+
const refCheck = isReferenceBody(skillBody);
|
|
168
|
+
if (refCheck.isReference) {
|
|
169
|
+
// Case 2: SKILL.md is @reference → source file is truth
|
|
170
|
+
if (refCheck.referencePath === `./${skillName}.mdc`) {
|
|
171
|
+
// Sibling reference pattern - validate/update frontmatter if .mdc changed
|
|
172
|
+
if (siblingMdcContent !== null) {
|
|
173
|
+
const { frontmatter: mdcFrontmatter } = (0, FrontmatterParser_1.parseFrontmatter)(siblingMdcContent);
|
|
174
|
+
// Update SKILL.md frontmatter if description changed in .mdc
|
|
175
|
+
if (mdcFrontmatter?.description &&
|
|
176
|
+
mdcFrontmatter.description !== skillFrontmatter?.description) {
|
|
177
|
+
const newFrontmatter = {
|
|
178
|
+
name: skillFrontmatter?.name || skillName,
|
|
179
|
+
description: mdcFrontmatter.description,
|
|
180
|
+
};
|
|
181
|
+
const newSkillMd = `---
|
|
125
182
|
${yaml.dump(newFrontmatter, { lineWidth: -1, noRefs: true }).trim()}
|
|
126
183
|
---
|
|
127
184
|
|
|
128
|
-
|
|
185
|
+
@./${skillName}.mdc
|
|
129
186
|
`;
|
|
130
|
-
|
|
131
|
-
|
|
187
|
+
if (dryRun) {
|
|
188
|
+
(0, constants_1.logVerboseInfo)(`DRY RUN: Would update ${skillName}/SKILL.md frontmatter from .mdc`, verbose, dryRun);
|
|
189
|
+
}
|
|
190
|
+
else {
|
|
191
|
+
await fs.writeFile(skillMdPath, newSkillMd, 'utf8');
|
|
192
|
+
(0, constants_1.logVerboseInfo)(`Updated ${skillName}/SKILL.md frontmatter from .mdc`, verbose, dryRun);
|
|
193
|
+
}
|
|
194
|
+
synced.push(skillName);
|
|
195
|
+
}
|
|
196
|
+
}
|
|
132
197
|
}
|
|
133
|
-
else {
|
|
134
|
-
|
|
135
|
-
|
|
198
|
+
else if (refCheck.referencePath) {
|
|
199
|
+
// Pre-0.7 pattern or other external reference - migrate to sibling pattern
|
|
200
|
+
// Determine base path for resolution:
|
|
201
|
+
// - Paths starting with .claude/ are relative to project root
|
|
202
|
+
// - Other paths are relative to the skill folder
|
|
203
|
+
let referencedPath;
|
|
204
|
+
if (refCheck.referencePath.startsWith('.claude/')) {
|
|
205
|
+
// Project root is parent of .claude directory (skillsDir is .claude/skills)
|
|
206
|
+
const projectRoot = path.dirname(path.dirname(skillsDir));
|
|
207
|
+
referencedPath = path.join(projectRoot, refCheck.referencePath);
|
|
208
|
+
}
|
|
209
|
+
else {
|
|
210
|
+
referencedPath = path.resolve(skillFolderPath, refCheck.referencePath);
|
|
211
|
+
}
|
|
212
|
+
try {
|
|
213
|
+
const referencedContent = await fs.readFile(referencedPath, 'utf8');
|
|
214
|
+
// Parse the referenced file for frontmatter
|
|
215
|
+
const { frontmatter: refFrontmatter, body: refBody } = (0, FrontmatterParser_1.parseFrontmatter)(referencedContent);
|
|
216
|
+
// Create sibling .mdc with the content
|
|
217
|
+
let mdcContent;
|
|
218
|
+
if (refFrontmatter &&
|
|
219
|
+
Object.keys(refFrontmatter).length > 0) {
|
|
220
|
+
const mdcFrontmatterData = {};
|
|
221
|
+
if (refFrontmatter.description) {
|
|
222
|
+
mdcFrontmatterData.description = refFrontmatter.description;
|
|
223
|
+
}
|
|
224
|
+
if (refFrontmatter.globs) {
|
|
225
|
+
mdcFrontmatterData.globs = refFrontmatter.globs;
|
|
226
|
+
}
|
|
227
|
+
if (refFrontmatter.alwaysApply !== undefined) {
|
|
228
|
+
mdcFrontmatterData.alwaysApply = refFrontmatter.alwaysApply;
|
|
229
|
+
}
|
|
230
|
+
if (Object.keys(mdcFrontmatterData).length > 0) {
|
|
231
|
+
mdcContent = `---
|
|
232
|
+
${yaml.dump(mdcFrontmatterData, { lineWidth: -1, noRefs: true }).trim()}
|
|
233
|
+
---
|
|
234
|
+
|
|
235
|
+
${refBody}
|
|
236
|
+
`;
|
|
237
|
+
}
|
|
238
|
+
else {
|
|
239
|
+
mdcContent = refBody;
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
else {
|
|
243
|
+
mdcContent = referencedContent;
|
|
244
|
+
}
|
|
245
|
+
// Update SKILL.md to point to sibling .mdc
|
|
246
|
+
const newFrontmatter = {
|
|
247
|
+
name: skillFrontmatter?.name || skillName,
|
|
248
|
+
description: refFrontmatter?.description ||
|
|
249
|
+
skillFrontmatter?.description ||
|
|
250
|
+
`Skill: ${skillName}`,
|
|
251
|
+
};
|
|
252
|
+
const newSkillMd = `---
|
|
253
|
+
${yaml.dump(newFrontmatter, { lineWidth: -1, noRefs: true }).trim()}
|
|
254
|
+
---
|
|
255
|
+
|
|
256
|
+
@./${skillName}.mdc
|
|
257
|
+
`;
|
|
258
|
+
if (dryRun) {
|
|
259
|
+
(0, constants_1.logVerboseInfo)(`DRY RUN: Would migrate ${skillName} from ${refCheck.referencePath} to sibling pattern`, verbose, dryRun);
|
|
260
|
+
}
|
|
261
|
+
else {
|
|
262
|
+
await fs.writeFile(siblingMdcPath, mdcContent, 'utf8');
|
|
263
|
+
await fs.writeFile(skillMdPath, newSkillMd, 'utf8');
|
|
264
|
+
(0, constants_1.logVerboseInfo)(`Migrated ${skillName} from ${refCheck.referencePath} to sibling pattern`, verbose, dryRun);
|
|
265
|
+
}
|
|
266
|
+
synced.push(skillName);
|
|
267
|
+
}
|
|
268
|
+
catch {
|
|
269
|
+
// Referenced file doesn't exist or can't be read
|
|
270
|
+
warnings.push(`Cannot migrate ${skillName}: referenced file ${refCheck.referencePath} not found or unreadable`);
|
|
271
|
+
}
|
|
136
272
|
}
|
|
137
|
-
synced.push(skillName);
|
|
138
273
|
}
|
|
139
274
|
else {
|
|
140
|
-
// SKILL.md
|
|
141
|
-
//
|
|
142
|
-
const
|
|
275
|
+
// Case 3: SKILL.md has full content → generate sibling .mdc, update to @reference
|
|
276
|
+
// Generate .mdc from SKILL.md body
|
|
277
|
+
const mdcFrontmatter = {};
|
|
143
278
|
if (skillFrontmatter?.description) {
|
|
144
|
-
|
|
279
|
+
mdcFrontmatter.description = skillFrontmatter.description;
|
|
145
280
|
}
|
|
146
|
-
let
|
|
147
|
-
if (Object.keys(
|
|
148
|
-
|
|
149
|
-
${yaml.dump(
|
|
281
|
+
let mdcContent;
|
|
282
|
+
if (Object.keys(mdcFrontmatter).length > 0) {
|
|
283
|
+
mdcContent = `---
|
|
284
|
+
${yaml.dump(mdcFrontmatter, { lineWidth: -1, noRefs: true }).trim()}
|
|
150
285
|
---
|
|
151
286
|
|
|
152
287
|
${skillBody}
|
|
153
288
|
`;
|
|
154
289
|
}
|
|
155
290
|
else {
|
|
156
|
-
|
|
291
|
+
mdcContent = skillBody;
|
|
157
292
|
}
|
|
158
|
-
// Update SKILL.md
|
|
293
|
+
// Update SKILL.md to @reference
|
|
159
294
|
const newSkillFrontmatter = {
|
|
160
295
|
name: skillFrontmatter?.name || skillName,
|
|
161
296
|
description: skillFrontmatter?.description || `Skill: ${skillName}`,
|
|
162
|
-
synced: true,
|
|
163
297
|
};
|
|
164
298
|
const newSkillMd = `---
|
|
165
299
|
${yaml.dump(newSkillFrontmatter, { lineWidth: -1, noRefs: true }).trim()}
|
|
166
300
|
---
|
|
167
301
|
|
|
168
|
-
|
|
302
|
+
@./${skillName}.mdc
|
|
169
303
|
`;
|
|
170
304
|
if (dryRun) {
|
|
171
|
-
(0, constants_1.logVerboseInfo)(`DRY RUN: Would
|
|
305
|
+
(0, constants_1.logVerboseInfo)(`DRY RUN: Would generate ${skillName}/${skillName}.mdc and update SKILL.md`, verbose, dryRun);
|
|
172
306
|
}
|
|
173
307
|
else {
|
|
174
|
-
await fs.writeFile(
|
|
308
|
+
await fs.writeFile(siblingMdcPath, mdcContent, 'utf8');
|
|
175
309
|
await fs.writeFile(skillMdPath, newSkillMd, 'utf8');
|
|
176
|
-
(0, constants_1.logVerboseInfo)(`
|
|
310
|
+
(0, constants_1.logVerboseInfo)(`Generated ${skillName}/${skillName}.mdc and updated SKILL.md to @reference`, verbose, dryRun);
|
|
177
311
|
}
|
|
178
312
|
synced.push(skillName);
|
|
179
313
|
}
|
|
180
314
|
}
|
|
181
|
-
|
|
182
|
-
catch (err) {
|
|
183
|
-
warnings.push(`Failed to sync ${skillName}: ${err.message}`);
|
|
184
|
-
}
|
|
185
|
-
}
|
|
186
|
-
// Case 3: Process skill folders without .mdc (SKILL.md → .mdc)
|
|
187
|
-
for (const folder of skillFolders) {
|
|
188
|
-
const skillName = folder.name;
|
|
189
|
-
const mdcPath = path.join(skillsDir, `${skillName}.mdc`);
|
|
190
|
-
const skillMdPath = path.join(skillsDir, skillName, constants_1.SKILL_MD_FILENAME);
|
|
191
|
-
// Check if .mdc already exists
|
|
192
|
-
let hasMdc = false;
|
|
193
|
-
try {
|
|
194
|
-
await fs.access(mdcPath);
|
|
195
|
-
hasMdc = true;
|
|
196
|
-
}
|
|
197
|
-
catch {
|
|
198
|
-
// No .mdc
|
|
199
|
-
}
|
|
200
|
-
if (hasMdc) {
|
|
201
|
-
// Already processed in Cases 1 & 2
|
|
202
|
-
continue;
|
|
203
|
-
}
|
|
204
|
-
// Check if SKILL.md exists
|
|
205
|
-
let skillMdContent = null;
|
|
206
|
-
try {
|
|
207
|
-
skillMdContent = await fs.readFile(skillMdPath, 'utf8');
|
|
208
|
-
}
|
|
209
|
-
catch {
|
|
210
|
-
// No SKILL.md - not a valid skill
|
|
211
|
-
continue;
|
|
212
|
-
}
|
|
213
|
-
try {
|
|
214
|
-
const { frontmatter, body } = (0, FrontmatterParser_1.parseFrontmatter)(skillMdContent);
|
|
215
|
-
if (frontmatter?.synced !== true) {
|
|
216
|
-
// Case 3: SKILL.md without synced: true → generate .mdc, add synced: true to SKILL.md
|
|
217
|
-
// Generate .mdc from SKILL.md body
|
|
218
|
-
const mdcFrontmatter = {};
|
|
219
|
-
if (frontmatter?.description) {
|
|
220
|
-
mdcFrontmatter.description = frontmatter.description;
|
|
221
|
-
}
|
|
222
|
-
let mdcContent;
|
|
223
|
-
if (Object.keys(mdcFrontmatter).length > 0) {
|
|
224
|
-
mdcContent = `---
|
|
225
|
-
${yaml.dump(mdcFrontmatter, { lineWidth: -1, noRefs: true }).trim()}
|
|
226
|
-
---
|
|
227
|
-
|
|
228
|
-
${body}
|
|
229
|
-
`;
|
|
230
|
-
}
|
|
231
|
-
else {
|
|
232
|
-
mdcContent = body;
|
|
233
|
-
}
|
|
234
|
-
// Update SKILL.md with synced: true
|
|
235
|
-
const newSkillFrontmatter = {
|
|
236
|
-
name: frontmatter?.name || skillName,
|
|
237
|
-
description: frontmatter?.description || `Skill: ${skillName}`,
|
|
238
|
-
synced: true,
|
|
239
|
-
};
|
|
240
|
-
const newSkillMd = `---
|
|
241
|
-
${yaml.dump(newSkillFrontmatter, { lineWidth: -1, noRefs: true }).trim()}
|
|
242
|
-
---
|
|
243
|
-
|
|
244
|
-
${body}
|
|
245
|
-
`;
|
|
246
|
-
if (dryRun) {
|
|
247
|
-
(0, constants_1.logVerboseInfo)(`DRY RUN: Would generate ${skillName}.mdc from ${skillName}/SKILL.md`, verbose, dryRun);
|
|
248
|
-
}
|
|
249
|
-
else {
|
|
250
|
-
await fs.writeFile(mdcPath, mdcContent, 'utf8');
|
|
251
|
-
await fs.writeFile(skillMdPath, newSkillMd, 'utf8');
|
|
252
|
-
(0, constants_1.logVerboseInfo)(`Generated ${skillName}.mdc from ${skillName}/SKILL.md`, verbose, dryRun);
|
|
253
|
-
}
|
|
254
|
-
synced.push(skillName);
|
|
255
|
-
}
|
|
315
|
+
// If neither exists, skip - not a valid skill folder
|
|
256
316
|
}
|
|
257
317
|
catch (err) {
|
|
258
318
|
warnings.push(`Failed to sync ${skillName}: ${err.message}`);
|