@powerformer/refly-cli 0.1.22 → 0.1.24
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/bin/refly.js +1565 -236
- package/dist/bin/refly.js.map +1 -1
- package/dist/index.d.ts +18 -0
- package/dist/index.js +1012 -93
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/skill/SKILL.md +114 -13
package/dist/index.js
CHANGED
|
@@ -185,17 +185,829 @@ var init_logger = __esm({
|
|
|
185
185
|
}
|
|
186
186
|
});
|
|
187
187
|
|
|
188
|
+
// src/platform/registry.ts
|
|
189
|
+
function pathExists(p) {
|
|
190
|
+
try {
|
|
191
|
+
return fs5.existsSync(p);
|
|
192
|
+
} catch {
|
|
193
|
+
return false;
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
var fs5, path5, import_node_os, home, agents;
|
|
197
|
+
var init_registry = __esm({
|
|
198
|
+
"src/platform/registry.ts"() {
|
|
199
|
+
"use strict";
|
|
200
|
+
init_cjs_shims();
|
|
201
|
+
fs5 = __toESM(require("fs"));
|
|
202
|
+
path5 = __toESM(require("path"));
|
|
203
|
+
import_node_os = require("os");
|
|
204
|
+
home = (0, import_node_os.homedir)();
|
|
205
|
+
agents = {
|
|
206
|
+
// === SKILL.md Format (Symlink Compatible) ===
|
|
207
|
+
"claude-code": {
|
|
208
|
+
name: "claude-code",
|
|
209
|
+
displayName: "Claude Code",
|
|
210
|
+
format: "skill-md",
|
|
211
|
+
skillsDir: ".claude/skills",
|
|
212
|
+
globalSkillsDir: path5.join(home, ".claude", "skills"),
|
|
213
|
+
detectInstalled: async () => pathExists(path5.join(home, ".claude"))
|
|
214
|
+
},
|
|
215
|
+
codex: {
|
|
216
|
+
name: "codex",
|
|
217
|
+
displayName: "Codex",
|
|
218
|
+
format: "skill-md",
|
|
219
|
+
skillsDir: ".codex/skills",
|
|
220
|
+
globalSkillsDir: process.env.CODEX_HOME ? path5.join(process.env.CODEX_HOME, "skills") : path5.join(home, ".codex", "skills"),
|
|
221
|
+
detectInstalled: async () => pathExists(path5.join(home, ".codex"))
|
|
222
|
+
},
|
|
223
|
+
antigravity: {
|
|
224
|
+
name: "antigravity",
|
|
225
|
+
displayName: "Antigravity",
|
|
226
|
+
format: "skill-md",
|
|
227
|
+
skillsDir: ".agent/skills",
|
|
228
|
+
globalSkillsDir: path5.join(home, ".gemini", "antigravity", "skills"),
|
|
229
|
+
detectInstalled: async () => pathExists(path5.join(home, ".gemini", "antigravity"))
|
|
230
|
+
},
|
|
231
|
+
"github-copilot": {
|
|
232
|
+
name: "github-copilot",
|
|
233
|
+
displayName: "GitHub Copilot",
|
|
234
|
+
format: "skill-md",
|
|
235
|
+
skillsDir: ".github/skills",
|
|
236
|
+
globalSkillsDir: path5.join(home, ".copilot", "skills"),
|
|
237
|
+
detectInstalled: async () => pathExists(path5.join(home, ".copilot"))
|
|
238
|
+
},
|
|
239
|
+
windsurf: {
|
|
240
|
+
name: "windsurf",
|
|
241
|
+
displayName: "Windsurf",
|
|
242
|
+
format: "skill-md",
|
|
243
|
+
skillsDir: ".windsurf/skills",
|
|
244
|
+
globalSkillsDir: path5.join(home, ".codeium", "windsurf", "skills"),
|
|
245
|
+
detectInstalled: async () => pathExists(path5.join(home, ".codeium", "windsurf"))
|
|
246
|
+
},
|
|
247
|
+
opencode: {
|
|
248
|
+
name: "opencode",
|
|
249
|
+
displayName: "OpenCode",
|
|
250
|
+
format: "skill-md",
|
|
251
|
+
skillsDir: ".opencode/skill",
|
|
252
|
+
globalSkillsDir: path5.join(home, ".config", "opencode", "skill"),
|
|
253
|
+
detectInstalled: async () => pathExists(path5.join(home, ".config", "opencode"))
|
|
254
|
+
},
|
|
255
|
+
moltbot: {
|
|
256
|
+
name: "moltbot",
|
|
257
|
+
displayName: "Moltbot",
|
|
258
|
+
format: "skill-md",
|
|
259
|
+
skillsDir: "skills",
|
|
260
|
+
// <workspace>/skills
|
|
261
|
+
globalSkillsDir: path5.join(home, ".clawdbot", "skills"),
|
|
262
|
+
// Note: .clawdbot not .moltbot
|
|
263
|
+
detectInstalled: async () => pathExists(path5.join(home, ".clawdbot"))
|
|
264
|
+
},
|
|
265
|
+
// === Different Formats (Require Conversion) ===
|
|
266
|
+
cursor: {
|
|
267
|
+
name: "cursor",
|
|
268
|
+
displayName: "Cursor",
|
|
269
|
+
format: "cursor-mdc",
|
|
270
|
+
skillsDir: ".cursor/rules",
|
|
271
|
+
globalSkillsDir: null,
|
|
272
|
+
// Cursor has no global rules directory
|
|
273
|
+
detectInstalled: async () => pathExists(path5.join(home, ".cursor")),
|
|
274
|
+
fileExtension: ".mdc",
|
|
275
|
+
skillsAsFiles: true
|
|
276
|
+
},
|
|
277
|
+
continue: {
|
|
278
|
+
name: "continue",
|
|
279
|
+
displayName: "Continue",
|
|
280
|
+
format: "rules-md",
|
|
281
|
+
skillsDir: ".continue/rules",
|
|
282
|
+
globalSkillsDir: path5.join(home, ".continue", "rules"),
|
|
283
|
+
detectInstalled: async () => pathExists(path5.join(home, ".continue")),
|
|
284
|
+
fileExtension: ".md",
|
|
285
|
+
skillsAsFiles: true
|
|
286
|
+
},
|
|
287
|
+
trae: {
|
|
288
|
+
name: "trae",
|
|
289
|
+
displayName: "Trae",
|
|
290
|
+
format: "rules-md",
|
|
291
|
+
skillsDir: ".trae/rules",
|
|
292
|
+
globalSkillsDir: path5.join(home, ".trae", "rules"),
|
|
293
|
+
detectInstalled: async () => pathExists(path5.join(home, ".trae")),
|
|
294
|
+
fileExtension: ".md",
|
|
295
|
+
skillsAsFiles: true
|
|
296
|
+
},
|
|
297
|
+
// === Unverified ===
|
|
298
|
+
qoder: {
|
|
299
|
+
name: "qoder",
|
|
300
|
+
displayName: "Qoder",
|
|
301
|
+
format: "unknown",
|
|
302
|
+
skillsDir: ".qoder/skills",
|
|
303
|
+
// Assumed, not verified
|
|
304
|
+
globalSkillsDir: path5.join(home, ".qoder", "skills"),
|
|
305
|
+
detectInstalled: async () => pathExists(path5.join(home, ".qoder"))
|
|
306
|
+
}
|
|
307
|
+
};
|
|
308
|
+
}
|
|
309
|
+
});
|
|
310
|
+
|
|
311
|
+
// src/platform/symlink-adapter.ts
|
|
312
|
+
async function createSymlinkSafe(target, linkPath) {
|
|
313
|
+
try {
|
|
314
|
+
const linkDir = path6.dirname(linkPath);
|
|
315
|
+
ensureDir(linkDir);
|
|
316
|
+
if (fs6.existsSync(linkPath)) {
|
|
317
|
+
const stat = fs6.lstatSync(linkPath);
|
|
318
|
+
if (stat.isSymbolicLink()) {
|
|
319
|
+
fs6.unlinkSync(linkPath);
|
|
320
|
+
logger.debug(`Removed existing symlink: ${linkPath}`);
|
|
321
|
+
} else if (stat.isDirectory()) {
|
|
322
|
+
return {
|
|
323
|
+
success: false,
|
|
324
|
+
error: `Target path is a directory, not a symlink: ${linkPath}`
|
|
325
|
+
};
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
const symlinkType = (0, import_node_os2.platform)() === "win32" ? "junction" : "dir";
|
|
329
|
+
fs6.symlinkSync(target, linkPath, symlinkType);
|
|
330
|
+
logger.debug(`Created symlink: ${linkPath} -> ${target}`);
|
|
331
|
+
return { success: true };
|
|
332
|
+
} catch (err) {
|
|
333
|
+
if (err.code === "ENOENT") {
|
|
334
|
+
try {
|
|
335
|
+
const symlinkType = (0, import_node_os2.platform)() === "win32" ? "junction" : "dir";
|
|
336
|
+
fs6.symlinkSync(target, linkPath, symlinkType);
|
|
337
|
+
logger.debug(`Created symlink: ${linkPath} -> ${target}`);
|
|
338
|
+
return { success: true };
|
|
339
|
+
} catch (innerErr) {
|
|
340
|
+
return {
|
|
341
|
+
success: false,
|
|
342
|
+
error: innerErr.message
|
|
343
|
+
};
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
return {
|
|
347
|
+
success: false,
|
|
348
|
+
error: err.message
|
|
349
|
+
};
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
var fs6, path6, import_node_os2, SymlinkAdapter, symlinkAdapter;
|
|
353
|
+
var init_symlink_adapter = __esm({
|
|
354
|
+
"src/platform/symlink-adapter.ts"() {
|
|
355
|
+
"use strict";
|
|
356
|
+
init_cjs_shims();
|
|
357
|
+
fs6 = __toESM(require("fs"));
|
|
358
|
+
path6 = __toESM(require("path"));
|
|
359
|
+
import_node_os2 = require("os");
|
|
360
|
+
init_logger();
|
|
361
|
+
init_paths();
|
|
362
|
+
SymlinkAdapter = class {
|
|
363
|
+
async deploy(skillName, sourcePath, agent, options) {
|
|
364
|
+
const result = {
|
|
365
|
+
success: false,
|
|
366
|
+
agent: agent.name,
|
|
367
|
+
skillName,
|
|
368
|
+
deployedPath: null,
|
|
369
|
+
sourcePath,
|
|
370
|
+
isSymlink: true
|
|
371
|
+
};
|
|
372
|
+
let targetDir = null;
|
|
373
|
+
if (options?.projectPath && agent.skillsDir) {
|
|
374
|
+
targetDir = path6.join(options.projectPath, agent.skillsDir);
|
|
375
|
+
} else {
|
|
376
|
+
targetDir = agent.globalSkillsDir;
|
|
377
|
+
}
|
|
378
|
+
if (!targetDir) {
|
|
379
|
+
result.error = `Agent ${agent.displayName} has no skills directory configured`;
|
|
380
|
+
return result;
|
|
381
|
+
}
|
|
382
|
+
if (!fs6.existsSync(sourcePath)) {
|
|
383
|
+
result.error = `Source skill directory does not exist: ${sourcePath}`;
|
|
384
|
+
return result;
|
|
385
|
+
}
|
|
386
|
+
const linkPath = path6.join(targetDir, skillName);
|
|
387
|
+
result.deployedPath = linkPath;
|
|
388
|
+
if (fs6.existsSync(linkPath) && !options?.force) {
|
|
389
|
+
const stat = fs6.lstatSync(linkPath);
|
|
390
|
+
if (stat.isSymbolicLink()) {
|
|
391
|
+
const existingTarget = fs6.readlinkSync(linkPath);
|
|
392
|
+
const resolvedTarget = path6.resolve(path6.dirname(linkPath), existingTarget);
|
|
393
|
+
if (resolvedTarget === sourcePath) {
|
|
394
|
+
result.success = true;
|
|
395
|
+
return result;
|
|
396
|
+
}
|
|
397
|
+
}
|
|
398
|
+
result.error = `Skill already exists at ${linkPath}. Use --force to overwrite.`;
|
|
399
|
+
return result;
|
|
400
|
+
}
|
|
401
|
+
const symlinkResult = await createSymlinkSafe(sourcePath, linkPath);
|
|
402
|
+
if (!symlinkResult.success) {
|
|
403
|
+
result.error = symlinkResult.error;
|
|
404
|
+
return result;
|
|
405
|
+
}
|
|
406
|
+
result.success = true;
|
|
407
|
+
logger.info(`Deployed ${skillName} to ${agent.displayName}: ${linkPath} -> ${sourcePath}`);
|
|
408
|
+
return result;
|
|
409
|
+
}
|
|
410
|
+
async remove(skillName, agent, options) {
|
|
411
|
+
const result = {
|
|
412
|
+
success: false,
|
|
413
|
+
agent: agent.name,
|
|
414
|
+
skillName,
|
|
415
|
+
removedPath: null
|
|
416
|
+
};
|
|
417
|
+
let targetDir = null;
|
|
418
|
+
if (options?.projectPath && agent.skillsDir) {
|
|
419
|
+
targetDir = path6.join(options.projectPath, agent.skillsDir);
|
|
420
|
+
} else {
|
|
421
|
+
targetDir = agent.globalSkillsDir;
|
|
422
|
+
}
|
|
423
|
+
if (!targetDir) {
|
|
424
|
+
result.error = `Agent ${agent.displayName} has no skills directory configured`;
|
|
425
|
+
return result;
|
|
426
|
+
}
|
|
427
|
+
const linkPath = path6.join(targetDir, skillName);
|
|
428
|
+
result.removedPath = linkPath;
|
|
429
|
+
try {
|
|
430
|
+
if (!fs6.existsSync(linkPath)) {
|
|
431
|
+
result.success = true;
|
|
432
|
+
return result;
|
|
433
|
+
}
|
|
434
|
+
const stat = fs6.lstatSync(linkPath);
|
|
435
|
+
if (!stat.isSymbolicLink()) {
|
|
436
|
+
result.error = `Path is not a symlink: ${linkPath}`;
|
|
437
|
+
return result;
|
|
438
|
+
}
|
|
439
|
+
fs6.unlinkSync(linkPath);
|
|
440
|
+
result.success = true;
|
|
441
|
+
logger.info(`Removed ${skillName} from ${agent.displayName}: ${linkPath}`);
|
|
442
|
+
} catch (err) {
|
|
443
|
+
result.error = err.message;
|
|
444
|
+
}
|
|
445
|
+
return result;
|
|
446
|
+
}
|
|
447
|
+
async list(agent, options) {
|
|
448
|
+
const results = [];
|
|
449
|
+
let targetDir = null;
|
|
450
|
+
if (options?.projectPath && agent.skillsDir) {
|
|
451
|
+
targetDir = path6.join(options.projectPath, agent.skillsDir);
|
|
452
|
+
} else {
|
|
453
|
+
targetDir = agent.globalSkillsDir;
|
|
454
|
+
}
|
|
455
|
+
if (!targetDir || !fs6.existsSync(targetDir)) {
|
|
456
|
+
return results;
|
|
457
|
+
}
|
|
458
|
+
try {
|
|
459
|
+
const entries = fs6.readdirSync(targetDir, { withFileTypes: true });
|
|
460
|
+
for (const entry of entries) {
|
|
461
|
+
const fullPath = path6.join(targetDir, entry.name);
|
|
462
|
+
try {
|
|
463
|
+
const stat = fs6.lstatSync(fullPath);
|
|
464
|
+
if (stat.isSymbolicLink()) {
|
|
465
|
+
const target = fs6.readlinkSync(fullPath);
|
|
466
|
+
const resolvedTarget = path6.resolve(path6.dirname(fullPath), target);
|
|
467
|
+
const isValid2 = fs6.existsSync(resolvedTarget);
|
|
468
|
+
results.push({
|
|
469
|
+
name: entry.name,
|
|
470
|
+
agent: agent.name,
|
|
471
|
+
path: fullPath,
|
|
472
|
+
isValid: isValid2,
|
|
473
|
+
target: resolvedTarget,
|
|
474
|
+
isSymlink: true
|
|
475
|
+
});
|
|
476
|
+
} else if (stat.isDirectory()) {
|
|
477
|
+
const skillMdPath = path6.join(fullPath, "SKILL.md");
|
|
478
|
+
results.push({
|
|
479
|
+
name: entry.name,
|
|
480
|
+
agent: agent.name,
|
|
481
|
+
path: fullPath,
|
|
482
|
+
isValid: fs6.existsSync(skillMdPath),
|
|
483
|
+
isSymlink: false
|
|
484
|
+
});
|
|
485
|
+
}
|
|
486
|
+
} catch {
|
|
487
|
+
}
|
|
488
|
+
}
|
|
489
|
+
} catch {
|
|
490
|
+
}
|
|
491
|
+
return results;
|
|
492
|
+
}
|
|
493
|
+
async isDeployed(skillName, agent, options) {
|
|
494
|
+
let targetDir = null;
|
|
495
|
+
if (options?.projectPath && agent.skillsDir) {
|
|
496
|
+
targetDir = path6.join(options.projectPath, agent.skillsDir);
|
|
497
|
+
} else {
|
|
498
|
+
targetDir = agent.globalSkillsDir;
|
|
499
|
+
}
|
|
500
|
+
if (!targetDir) {
|
|
501
|
+
return { deployed: false, valid: false };
|
|
502
|
+
}
|
|
503
|
+
const linkPath = path6.join(targetDir, skillName);
|
|
504
|
+
try {
|
|
505
|
+
if (!fs6.existsSync(linkPath)) {
|
|
506
|
+
return { deployed: false, valid: false };
|
|
507
|
+
}
|
|
508
|
+
const stat = fs6.lstatSync(linkPath);
|
|
509
|
+
if (!stat.isSymbolicLink()) {
|
|
510
|
+
const skillMdPath = path6.join(linkPath, "SKILL.md");
|
|
511
|
+
return {
|
|
512
|
+
deployed: true,
|
|
513
|
+
valid: fs6.existsSync(skillMdPath),
|
|
514
|
+
path: linkPath
|
|
515
|
+
};
|
|
516
|
+
}
|
|
517
|
+
const target = fs6.readlinkSync(linkPath);
|
|
518
|
+
const resolvedTarget = path6.resolve(path6.dirname(linkPath), target);
|
|
519
|
+
const isValid2 = fs6.existsSync(resolvedTarget);
|
|
520
|
+
return {
|
|
521
|
+
deployed: true,
|
|
522
|
+
valid: isValid2,
|
|
523
|
+
path: linkPath
|
|
524
|
+
};
|
|
525
|
+
} catch {
|
|
526
|
+
return { deployed: false, valid: false };
|
|
527
|
+
}
|
|
528
|
+
}
|
|
529
|
+
};
|
|
530
|
+
symlinkAdapter = new SymlinkAdapter();
|
|
531
|
+
}
|
|
532
|
+
});
|
|
533
|
+
|
|
534
|
+
// src/platform/format-converter.ts
|
|
535
|
+
function convertToMdc(skill) {
|
|
536
|
+
const lines = [];
|
|
537
|
+
lines.push("---");
|
|
538
|
+
lines.push(`description: "${skill.description.replace(/"/g, '\\"')}"`);
|
|
539
|
+
lines.push("globs:");
|
|
540
|
+
lines.push("alwaysApply: false");
|
|
541
|
+
lines.push("---");
|
|
542
|
+
lines.push("");
|
|
543
|
+
lines.push(`# ${skill.displayName || formatSkillName(skill.name)}`);
|
|
544
|
+
lines.push("");
|
|
545
|
+
lines.push(skill.description);
|
|
546
|
+
lines.push("");
|
|
547
|
+
lines.push(skill.body);
|
|
548
|
+
if (skill.skillId || skill.workflowId) {
|
|
549
|
+
lines.push("");
|
|
550
|
+
lines.push("---");
|
|
551
|
+
lines.push("");
|
|
552
|
+
lines.push("## Refly Skill");
|
|
553
|
+
lines.push("");
|
|
554
|
+
if (skill.skillId) {
|
|
555
|
+
lines.push(`- **Skill ID**: ${skill.skillId}`);
|
|
556
|
+
}
|
|
557
|
+
if (skill.workflowId) {
|
|
558
|
+
lines.push(`- **Workflow ID**: ${skill.workflowId}`);
|
|
559
|
+
}
|
|
560
|
+
if (skill.installationId) {
|
|
561
|
+
lines.push(`- **Installation ID**: ${skill.installationId}`);
|
|
562
|
+
}
|
|
563
|
+
const runId = skill.installationId || skill.workflowId || skill.name;
|
|
564
|
+
lines.push(`- **Run**: \`refly skill run ${runId}\``);
|
|
565
|
+
}
|
|
566
|
+
return lines.join("\n");
|
|
567
|
+
}
|
|
568
|
+
function convertToRules(skill) {
|
|
569
|
+
const lines = [];
|
|
570
|
+
lines.push(`# ${skill.displayName || formatSkillName(skill.name)}`);
|
|
571
|
+
lines.push("");
|
|
572
|
+
lines.push(`> ${skill.description}`);
|
|
573
|
+
lines.push("");
|
|
574
|
+
if (skill.triggers && skill.triggers.length > 0) {
|
|
575
|
+
lines.push("## Triggers");
|
|
576
|
+
lines.push("");
|
|
577
|
+
for (const trigger of skill.triggers) {
|
|
578
|
+
lines.push(`- ${trigger}`);
|
|
579
|
+
}
|
|
580
|
+
lines.push("");
|
|
581
|
+
}
|
|
582
|
+
lines.push(skill.body);
|
|
583
|
+
if (skill.skillId || skill.workflowId) {
|
|
584
|
+
lines.push("");
|
|
585
|
+
lines.push("---");
|
|
586
|
+
lines.push("");
|
|
587
|
+
lines.push("## Refly Skill");
|
|
588
|
+
lines.push("");
|
|
589
|
+
if (skill.skillId) {
|
|
590
|
+
lines.push(`- **Skill ID**: ${skill.skillId}`);
|
|
591
|
+
}
|
|
592
|
+
if (skill.workflowId) {
|
|
593
|
+
lines.push(`- **Workflow ID**: ${skill.workflowId}`);
|
|
594
|
+
}
|
|
595
|
+
if (skill.installationId) {
|
|
596
|
+
lines.push(`- **Installation ID**: ${skill.installationId}`);
|
|
597
|
+
}
|
|
598
|
+
const runId = skill.installationId || skill.workflowId || skill.name;
|
|
599
|
+
lines.push(`- **Run**: \`refly skill run ${runId}\``);
|
|
600
|
+
}
|
|
601
|
+
return lines.join("\n");
|
|
602
|
+
}
|
|
603
|
+
function formatSkillName(name) {
|
|
604
|
+
return name.split("-").map((w) => w.charAt(0).toUpperCase() + w.slice(1)).join(" ");
|
|
605
|
+
}
|
|
606
|
+
function parseSkillMdLenient(content) {
|
|
607
|
+
const frontmatterRegex = /^---\n([\s\S]*?)\n---\n?([\s\S]*)$/;
|
|
608
|
+
const match = content.match(frontmatterRegex);
|
|
609
|
+
if (!match) {
|
|
610
|
+
return null;
|
|
611
|
+
}
|
|
612
|
+
const [, frontmatterStr, body] = match;
|
|
613
|
+
const meta = {};
|
|
614
|
+
const lines = frontmatterStr.split("\n");
|
|
615
|
+
let currentKey = null;
|
|
616
|
+
let currentArray = [];
|
|
617
|
+
for (const line of lines) {
|
|
618
|
+
const trimmed = line.trim();
|
|
619
|
+
if (trimmed.startsWith("- ")) {
|
|
620
|
+
if (currentKey) {
|
|
621
|
+
currentArray.push(trimmed.slice(2).trim());
|
|
622
|
+
}
|
|
623
|
+
continue;
|
|
624
|
+
}
|
|
625
|
+
if (currentKey && currentArray.length > 0) {
|
|
626
|
+
meta[currentKey] = currentArray;
|
|
627
|
+
currentArray = [];
|
|
628
|
+
currentKey = null;
|
|
629
|
+
}
|
|
630
|
+
const colonIndex = trimmed.indexOf(":");
|
|
631
|
+
if (colonIndex > 0) {
|
|
632
|
+
const key = trimmed.slice(0, colonIndex).trim();
|
|
633
|
+
const value = trimmed.slice(colonIndex + 1).trim();
|
|
634
|
+
if (value === "") {
|
|
635
|
+
currentKey = key;
|
|
636
|
+
currentArray = [];
|
|
637
|
+
} else {
|
|
638
|
+
meta[key] = value;
|
|
639
|
+
}
|
|
640
|
+
}
|
|
641
|
+
}
|
|
642
|
+
if (currentKey && currentArray.length > 0) {
|
|
643
|
+
meta[currentKey] = currentArray;
|
|
644
|
+
}
|
|
645
|
+
if (!meta.name || !meta.description) {
|
|
646
|
+
return null;
|
|
647
|
+
}
|
|
648
|
+
return {
|
|
649
|
+
name: meta.name,
|
|
650
|
+
displayName: meta.displayName,
|
|
651
|
+
description: meta.description,
|
|
652
|
+
skillId: meta.skillId,
|
|
653
|
+
workflowId: meta.workflowId,
|
|
654
|
+
installationId: meta.installationId,
|
|
655
|
+
triggers: meta.triggers,
|
|
656
|
+
tags: meta.tags,
|
|
657
|
+
version: meta.version,
|
|
658
|
+
body: body.trim()
|
|
659
|
+
};
|
|
660
|
+
}
|
|
661
|
+
function readSkillMd(sourcePath) {
|
|
662
|
+
const skillMdPath = path7.join(sourcePath, "SKILL.md");
|
|
663
|
+
if (!fs7.existsSync(skillMdPath)) {
|
|
664
|
+
return null;
|
|
665
|
+
}
|
|
666
|
+
try {
|
|
667
|
+
const content = fs7.readFileSync(skillMdPath, "utf-8");
|
|
668
|
+
return parseSkillMdLenient(content);
|
|
669
|
+
} catch {
|
|
670
|
+
return null;
|
|
671
|
+
}
|
|
672
|
+
}
|
|
673
|
+
var fs7, path7, FormatConverterAdapter, formatConverterAdapter;
|
|
674
|
+
var init_format_converter = __esm({
|
|
675
|
+
"src/platform/format-converter.ts"() {
|
|
676
|
+
"use strict";
|
|
677
|
+
init_cjs_shims();
|
|
678
|
+
fs7 = __toESM(require("fs"));
|
|
679
|
+
path7 = __toESM(require("path"));
|
|
680
|
+
init_logger();
|
|
681
|
+
init_paths();
|
|
682
|
+
FormatConverterAdapter = class {
|
|
683
|
+
async deploy(skillName, sourcePath, agent, options) {
|
|
684
|
+
const result = {
|
|
685
|
+
success: false,
|
|
686
|
+
agent: agent.name,
|
|
687
|
+
skillName,
|
|
688
|
+
deployedPath: null,
|
|
689
|
+
sourcePath,
|
|
690
|
+
isSymlink: false
|
|
691
|
+
// We generate files, not symlinks
|
|
692
|
+
};
|
|
693
|
+
let targetDir = null;
|
|
694
|
+
if (options?.projectPath && agent.skillsDir) {
|
|
695
|
+
targetDir = path7.join(options.projectPath, agent.skillsDir);
|
|
696
|
+
} else {
|
|
697
|
+
targetDir = agent.globalSkillsDir;
|
|
698
|
+
}
|
|
699
|
+
if (!targetDir) {
|
|
700
|
+
result.success = true;
|
|
701
|
+
logger.debug(`Skipping ${skillName} for ${agent.displayName}: no global skills directory`);
|
|
702
|
+
return result;
|
|
703
|
+
}
|
|
704
|
+
const skill = readSkillMd(sourcePath);
|
|
705
|
+
if (!skill) {
|
|
706
|
+
result.error = `Failed to read SKILL.md from ${sourcePath}`;
|
|
707
|
+
return result;
|
|
708
|
+
}
|
|
709
|
+
const extension = agent.fileExtension || ".md";
|
|
710
|
+
const filePath = path7.join(targetDir, `${skillName}${extension}`);
|
|
711
|
+
result.deployedPath = filePath;
|
|
712
|
+
if (fs7.existsSync(filePath) && !options?.force) {
|
|
713
|
+
result.error = `Skill already exists at ${filePath}. Use --force to overwrite.`;
|
|
714
|
+
return result;
|
|
715
|
+
}
|
|
716
|
+
let content;
|
|
717
|
+
switch (agent.format) {
|
|
718
|
+
case "cursor-mdc":
|
|
719
|
+
content = convertToMdc(skill);
|
|
720
|
+
break;
|
|
721
|
+
case "rules-md":
|
|
722
|
+
content = convertToRules(skill);
|
|
723
|
+
break;
|
|
724
|
+
default:
|
|
725
|
+
result.error = `Unsupported format: ${agent.format}`;
|
|
726
|
+
return result;
|
|
727
|
+
}
|
|
728
|
+
try {
|
|
729
|
+
ensureDir(targetDir);
|
|
730
|
+
fs7.writeFileSync(filePath, content, { encoding: "utf-8", mode: 420 });
|
|
731
|
+
result.success = true;
|
|
732
|
+
logger.info(`Deployed ${skillName} to ${agent.displayName}: ${filePath}`);
|
|
733
|
+
} catch (err) {
|
|
734
|
+
result.error = err.message;
|
|
735
|
+
}
|
|
736
|
+
return result;
|
|
737
|
+
}
|
|
738
|
+
async remove(skillName, agent, options) {
|
|
739
|
+
const result = {
|
|
740
|
+
success: false,
|
|
741
|
+
agent: agent.name,
|
|
742
|
+
skillName,
|
|
743
|
+
removedPath: null
|
|
744
|
+
};
|
|
745
|
+
let targetDir = null;
|
|
746
|
+
if (options?.projectPath && agent.skillsDir) {
|
|
747
|
+
targetDir = path7.join(options.projectPath, agent.skillsDir);
|
|
748
|
+
} else {
|
|
749
|
+
targetDir = agent.globalSkillsDir;
|
|
750
|
+
}
|
|
751
|
+
if (!targetDir) {
|
|
752
|
+
result.success = true;
|
|
753
|
+
logger.debug(
|
|
754
|
+
`Skipping ${skillName} removal for ${agent.displayName}: no global skills directory`
|
|
755
|
+
);
|
|
756
|
+
return result;
|
|
757
|
+
}
|
|
758
|
+
const extension = agent.fileExtension || ".md";
|
|
759
|
+
const filePath = path7.join(targetDir, `${skillName}${extension}`);
|
|
760
|
+
result.removedPath = filePath;
|
|
761
|
+
try {
|
|
762
|
+
if (!fs7.existsSync(filePath)) {
|
|
763
|
+
result.success = true;
|
|
764
|
+
return result;
|
|
765
|
+
}
|
|
766
|
+
fs7.unlinkSync(filePath);
|
|
767
|
+
result.success = true;
|
|
768
|
+
logger.info(`Removed ${skillName} from ${agent.displayName}: ${filePath}`);
|
|
769
|
+
} catch (err) {
|
|
770
|
+
result.error = err.message;
|
|
771
|
+
}
|
|
772
|
+
return result;
|
|
773
|
+
}
|
|
774
|
+
async list(agent, options) {
|
|
775
|
+
const results = [];
|
|
776
|
+
let targetDir = null;
|
|
777
|
+
if (options?.projectPath && agent.skillsDir) {
|
|
778
|
+
targetDir = path7.join(options.projectPath, agent.skillsDir);
|
|
779
|
+
} else {
|
|
780
|
+
targetDir = agent.globalSkillsDir;
|
|
781
|
+
}
|
|
782
|
+
if (!targetDir || !fs7.existsSync(targetDir)) {
|
|
783
|
+
return results;
|
|
784
|
+
}
|
|
785
|
+
const extension = agent.fileExtension || ".md";
|
|
786
|
+
try {
|
|
787
|
+
const entries = fs7.readdirSync(targetDir, { withFileTypes: true });
|
|
788
|
+
for (const entry of entries) {
|
|
789
|
+
if (entry.isFile() && entry.name.endsWith(extension)) {
|
|
790
|
+
const fullPath = path7.join(targetDir, entry.name);
|
|
791
|
+
const skillName = entry.name.slice(0, -extension.length);
|
|
792
|
+
let isReflySkill = false;
|
|
793
|
+
try {
|
|
794
|
+
const content = fs7.readFileSync(fullPath, "utf-8");
|
|
795
|
+
isReflySkill = content.includes("## Refly Skill") || content.includes("Skill ID:");
|
|
796
|
+
} catch {
|
|
797
|
+
}
|
|
798
|
+
results.push({
|
|
799
|
+
name: skillName,
|
|
800
|
+
agent: agent.name,
|
|
801
|
+
path: fullPath,
|
|
802
|
+
isValid: isReflySkill,
|
|
803
|
+
isSymlink: false
|
|
804
|
+
});
|
|
805
|
+
}
|
|
806
|
+
}
|
|
807
|
+
} catch {
|
|
808
|
+
}
|
|
809
|
+
return results;
|
|
810
|
+
}
|
|
811
|
+
async isDeployed(skillName, agent, options) {
|
|
812
|
+
let targetDir = null;
|
|
813
|
+
if (options?.projectPath && agent.skillsDir) {
|
|
814
|
+
targetDir = path7.join(options.projectPath, agent.skillsDir);
|
|
815
|
+
} else {
|
|
816
|
+
targetDir = agent.globalSkillsDir;
|
|
817
|
+
}
|
|
818
|
+
if (!targetDir) {
|
|
819
|
+
return { deployed: false, valid: false };
|
|
820
|
+
}
|
|
821
|
+
const extension = agent.fileExtension || ".md";
|
|
822
|
+
const filePath = path7.join(targetDir, `${skillName}${extension}`);
|
|
823
|
+
if (!fs7.existsSync(filePath)) {
|
|
824
|
+
return { deployed: false, valid: false };
|
|
825
|
+
}
|
|
826
|
+
let isValid2 = false;
|
|
827
|
+
try {
|
|
828
|
+
const content = fs7.readFileSync(filePath, "utf-8");
|
|
829
|
+
isValid2 = content.includes("## Refly Skill") || content.includes("Skill ID:");
|
|
830
|
+
} catch {
|
|
831
|
+
}
|
|
832
|
+
return {
|
|
833
|
+
deployed: true,
|
|
834
|
+
valid: isValid2,
|
|
835
|
+
path: filePath
|
|
836
|
+
};
|
|
837
|
+
}
|
|
838
|
+
};
|
|
839
|
+
formatConverterAdapter = new FormatConverterAdapter();
|
|
840
|
+
}
|
|
841
|
+
});
|
|
842
|
+
|
|
843
|
+
// src/platform/manager.ts
|
|
844
|
+
function getAdapter(agent) {
|
|
845
|
+
switch (agent.format) {
|
|
846
|
+
case "skill-md":
|
|
847
|
+
return symlinkAdapter;
|
|
848
|
+
case "cursor-mdc":
|
|
849
|
+
case "rules-md":
|
|
850
|
+
return formatConverterAdapter;
|
|
851
|
+
default:
|
|
852
|
+
return symlinkAdapter;
|
|
853
|
+
}
|
|
854
|
+
}
|
|
855
|
+
async function detectInstalledAgents() {
|
|
856
|
+
const installed = [];
|
|
857
|
+
for (const agent of Object.values(agents)) {
|
|
858
|
+
try {
|
|
859
|
+
const isInstalled = await agent.detectInstalled();
|
|
860
|
+
if (isInstalled) {
|
|
861
|
+
installed.push(agent);
|
|
862
|
+
}
|
|
863
|
+
} catch (err) {
|
|
864
|
+
logger.debug(`Error detecting ${agent.displayName}: ${err.message}`);
|
|
865
|
+
}
|
|
866
|
+
}
|
|
867
|
+
return installed;
|
|
868
|
+
}
|
|
869
|
+
async function getDeployableAgents(options) {
|
|
870
|
+
const installed = await detectInstalledAgents();
|
|
871
|
+
if (options?.includeUnknown) {
|
|
872
|
+
return installed;
|
|
873
|
+
}
|
|
874
|
+
return installed.filter((agent) => agent.format !== "unknown");
|
|
875
|
+
}
|
|
876
|
+
async function deploySkillToAllPlatforms(skillName, options) {
|
|
877
|
+
const sourcePath = skillName === "refly" ? getReflyBaseSkillDir() : getReflyDomainSkillDir(skillName);
|
|
878
|
+
const result = {
|
|
879
|
+
skillName,
|
|
880
|
+
sourcePath,
|
|
881
|
+
results: /* @__PURE__ */ new Map(),
|
|
882
|
+
successCount: 0,
|
|
883
|
+
failureCount: 0
|
|
884
|
+
};
|
|
885
|
+
if (!fs8.existsSync(sourcePath)) {
|
|
886
|
+
logger.error(`Source skill directory does not exist: ${sourcePath}`);
|
|
887
|
+
return result;
|
|
888
|
+
}
|
|
889
|
+
let targetAgents;
|
|
890
|
+
if (options?.agents && options.agents.length > 0) {
|
|
891
|
+
targetAgents = options.agents.map((name) => agents[name]).filter(Boolean);
|
|
892
|
+
} else {
|
|
893
|
+
targetAgents = await getDeployableAgents();
|
|
894
|
+
}
|
|
895
|
+
for (const agent of targetAgents) {
|
|
896
|
+
const adapter = getAdapter(agent);
|
|
897
|
+
try {
|
|
898
|
+
const deployResult = await adapter.deploy(skillName, sourcePath, agent, {
|
|
899
|
+
force: options?.force,
|
|
900
|
+
projectPath: options?.projectPath
|
|
901
|
+
});
|
|
902
|
+
result.results.set(agent.name, deployResult);
|
|
903
|
+
if (deployResult.success) {
|
|
904
|
+
result.successCount++;
|
|
905
|
+
} else {
|
|
906
|
+
result.failureCount++;
|
|
907
|
+
}
|
|
908
|
+
} catch (err) {
|
|
909
|
+
result.results.set(agent.name, {
|
|
910
|
+
success: false,
|
|
911
|
+
agent: agent.name,
|
|
912
|
+
skillName,
|
|
913
|
+
deployedPath: null,
|
|
914
|
+
sourcePath,
|
|
915
|
+
isSymlink: false,
|
|
916
|
+
error: err.message
|
|
917
|
+
});
|
|
918
|
+
result.failureCount++;
|
|
919
|
+
}
|
|
920
|
+
}
|
|
921
|
+
return result;
|
|
922
|
+
}
|
|
923
|
+
async function removeSkillFromAllPlatforms(skillName, options) {
|
|
924
|
+
const result = {
|
|
925
|
+
skillName,
|
|
926
|
+
results: /* @__PURE__ */ new Map(),
|
|
927
|
+
successCount: 0,
|
|
928
|
+
failureCount: 0
|
|
929
|
+
};
|
|
930
|
+
let targetAgents;
|
|
931
|
+
if (options?.agents && options.agents.length > 0) {
|
|
932
|
+
targetAgents = options.agents.map((name) => agents[name]).filter(Boolean);
|
|
933
|
+
} else {
|
|
934
|
+
targetAgents = await getDeployableAgents();
|
|
935
|
+
}
|
|
936
|
+
for (const agent of targetAgents) {
|
|
937
|
+
const adapter = getAdapter(agent);
|
|
938
|
+
try {
|
|
939
|
+
const removeResult = await adapter.remove(skillName, agent, {
|
|
940
|
+
projectPath: options?.projectPath
|
|
941
|
+
});
|
|
942
|
+
result.results.set(agent.name, removeResult);
|
|
943
|
+
if (removeResult.success) {
|
|
944
|
+
result.successCount++;
|
|
945
|
+
} else {
|
|
946
|
+
result.failureCount++;
|
|
947
|
+
}
|
|
948
|
+
} catch (err) {
|
|
949
|
+
result.results.set(agent.name, {
|
|
950
|
+
success: false,
|
|
951
|
+
agent: agent.name,
|
|
952
|
+
skillName,
|
|
953
|
+
removedPath: null,
|
|
954
|
+
error: err.message
|
|
955
|
+
});
|
|
956
|
+
result.failureCount++;
|
|
957
|
+
}
|
|
958
|
+
}
|
|
959
|
+
return result;
|
|
960
|
+
}
|
|
961
|
+
async function listAllDeployedSkills(options) {
|
|
962
|
+
const result = /* @__PURE__ */ new Map();
|
|
963
|
+
let targetAgents;
|
|
964
|
+
if (options?.agents && options.agents.length > 0) {
|
|
965
|
+
targetAgents = options.agents.map((name) => agents[name]).filter(Boolean);
|
|
966
|
+
} else {
|
|
967
|
+
targetAgents = await getDeployableAgents();
|
|
968
|
+
}
|
|
969
|
+
for (const agent of targetAgents) {
|
|
970
|
+
const adapter = getAdapter(agent);
|
|
971
|
+
try {
|
|
972
|
+
const skills = await adapter.list(agent, {
|
|
973
|
+
projectPath: options?.projectPath
|
|
974
|
+
});
|
|
975
|
+
result.set(agent.name, skills);
|
|
976
|
+
} catch (err) {
|
|
977
|
+
logger.debug(`Error listing skills for ${agent.displayName}: ${err.message}`);
|
|
978
|
+
result.set(agent.name, []);
|
|
979
|
+
}
|
|
980
|
+
}
|
|
981
|
+
return result;
|
|
982
|
+
}
|
|
983
|
+
var fs8;
|
|
984
|
+
var init_manager = __esm({
|
|
985
|
+
"src/platform/manager.ts"() {
|
|
986
|
+
"use strict";
|
|
987
|
+
init_cjs_shims();
|
|
988
|
+
fs8 = __toESM(require("fs"));
|
|
989
|
+
init_registry();
|
|
990
|
+
init_symlink_adapter();
|
|
991
|
+
init_format_converter();
|
|
992
|
+
init_paths();
|
|
993
|
+
init_logger();
|
|
994
|
+
}
|
|
995
|
+
});
|
|
996
|
+
|
|
188
997
|
// src/skill/symlink.ts
|
|
189
998
|
var symlink_exports = {};
|
|
190
999
|
__export(symlink_exports, {
|
|
1000
|
+
createMultiPlatformSkill: () => createMultiPlatformSkill,
|
|
191
1001
|
createReflySkillWithSymlink: () => createReflySkillWithSymlink,
|
|
192
1002
|
createSkillSymlink: () => createSkillSymlink,
|
|
193
1003
|
deleteDomainSkillWithSymlink: () => deleteDomainSkillWithSymlink,
|
|
194
1004
|
generateReflySkillMd: () => generateReflySkillMd,
|
|
195
1005
|
initializeBaseSkillSymlink: () => initializeBaseSkillSymlink,
|
|
196
1006
|
isSkillSymlinkValid: () => isSkillSymlinkValid,
|
|
1007
|
+
listMultiPlatformSkills: () => listMultiPlatformSkills,
|
|
197
1008
|
listSkillSymlinks: () => listSkillSymlinks,
|
|
198
1009
|
parseReflySkillMd: () => parseReflySkillMd,
|
|
1010
|
+
removeMultiPlatformSkill: () => removeMultiPlatformSkill,
|
|
199
1011
|
removeSkillSymlink: () => removeSkillSymlink
|
|
200
1012
|
});
|
|
201
1013
|
function createSkillSymlink(skillName) {
|
|
@@ -204,7 +1016,7 @@ function createSkillSymlink(skillName) {
|
|
|
204
1016
|
try {
|
|
205
1017
|
ensureReflySkillsDir();
|
|
206
1018
|
ensureClaudeSkillsDir();
|
|
207
|
-
if (!
|
|
1019
|
+
if (!fs9.existsSync(reflyPath)) {
|
|
208
1020
|
return {
|
|
209
1021
|
success: false,
|
|
210
1022
|
skillName,
|
|
@@ -213,10 +1025,10 @@ function createSkillSymlink(skillName) {
|
|
|
213
1025
|
error: `Source skill directory does not exist: ${reflyPath}`
|
|
214
1026
|
};
|
|
215
1027
|
}
|
|
216
|
-
if (
|
|
217
|
-
const stat =
|
|
1028
|
+
if (fs9.existsSync(claudePath) || fs9.lstatSync(claudePath).isSymbolicLink()) {
|
|
1029
|
+
const stat = fs9.lstatSync(claudePath);
|
|
218
1030
|
if (stat.isSymbolicLink()) {
|
|
219
|
-
|
|
1031
|
+
fs9.unlinkSync(claudePath);
|
|
220
1032
|
logger.debug(`Removed existing symlink: ${claudePath}`);
|
|
221
1033
|
} else if (stat.isDirectory()) {
|
|
222
1034
|
logger.warn(`Cannot create symlink: ${claudePath} is a directory, not a symlink`);
|
|
@@ -229,7 +1041,7 @@ function createSkillSymlink(skillName) {
|
|
|
229
1041
|
};
|
|
230
1042
|
}
|
|
231
1043
|
}
|
|
232
|
-
|
|
1044
|
+
fs9.symlinkSync(reflyPath, claudePath, "dir");
|
|
233
1045
|
logger.info(`Created symlink: ${claudePath} -> ${reflyPath}`);
|
|
234
1046
|
return {
|
|
235
1047
|
success: true,
|
|
@@ -240,7 +1052,7 @@ function createSkillSymlink(skillName) {
|
|
|
240
1052
|
} catch (err) {
|
|
241
1053
|
if (err.code === "ENOENT") {
|
|
242
1054
|
try {
|
|
243
|
-
|
|
1055
|
+
fs9.symlinkSync(reflyPath, claudePath, "dir");
|
|
244
1056
|
logger.info(`Created symlink: ${claudePath} -> ${reflyPath}`);
|
|
245
1057
|
return {
|
|
246
1058
|
success: true,
|
|
@@ -270,16 +1082,16 @@ function createSkillSymlink(skillName) {
|
|
|
270
1082
|
function removeSkillSymlink(skillName) {
|
|
271
1083
|
const claudePath = getClaudeSkillSymlinkPath(skillName);
|
|
272
1084
|
try {
|
|
273
|
-
if (!
|
|
1085
|
+
if (!fs9.existsSync(claudePath)) {
|
|
274
1086
|
logger.debug(`Symlink not found: ${claudePath}`);
|
|
275
1087
|
return false;
|
|
276
1088
|
}
|
|
277
|
-
const stat =
|
|
1089
|
+
const stat = fs9.lstatSync(claudePath);
|
|
278
1090
|
if (!stat.isSymbolicLink()) {
|
|
279
1091
|
logger.warn(`Not a symlink: ${claudePath}`);
|
|
280
1092
|
return false;
|
|
281
1093
|
}
|
|
282
|
-
|
|
1094
|
+
fs9.unlinkSync(claudePath);
|
|
283
1095
|
logger.info(`Removed symlink: ${claudePath}`);
|
|
284
1096
|
return true;
|
|
285
1097
|
} catch (err) {
|
|
@@ -291,16 +1103,16 @@ function isSkillSymlinkValid(skillName) {
|
|
|
291
1103
|
const claudePath = getClaudeSkillSymlinkPath(skillName);
|
|
292
1104
|
const expectedTarget = skillName === "refly" ? getReflyBaseSkillDir() : getReflyDomainSkillDir(skillName);
|
|
293
1105
|
try {
|
|
294
|
-
if (!
|
|
1106
|
+
if (!fs9.existsSync(claudePath)) {
|
|
295
1107
|
return { exists: false, isSymlink: false, isValid: false };
|
|
296
1108
|
}
|
|
297
|
-
const stat =
|
|
1109
|
+
const stat = fs9.lstatSync(claudePath);
|
|
298
1110
|
if (!stat.isSymbolicLink()) {
|
|
299
1111
|
return { exists: true, isSymlink: false, isValid: false };
|
|
300
1112
|
}
|
|
301
|
-
const target =
|
|
302
|
-
const resolvedTarget =
|
|
303
|
-
const isValid2 = resolvedTarget === expectedTarget &&
|
|
1113
|
+
const target = fs9.readlinkSync(claudePath);
|
|
1114
|
+
const resolvedTarget = path8.resolve(path8.dirname(claudePath), target);
|
|
1115
|
+
const isValid2 = resolvedTarget === expectedTarget && fs9.existsSync(resolvedTarget);
|
|
304
1116
|
return {
|
|
305
1117
|
exists: true,
|
|
306
1118
|
isSymlink: true,
|
|
@@ -314,17 +1126,17 @@ function isSkillSymlinkValid(skillName) {
|
|
|
314
1126
|
function initializeBaseSkillSymlink() {
|
|
315
1127
|
const baseDir = getReflyBaseSkillDir();
|
|
316
1128
|
ensureDir(baseDir);
|
|
317
|
-
ensureDir(
|
|
1129
|
+
ensureDir(path8.join(baseDir, "rules"));
|
|
318
1130
|
return createSkillSymlink("refly");
|
|
319
1131
|
}
|
|
320
1132
|
function createReflySkillWithSymlink(skillName, skillMdContent, options) {
|
|
321
1133
|
const skillDir = getReflyDomainSkillDir(skillName);
|
|
322
1134
|
try {
|
|
323
1135
|
ensureReflySkillsDir();
|
|
324
|
-
if (
|
|
1136
|
+
if (fs9.existsSync(skillDir)) {
|
|
325
1137
|
if (options?.force) {
|
|
326
|
-
const skillMdPath2 =
|
|
327
|
-
|
|
1138
|
+
const skillMdPath2 = path8.join(skillDir, "SKILL.md");
|
|
1139
|
+
fs9.writeFileSync(skillMdPath2, skillMdContent, { encoding: "utf-8", mode: 420 });
|
|
328
1140
|
logger.debug(`Updated SKILL.md (force): ${skillMdPath2}`);
|
|
329
1141
|
return createSkillSymlink(skillName);
|
|
330
1142
|
}
|
|
@@ -336,9 +1148,9 @@ function createReflySkillWithSymlink(skillName, skillMdContent, options) {
|
|
|
336
1148
|
error: `Skill directory already exists: ${skillDir}`
|
|
337
1149
|
};
|
|
338
1150
|
}
|
|
339
|
-
|
|
340
|
-
const skillMdPath =
|
|
341
|
-
|
|
1151
|
+
fs9.mkdirSync(skillDir, { recursive: true, mode: 493 });
|
|
1152
|
+
const skillMdPath = path8.join(skillDir, "SKILL.md");
|
|
1153
|
+
fs9.writeFileSync(skillMdPath, skillMdContent, { encoding: "utf-8", mode: 420 });
|
|
342
1154
|
logger.debug(`Created SKILL.md: ${skillMdPath}`);
|
|
343
1155
|
return createSkillSymlink(skillName);
|
|
344
1156
|
} catch (err) {
|
|
@@ -356,8 +1168,8 @@ function deleteDomainSkillWithSymlink(skillName) {
|
|
|
356
1168
|
const skillDir = getReflyDomainSkillDir(skillName);
|
|
357
1169
|
let directoryRemoved = false;
|
|
358
1170
|
try {
|
|
359
|
-
if (
|
|
360
|
-
|
|
1171
|
+
if (fs9.existsSync(skillDir)) {
|
|
1172
|
+
fs9.rmSync(skillDir, { recursive: true, force: true });
|
|
361
1173
|
directoryRemoved = true;
|
|
362
1174
|
logger.info(`Removed skill directory: ${skillDir}`);
|
|
363
1175
|
}
|
|
@@ -369,19 +1181,19 @@ function deleteDomainSkillWithSymlink(skillName) {
|
|
|
369
1181
|
function listSkillSymlinks() {
|
|
370
1182
|
const claudeSkillsDir = getClaudeSkillsDir();
|
|
371
1183
|
const results = [];
|
|
372
|
-
if (!
|
|
1184
|
+
if (!fs9.existsSync(claudeSkillsDir)) {
|
|
373
1185
|
return results;
|
|
374
1186
|
}
|
|
375
1187
|
try {
|
|
376
|
-
const entries =
|
|
1188
|
+
const entries = fs9.readdirSync(claudeSkillsDir, { withFileTypes: true });
|
|
377
1189
|
for (const entry of entries) {
|
|
378
|
-
const fullPath =
|
|
1190
|
+
const fullPath = path8.join(claudeSkillsDir, entry.name);
|
|
379
1191
|
try {
|
|
380
|
-
const stat =
|
|
1192
|
+
const stat = fs9.lstatSync(fullPath);
|
|
381
1193
|
if (stat.isSymbolicLink()) {
|
|
382
|
-
const target =
|
|
383
|
-
const resolvedTarget =
|
|
384
|
-
const isValid2 =
|
|
1194
|
+
const target = fs9.readlinkSync(fullPath);
|
|
1195
|
+
const resolvedTarget = path8.resolve(path8.dirname(fullPath), target);
|
|
1196
|
+
const isValid2 = fs9.existsSync(resolvedTarget);
|
|
385
1197
|
results.push({
|
|
386
1198
|
name: entry.name,
|
|
387
1199
|
claudePath: fullPath,
|
|
@@ -396,6 +1208,12 @@ function listSkillSymlinks() {
|
|
|
396
1208
|
}
|
|
397
1209
|
return results;
|
|
398
1210
|
}
|
|
1211
|
+
function escapeYamlValue(value) {
|
|
1212
|
+
if (value.includes(":") || value.includes("#") || value.includes("'") || value.includes('"') || value.includes("\n") || value.startsWith(" ") || value.endsWith(" ") || value.startsWith("[") || value.startsWith("{")) {
|
|
1213
|
+
return `"${value.replace(/\\/g, "\\\\").replace(/"/g, '\\"')}"`;
|
|
1214
|
+
}
|
|
1215
|
+
return value;
|
|
1216
|
+
}
|
|
399
1217
|
function generateReflySkillMd(options) {
|
|
400
1218
|
const {
|
|
401
1219
|
name,
|
|
@@ -410,21 +1228,21 @@ function generateReflySkillMd(options) {
|
|
|
410
1228
|
inputSchema,
|
|
411
1229
|
outputSchema
|
|
412
1230
|
} = options;
|
|
413
|
-
const frontmatterLines = ["---", `name: ${name}`];
|
|
414
|
-
frontmatterLines.push(`description: ${description}`);
|
|
1231
|
+
const frontmatterLines = ["---", `name: ${escapeYamlValue(name)}`];
|
|
1232
|
+
frontmatterLines.push(`description: ${escapeYamlValue(description)}`);
|
|
415
1233
|
if (tags.length > 0) {
|
|
416
1234
|
frontmatterLines.push("tags:");
|
|
417
|
-
frontmatterLines.push(...tags.map((t) => ` - ${t}`));
|
|
1235
|
+
frontmatterLines.push(...tags.map((t) => ` - ${escapeYamlValue(t)}`));
|
|
418
1236
|
}
|
|
419
|
-
frontmatterLines.push(`version: ${version}`);
|
|
420
|
-
frontmatterLines.push(`skillId: ${skillId}`);
|
|
421
|
-
frontmatterLines.push(`workflowId: ${workflowId}`);
|
|
1237
|
+
frontmatterLines.push(`version: ${escapeYamlValue(version)}`);
|
|
1238
|
+
frontmatterLines.push(`skillId: ${escapeYamlValue(skillId)}`);
|
|
1239
|
+
frontmatterLines.push(`workflowId: ${escapeYamlValue(workflowId)}`);
|
|
422
1240
|
if (installationId) {
|
|
423
|
-
frontmatterLines.push(`installationId: ${installationId}`);
|
|
1241
|
+
frontmatterLines.push(`installationId: ${escapeYamlValue(installationId)}`);
|
|
424
1242
|
}
|
|
425
1243
|
if (triggers.length > 0) {
|
|
426
1244
|
frontmatterLines.push("triggers:");
|
|
427
|
-
frontmatterLines.push(...triggers.map((t) => ` - ${t}`));
|
|
1245
|
+
frontmatterLines.push(...triggers.map((t) => ` - ${escapeYamlValue(t)}`));
|
|
428
1246
|
}
|
|
429
1247
|
frontmatterLines.push("---");
|
|
430
1248
|
const title = displayName || name.split("-").map((w) => w.charAt(0).toUpperCase() + w.slice(1)).join(" ");
|
|
@@ -443,14 +1261,6 @@ ${JSON.stringify(outputSchema, null, 2)}
|
|
|
443
1261
|
|
|
444
1262
|
${description}
|
|
445
1263
|
|
|
446
|
-
## Usage
|
|
447
|
-
|
|
448
|
-
This skill is executed via Refly CLI:
|
|
449
|
-
|
|
450
|
-
\`\`\`bash
|
|
451
|
-
${runCommand}
|
|
452
|
-
\`\`\`
|
|
453
|
-
|
|
454
1264
|
## Input
|
|
455
1265
|
|
|
456
1266
|
Provide input as JSON:
|
|
@@ -459,16 +1269,42 @@ Provide input as JSON:
|
|
|
459
1269
|
${inputExample}
|
|
460
1270
|
\`\`\`
|
|
461
1271
|
|
|
1272
|
+
## Execution
|
|
1273
|
+
|
|
1274
|
+
**Follow this exact 4-step pattern:**
|
|
1275
|
+
|
|
1276
|
+
\`\`\`bash
|
|
1277
|
+
# Step 1: Run and capture RUN_ID (we-xxx format)
|
|
1278
|
+
RESULT=$(${runCommand})
|
|
1279
|
+
RUN_ID=$(echo "$RESULT" | jq -r '.payload.workflowExecutions[0].id')
|
|
1280
|
+
# RUN_ID is we-xxx format, use this for workflow commands below
|
|
1281
|
+
|
|
1282
|
+
# Step 2: Wait for completion (use RUN_ID, not installationId)
|
|
1283
|
+
refly workflow status "$RUN_ID" --watch --interval 30000
|
|
1284
|
+
|
|
1285
|
+
# Step 3: Get files from this run (use RUN_ID)
|
|
1286
|
+
FILES=$(refly workflow toolcalls "$RUN_ID" --files --latest | jq -r '.payload.files[]')
|
|
1287
|
+
|
|
1288
|
+
# Step 4: Download and open each file
|
|
1289
|
+
echo "$FILES" | jq -c '.' | while read -r file; do
|
|
1290
|
+
FILE_ID=$(echo "$file" | jq -r '.fileId')
|
|
1291
|
+
FILE_NAME=$(echo "$file" | jq -r '.name')
|
|
1292
|
+
if [ -n "$FILE_ID" ] && [ "$FILE_ID" != "null" ]; then
|
|
1293
|
+
OUTPUT_PATH="$HOME/Desktop/$FILE_NAME"
|
|
1294
|
+
refly file download "$FILE_ID" -o "$OUTPUT_PATH"
|
|
1295
|
+
open "$OUTPUT_PATH"
|
|
1296
|
+
fi
|
|
1297
|
+
done
|
|
1298
|
+
\`\`\`
|
|
1299
|
+
|
|
462
1300
|
## Output
|
|
463
1301
|
|
|
464
1302
|
${outputSection}
|
|
465
1303
|
|
|
466
1304
|
## Rules
|
|
467
1305
|
|
|
468
|
-
For workflow operations, refer to the base skill
|
|
469
|
-
-
|
|
470
|
-
- Node: \`~/.claude/skills/refly/rules/node.md\`
|
|
471
|
-
- File: \`~/.claude/skills/refly/rules/file.md\`
|
|
1306
|
+
For workflow operations, refer to the base skill:
|
|
1307
|
+
- Base skill: \`~/.claude/skills/refly/SKILL.md\`
|
|
472
1308
|
`;
|
|
473
1309
|
return frontmatterLines.join("\n") + content;
|
|
474
1310
|
}
|
|
@@ -529,15 +1365,79 @@ function parseReflySkillMd(content) {
|
|
|
529
1365
|
raw: content
|
|
530
1366
|
};
|
|
531
1367
|
}
|
|
532
|
-
|
|
1368
|
+
async function createMultiPlatformSkill(skillName, skillMdContent, options) {
|
|
1369
|
+
const skillDir = getReflyDomainSkillDir(skillName);
|
|
1370
|
+
ensureReflySkillsDir();
|
|
1371
|
+
if (fs9.existsSync(skillDir)) {
|
|
1372
|
+
if (options?.force) {
|
|
1373
|
+
const skillMdPath = path8.join(skillDir, "SKILL.md");
|
|
1374
|
+
fs9.writeFileSync(skillMdPath, skillMdContent, { encoding: "utf-8", mode: 420 });
|
|
1375
|
+
logger.debug(`Updated SKILL.md (force): ${skillMdPath}`);
|
|
1376
|
+
} else {
|
|
1377
|
+
return {
|
|
1378
|
+
skillName,
|
|
1379
|
+
sourcePath: skillDir,
|
|
1380
|
+
results: /* @__PURE__ */ new Map(),
|
|
1381
|
+
successCount: 0,
|
|
1382
|
+
failureCount: 1
|
|
1383
|
+
};
|
|
1384
|
+
}
|
|
1385
|
+
} else {
|
|
1386
|
+
fs9.mkdirSync(skillDir, { recursive: true, mode: 493 });
|
|
1387
|
+
const skillMdPath = path8.join(skillDir, "SKILL.md");
|
|
1388
|
+
fs9.writeFileSync(skillMdPath, skillMdContent, { encoding: "utf-8", mode: 420 });
|
|
1389
|
+
logger.debug(`Created SKILL.md: ${skillMdPath}`);
|
|
1390
|
+
}
|
|
1391
|
+
return deploySkillToAllPlatforms(skillName, {
|
|
1392
|
+
force: options?.force,
|
|
1393
|
+
agents: options?.agents
|
|
1394
|
+
});
|
|
1395
|
+
}
|
|
1396
|
+
async function removeMultiPlatformSkill(skillName, options) {
|
|
1397
|
+
const platformResults = await removeSkillFromAllPlatforms(skillName, {
|
|
1398
|
+
agents: options?.agents
|
|
1399
|
+
});
|
|
1400
|
+
let directoryRemoved = false;
|
|
1401
|
+
if (!options?.keepLocal) {
|
|
1402
|
+
const skillDir = getReflyDomainSkillDir(skillName);
|
|
1403
|
+
try {
|
|
1404
|
+
if (fs9.existsSync(skillDir)) {
|
|
1405
|
+
fs9.rmSync(skillDir, { recursive: true, force: true });
|
|
1406
|
+
directoryRemoved = true;
|
|
1407
|
+
logger.info(`Removed skill directory: ${skillDir}`);
|
|
1408
|
+
}
|
|
1409
|
+
} catch (err) {
|
|
1410
|
+
logger.error(`Failed to remove skill directory ${skillDir}:`, err);
|
|
1411
|
+
}
|
|
1412
|
+
}
|
|
1413
|
+
return { platformResults, directoryRemoved };
|
|
1414
|
+
}
|
|
1415
|
+
async function listMultiPlatformSkills(options) {
|
|
1416
|
+
const allDeployed = await listAllDeployedSkills({ agents: options?.agents });
|
|
1417
|
+
const result = /* @__PURE__ */ new Map();
|
|
1418
|
+
for (const [agent, skills] of allDeployed) {
|
|
1419
|
+
result.set(
|
|
1420
|
+
agent,
|
|
1421
|
+
skills.map((s) => ({
|
|
1422
|
+
name: s.name,
|
|
1423
|
+
path: s.path,
|
|
1424
|
+
isValid: s.isValid,
|
|
1425
|
+
isSymlink: s.isSymlink
|
|
1426
|
+
}))
|
|
1427
|
+
);
|
|
1428
|
+
}
|
|
1429
|
+
return result;
|
|
1430
|
+
}
|
|
1431
|
+
var fs9, path8;
|
|
533
1432
|
var init_symlink = __esm({
|
|
534
1433
|
"src/skill/symlink.ts"() {
|
|
535
1434
|
"use strict";
|
|
536
1435
|
init_cjs_shims();
|
|
537
|
-
|
|
538
|
-
|
|
1436
|
+
fs9 = __toESM(require("fs"));
|
|
1437
|
+
path8 = __toESM(require("path"));
|
|
539
1438
|
init_paths();
|
|
540
1439
|
init_logger();
|
|
1440
|
+
init_manager();
|
|
541
1441
|
}
|
|
542
1442
|
});
|
|
543
1443
|
|
|
@@ -1196,8 +2096,8 @@ function getErrorMap() {
|
|
|
1196
2096
|
// ../../node_modules/.pnpm/zod@3.25.76/node_modules/zod/v3/helpers/parseUtil.js
|
|
1197
2097
|
init_cjs_shims();
|
|
1198
2098
|
var makeIssue = (params) => {
|
|
1199
|
-
const { data, path:
|
|
1200
|
-
const fullPath = [...
|
|
2099
|
+
const { data, path: path10, errorMaps, issueData } = params;
|
|
2100
|
+
const fullPath = [...path10, ...issueData.path || []];
|
|
1201
2101
|
const fullIssue = {
|
|
1202
2102
|
...issueData,
|
|
1203
2103
|
path: fullPath
|
|
@@ -1317,11 +2217,11 @@ var errorUtil;
|
|
|
1317
2217
|
|
|
1318
2218
|
// ../../node_modules/.pnpm/zod@3.25.76/node_modules/zod/v3/types.js
|
|
1319
2219
|
var ParseInputLazyPath = class {
|
|
1320
|
-
constructor(parent, value,
|
|
2220
|
+
constructor(parent, value, path10, key) {
|
|
1321
2221
|
this._cachedPath = [];
|
|
1322
2222
|
this.parent = parent;
|
|
1323
2223
|
this.data = value;
|
|
1324
|
-
this._path =
|
|
2224
|
+
this._path = path10;
|
|
1325
2225
|
this._key = key;
|
|
1326
2226
|
}
|
|
1327
2227
|
get path() {
|
|
@@ -4765,6 +5665,23 @@ var NEVER = INVALID;
|
|
|
4765
5665
|
|
|
4766
5666
|
// src/config/config.ts
|
|
4767
5667
|
init_paths();
|
|
5668
|
+
var AgentTypeEnum = external_exports.enum([
|
|
5669
|
+
"claude-code",
|
|
5670
|
+
"codex",
|
|
5671
|
+
"antigravity",
|
|
5672
|
+
"github-copilot",
|
|
5673
|
+
"windsurf",
|
|
5674
|
+
"opencode",
|
|
5675
|
+
"moltbot",
|
|
5676
|
+
"cursor",
|
|
5677
|
+
"continue",
|
|
5678
|
+
"trae",
|
|
5679
|
+
"qoder"
|
|
5680
|
+
]);
|
|
5681
|
+
var PlatformConfigSchema = external_exports.object({
|
|
5682
|
+
enabled: external_exports.boolean().default(true),
|
|
5683
|
+
globalPath: external_exports.string().optional()
|
|
5684
|
+
});
|
|
4768
5685
|
var ConfigSchema = external_exports.object({
|
|
4769
5686
|
version: external_exports.number().default(1),
|
|
4770
5687
|
auth: external_exports.object({
|
|
@@ -4792,9 +5709,11 @@ var ConfigSchema = external_exports.object({
|
|
|
4792
5709
|
skill: external_exports.object({
|
|
4793
5710
|
installedVersion: external_exports.string().optional(),
|
|
4794
5711
|
installedAt: external_exports.string().optional()
|
|
4795
|
-
}).optional()
|
|
5712
|
+
}).optional(),
|
|
5713
|
+
// Multi-platform configuration
|
|
5714
|
+
platforms: external_exports.record(AgentTypeEnum, PlatformConfigSchema).optional()
|
|
4796
5715
|
});
|
|
4797
|
-
var DEFAULT_API_ENDPOINT = "https://
|
|
5716
|
+
var DEFAULT_API_ENDPOINT = "https://api.refly.ai";
|
|
4798
5717
|
var DEFAULT_CONFIG = {
|
|
4799
5718
|
version: 1,
|
|
4800
5719
|
api: {
|
|
@@ -4899,10 +5818,10 @@ var path4 = __toESM(require("path"));
|
|
|
4899
5818
|
var import_mime = __toESM(require("mime"));
|
|
4900
5819
|
init_logger();
|
|
4901
5820
|
var DEFAULT_TIMEOUT = 3e4;
|
|
4902
|
-
async function apiRequest(
|
|
5821
|
+
async function apiRequest(path10, options = {}) {
|
|
4903
5822
|
const { method = "GET", body, query, timeout = DEFAULT_TIMEOUT, requireAuth = true } = options;
|
|
4904
5823
|
const endpoint = getApiEndpoint();
|
|
4905
|
-
let url = `${endpoint}${
|
|
5824
|
+
let url = `${endpoint}${path10}`;
|
|
4906
5825
|
if (query && Object.keys(query).length > 0) {
|
|
4907
5826
|
const params = new URLSearchParams(query);
|
|
4908
5827
|
url = `${url}?${params.toString()}`;
|
|
@@ -4940,7 +5859,7 @@ async function apiRequest(path7, options = {}) {
|
|
|
4940
5859
|
const controller = new AbortController();
|
|
4941
5860
|
const timeoutId = setTimeout(() => controller.abort(), timeout);
|
|
4942
5861
|
try {
|
|
4943
|
-
logger.debug(`API Request: ${method} ${
|
|
5862
|
+
logger.debug(`API Request: ${method} ${path10}`);
|
|
4944
5863
|
const response = await fetch(url, {
|
|
4945
5864
|
method,
|
|
4946
5865
|
headers,
|
|
@@ -5086,22 +6005,22 @@ async function verifyConnection() {
|
|
|
5086
6005
|
|
|
5087
6006
|
// src/skill/installer.ts
|
|
5088
6007
|
init_cjs_shims();
|
|
5089
|
-
var
|
|
5090
|
-
var
|
|
6008
|
+
var fs10 = __toESM(require("fs"));
|
|
6009
|
+
var path9 = __toESM(require("path"));
|
|
5091
6010
|
init_paths();
|
|
5092
6011
|
init_logger();
|
|
5093
6012
|
init_symlink();
|
|
5094
6013
|
function removeOldSkillDirectory() {
|
|
5095
6014
|
const claudeSkillPath = getClaudeSkillSymlinkPath("refly");
|
|
5096
|
-
if (!
|
|
6015
|
+
if (!fs10.existsSync(claudeSkillPath)) {
|
|
5097
6016
|
return;
|
|
5098
6017
|
}
|
|
5099
6018
|
try {
|
|
5100
|
-
const stat =
|
|
6019
|
+
const stat = fs10.lstatSync(claudeSkillPath);
|
|
5101
6020
|
if (stat.isSymbolicLink()) {
|
|
5102
|
-
|
|
6021
|
+
fs10.unlinkSync(claudeSkillPath);
|
|
5103
6022
|
} else if (stat.isDirectory()) {
|
|
5104
|
-
|
|
6023
|
+
fs10.rmSync(claudeSkillPath, { recursive: true, force: true });
|
|
5105
6024
|
logger.info("Removed old skill directory");
|
|
5106
6025
|
}
|
|
5107
6026
|
} catch (err) {
|
|
@@ -5110,17 +6029,17 @@ function removeOldSkillDirectory() {
|
|
|
5110
6029
|
}
|
|
5111
6030
|
function getPackageSkillDir() {
|
|
5112
6031
|
const possiblePaths = [
|
|
5113
|
-
|
|
6032
|
+
path9.join(__dirname, "..", "..", "skill"),
|
|
5114
6033
|
// Built package: dist/bin/../../skill
|
|
5115
|
-
|
|
6034
|
+
path9.join(__dirname, "..", "..", "..", "skill"),
|
|
5116
6035
|
// Development: dist/bin/../../../skill
|
|
5117
|
-
|
|
6036
|
+
path9.join(__dirname, "..", "skill")
|
|
5118
6037
|
// Alternative: dist/../skill
|
|
5119
6038
|
];
|
|
5120
6039
|
logger.debug("Looking for skill files, __dirname:", __dirname);
|
|
5121
6040
|
for (const p of possiblePaths) {
|
|
5122
|
-
const resolved =
|
|
5123
|
-
const exists =
|
|
6041
|
+
const resolved = path9.resolve(p);
|
|
6042
|
+
const exists = fs10.existsSync(resolved);
|
|
5124
6043
|
logger.debug(` Checking path: ${resolved} - exists: ${exists}`);
|
|
5125
6044
|
if (exists) {
|
|
5126
6045
|
return resolved;
|
|
@@ -5144,30 +6063,30 @@ function installSkill() {
|
|
|
5144
6063
|
logger.debug("Target skill directory:", targetDir);
|
|
5145
6064
|
try {
|
|
5146
6065
|
ensureDir(targetDir);
|
|
5147
|
-
ensureDir(
|
|
6066
|
+
ensureDir(path9.join(targetDir, "rules"));
|
|
5148
6067
|
logger.debug("Created target directories");
|
|
5149
6068
|
} catch (err) {
|
|
5150
6069
|
logger.error("Failed to create target directories:", err);
|
|
5151
6070
|
throw err;
|
|
5152
6071
|
}
|
|
5153
|
-
const skillSource =
|
|
5154
|
-
const skillTarget =
|
|
6072
|
+
const skillSource = path9.join(sourceDir, "SKILL.md");
|
|
6073
|
+
const skillTarget = path9.join(targetDir, "SKILL.md");
|
|
5155
6074
|
logger.debug(`Copying SKILL.md: ${skillSource} -> ${skillTarget}`);
|
|
5156
|
-
if (
|
|
5157
|
-
|
|
6075
|
+
if (fs10.existsSync(skillSource)) {
|
|
6076
|
+
fs10.copyFileSync(skillSource, skillTarget);
|
|
5158
6077
|
result.skillInstalled = true;
|
|
5159
6078
|
result.skillPath = targetDir;
|
|
5160
6079
|
logger.debug("SKILL.md copied successfully");
|
|
5161
6080
|
} else {
|
|
5162
6081
|
logger.warn("SKILL.md source not found:", skillSource);
|
|
5163
6082
|
}
|
|
5164
|
-
const refsSource =
|
|
5165
|
-
const rulesTarget =
|
|
5166
|
-
if (
|
|
5167
|
-
const files =
|
|
6083
|
+
const refsSource = path9.join(sourceDir, "references");
|
|
6084
|
+
const rulesTarget = path9.join(targetDir, "rules");
|
|
6085
|
+
if (fs10.existsSync(refsSource)) {
|
|
6086
|
+
const files = fs10.readdirSync(refsSource);
|
|
5168
6087
|
logger.debug(`Copying ${files.length} rule files`);
|
|
5169
6088
|
for (const file of files) {
|
|
5170
|
-
|
|
6089
|
+
fs10.copyFileSync(path9.join(refsSource, file), path9.join(rulesTarget, file));
|
|
5171
6090
|
}
|
|
5172
6091
|
}
|
|
5173
6092
|
removeOldSkillDirectory();
|
|
@@ -5195,15 +6114,15 @@ function installSkill() {
|
|
|
5195
6114
|
return result;
|
|
5196
6115
|
}
|
|
5197
6116
|
function installSlashCommands(sourceDir, targetDir) {
|
|
5198
|
-
const commandsSource =
|
|
5199
|
-
if (!
|
|
6117
|
+
const commandsSource = path9.join(sourceDir, "..", "commands");
|
|
6118
|
+
if (!fs10.existsSync(commandsSource)) {
|
|
5200
6119
|
return false;
|
|
5201
6120
|
}
|
|
5202
6121
|
try {
|
|
5203
|
-
const files =
|
|
6122
|
+
const files = fs10.readdirSync(commandsSource);
|
|
5204
6123
|
for (const file of files) {
|
|
5205
6124
|
if (file.endsWith(".md")) {
|
|
5206
|
-
|
|
6125
|
+
fs10.copyFileSync(path9.join(commandsSource, file), path9.join(targetDir, file));
|
|
5207
6126
|
}
|
|
5208
6127
|
}
|
|
5209
6128
|
return files.length > 0;
|
|
@@ -5213,8 +6132,8 @@ function installSlashCommands(sourceDir, targetDir) {
|
|
|
5213
6132
|
}
|
|
5214
6133
|
function getSkillVersion() {
|
|
5215
6134
|
try {
|
|
5216
|
-
const skillPath =
|
|
5217
|
-
const content =
|
|
6135
|
+
const skillPath = path9.join(getPackageSkillDir(), "SKILL.md");
|
|
6136
|
+
const content = fs10.readFileSync(skillPath, "utf-8");
|
|
5218
6137
|
const versionMatch = content.match(/version:\s*(\d+\.\d+\.\d+)/);
|
|
5219
6138
|
if (versionMatch) {
|
|
5220
6139
|
return versionMatch[1];
|
|
@@ -5222,16 +6141,16 @@ function getSkillVersion() {
|
|
|
5222
6141
|
} catch {
|
|
5223
6142
|
}
|
|
5224
6143
|
try {
|
|
5225
|
-
const pkgPath =
|
|
5226
|
-
const pkg = JSON.parse(
|
|
6144
|
+
const pkgPath = path9.join(__dirname, "..", "..", "package.json");
|
|
6145
|
+
const pkg = JSON.parse(fs10.readFileSync(pkgPath, "utf-8"));
|
|
5227
6146
|
return pkg.version;
|
|
5228
6147
|
} catch {
|
|
5229
6148
|
return "0.1.0";
|
|
5230
6149
|
}
|
|
5231
6150
|
}
|
|
5232
6151
|
function isSkillInstalled() {
|
|
5233
|
-
const skillPath =
|
|
5234
|
-
if (!
|
|
6152
|
+
const skillPath = path9.join(getReflyBaseSkillDir(), "SKILL.md");
|
|
6153
|
+
if (!fs10.existsSync(skillPath)) {
|
|
5235
6154
|
return { installed: false, upToDate: false };
|
|
5236
6155
|
}
|
|
5237
6156
|
const currentVersion = getSkillVersion();
|