@powerformer/refly-cli 0.1.23 → 0.1.25

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 CHANGED
@@ -989,8 +989,8 @@ var require_command = __commonJS({
989
989
  init_cjs_shims();
990
990
  var EventEmitter = require("events").EventEmitter;
991
991
  var childProcess2 = require("child_process");
992
- var path22 = require("path");
993
- var fs27 = require("fs");
992
+ var path25 = require("path");
993
+ var fs32 = require("fs");
994
994
  var process8 = require("process");
995
995
  var { Argument: Argument2, humanReadableArgName } = require_argument();
996
996
  var { CommanderError: CommanderError2 } = require_error();
@@ -1922,11 +1922,11 @@ Expecting one of '${allowedValues.join("', '")}'`);
1922
1922
  let launchWithNode = false;
1923
1923
  const sourceExt = [".js", ".ts", ".tsx", ".mjs", ".cjs"];
1924
1924
  function findFile(baseDir, baseName) {
1925
- const localBin = path22.resolve(baseDir, baseName);
1926
- if (fs27.existsSync(localBin)) return localBin;
1927
- if (sourceExt.includes(path22.extname(baseName))) return void 0;
1925
+ const localBin = path25.resolve(baseDir, baseName);
1926
+ if (fs32.existsSync(localBin)) return localBin;
1927
+ if (sourceExt.includes(path25.extname(baseName))) return void 0;
1928
1928
  const foundExt = sourceExt.find(
1929
- (ext) => fs27.existsSync(`${localBin}${ext}`)
1929
+ (ext) => fs32.existsSync(`${localBin}${ext}`)
1930
1930
  );
1931
1931
  if (foundExt) return `${localBin}${foundExt}`;
1932
1932
  return void 0;
@@ -1938,21 +1938,21 @@ Expecting one of '${allowedValues.join("', '")}'`);
1938
1938
  if (this._scriptPath) {
1939
1939
  let resolvedScriptPath;
1940
1940
  try {
1941
- resolvedScriptPath = fs27.realpathSync(this._scriptPath);
1941
+ resolvedScriptPath = fs32.realpathSync(this._scriptPath);
1942
1942
  } catch (err) {
1943
1943
  resolvedScriptPath = this._scriptPath;
1944
1944
  }
1945
- executableDir = path22.resolve(
1946
- path22.dirname(resolvedScriptPath),
1945
+ executableDir = path25.resolve(
1946
+ path25.dirname(resolvedScriptPath),
1947
1947
  executableDir
1948
1948
  );
1949
1949
  }
1950
1950
  if (executableDir) {
1951
1951
  let localFile = findFile(executableDir, executableFile);
1952
1952
  if (!localFile && !subcommand._executableFile && this._scriptPath) {
1953
- const legacyName = path22.basename(
1953
+ const legacyName = path25.basename(
1954
1954
  this._scriptPath,
1955
- path22.extname(this._scriptPath)
1955
+ path25.extname(this._scriptPath)
1956
1956
  );
1957
1957
  if (legacyName !== this._name) {
1958
1958
  localFile = findFile(
@@ -1963,7 +1963,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
1963
1963
  }
1964
1964
  executableFile = localFile || executableFile;
1965
1965
  }
1966
- launchWithNode = sourceExt.includes(path22.extname(executableFile));
1966
+ launchWithNode = sourceExt.includes(path25.extname(executableFile));
1967
1967
  let proc;
1968
1968
  if (process8.platform !== "win32") {
1969
1969
  if (launchWithNode) {
@@ -2803,7 +2803,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
2803
2803
  * @return {Command}
2804
2804
  */
2805
2805
  nameFromFilename(filename) {
2806
- this._name = path22.basename(filename, path22.extname(filename));
2806
+ this._name = path25.basename(filename, path25.extname(filename));
2807
2807
  return this;
2808
2808
  }
2809
2809
  /**
@@ -2817,9 +2817,9 @@ Expecting one of '${allowedValues.join("', '")}'`);
2817
2817
  * @param {string} [path]
2818
2818
  * @return {(string|null|Command)}
2819
2819
  */
2820
- executableDir(path23) {
2821
- if (path23 === void 0) return this._executableDir;
2822
- this._executableDir = path23;
2820
+ executableDir(path26) {
2821
+ if (path26 === void 0) return this._executableDir;
2822
+ this._executableDir = path26;
2823
2823
  return this;
2824
2824
  }
2825
2825
  /**
@@ -3260,17 +3260,865 @@ var init_logger = __esm({
3260
3260
  }
3261
3261
  });
3262
3262
 
3263
+ // src/platform/registry.ts
3264
+ function pathExists(p) {
3265
+ try {
3266
+ return fs4.existsSync(p);
3267
+ } catch {
3268
+ return false;
3269
+ }
3270
+ }
3271
+ function isValidAgentType(name) {
3272
+ return name in agents;
3273
+ }
3274
+ var fs4, path4, import_node_os, home, agents;
3275
+ var init_registry = __esm({
3276
+ "src/platform/registry.ts"() {
3277
+ "use strict";
3278
+ init_cjs_shims();
3279
+ fs4 = __toESM(require("fs"));
3280
+ path4 = __toESM(require("path"));
3281
+ import_node_os = require("os");
3282
+ home = (0, import_node_os.homedir)();
3283
+ agents = {
3284
+ // === SKILL.md Format (Symlink Compatible) ===
3285
+ "claude-code": {
3286
+ name: "claude-code",
3287
+ displayName: "Claude Code",
3288
+ format: "skill-md",
3289
+ skillsDir: ".claude/skills",
3290
+ globalSkillsDir: path4.join(home, ".claude", "skills"),
3291
+ detectInstalled: async () => pathExists(path4.join(home, ".claude"))
3292
+ },
3293
+ codex: {
3294
+ name: "codex",
3295
+ displayName: "Codex",
3296
+ format: "skill-md",
3297
+ skillsDir: ".codex/skills",
3298
+ globalSkillsDir: process.env.CODEX_HOME ? path4.join(process.env.CODEX_HOME, "skills") : path4.join(home, ".codex", "skills"),
3299
+ detectInstalled: async () => pathExists(path4.join(home, ".codex"))
3300
+ },
3301
+ antigravity: {
3302
+ name: "antigravity",
3303
+ displayName: "Antigravity",
3304
+ format: "skill-md",
3305
+ skillsDir: ".agent/skills",
3306
+ globalSkillsDir: path4.join(home, ".gemini", "antigravity", "skills"),
3307
+ detectInstalled: async () => pathExists(path4.join(home, ".gemini", "antigravity"))
3308
+ },
3309
+ "github-copilot": {
3310
+ name: "github-copilot",
3311
+ displayName: "GitHub Copilot",
3312
+ format: "skill-md",
3313
+ skillsDir: ".github/skills",
3314
+ globalSkillsDir: path4.join(home, ".copilot", "skills"),
3315
+ detectInstalled: async () => pathExists(path4.join(home, ".copilot"))
3316
+ },
3317
+ windsurf: {
3318
+ name: "windsurf",
3319
+ displayName: "Windsurf",
3320
+ format: "skill-md",
3321
+ skillsDir: ".windsurf/skills",
3322
+ globalSkillsDir: path4.join(home, ".codeium", "windsurf", "skills"),
3323
+ detectInstalled: async () => pathExists(path4.join(home, ".codeium", "windsurf"))
3324
+ },
3325
+ opencode: {
3326
+ name: "opencode",
3327
+ displayName: "OpenCode",
3328
+ format: "skill-md",
3329
+ skillsDir: ".opencode/skill",
3330
+ globalSkillsDir: path4.join(home, ".config", "opencode", "skill"),
3331
+ detectInstalled: async () => pathExists(path4.join(home, ".config", "opencode"))
3332
+ },
3333
+ moltbot: {
3334
+ name: "moltbot",
3335
+ displayName: "Moltbot",
3336
+ format: "skill-md",
3337
+ skillsDir: "skills",
3338
+ // <workspace>/skills
3339
+ globalSkillsDir: path4.join(home, ".clawdbot", "skills"),
3340
+ // Note: .clawdbot not .moltbot
3341
+ detectInstalled: async () => pathExists(path4.join(home, ".clawdbot"))
3342
+ },
3343
+ // === Different Formats (Require Conversion) ===
3344
+ cursor: {
3345
+ name: "cursor",
3346
+ displayName: "Cursor",
3347
+ format: "cursor-mdc",
3348
+ skillsDir: ".cursor/rules",
3349
+ globalSkillsDir: null,
3350
+ // Cursor has no global rules directory
3351
+ detectInstalled: async () => pathExists(path4.join(home, ".cursor")),
3352
+ fileExtension: ".mdc",
3353
+ skillsAsFiles: true
3354
+ },
3355
+ continue: {
3356
+ name: "continue",
3357
+ displayName: "Continue",
3358
+ format: "rules-md",
3359
+ skillsDir: ".continue/rules",
3360
+ globalSkillsDir: path4.join(home, ".continue", "rules"),
3361
+ detectInstalled: async () => pathExists(path4.join(home, ".continue")),
3362
+ fileExtension: ".md",
3363
+ skillsAsFiles: true
3364
+ },
3365
+ trae: {
3366
+ name: "trae",
3367
+ displayName: "Trae",
3368
+ format: "rules-md",
3369
+ skillsDir: ".trae/rules",
3370
+ globalSkillsDir: path4.join(home, ".trae", "rules"),
3371
+ detectInstalled: async () => pathExists(path4.join(home, ".trae")),
3372
+ fileExtension: ".md",
3373
+ skillsAsFiles: true
3374
+ },
3375
+ // === Unverified ===
3376
+ qoder: {
3377
+ name: "qoder",
3378
+ displayName: "Qoder",
3379
+ format: "unknown",
3380
+ skillsDir: ".qoder/skills",
3381
+ // Assumed, not verified
3382
+ globalSkillsDir: path4.join(home, ".qoder", "skills"),
3383
+ detectInstalled: async () => pathExists(path4.join(home, ".qoder"))
3384
+ }
3385
+ };
3386
+ }
3387
+ });
3388
+
3389
+ // src/platform/symlink-adapter.ts
3390
+ async function createSymlinkSafe(target, linkPath) {
3391
+ try {
3392
+ const linkDir = path5.dirname(linkPath);
3393
+ ensureDir(linkDir);
3394
+ if (fs5.existsSync(linkPath)) {
3395
+ const stat = fs5.lstatSync(linkPath);
3396
+ if (stat.isSymbolicLink()) {
3397
+ fs5.unlinkSync(linkPath);
3398
+ logger.debug(`Removed existing symlink: ${linkPath}`);
3399
+ } else if (stat.isDirectory()) {
3400
+ return {
3401
+ success: false,
3402
+ error: `Target path is a directory, not a symlink: ${linkPath}`
3403
+ };
3404
+ }
3405
+ }
3406
+ const symlinkType = (0, import_node_os2.platform)() === "win32" ? "junction" : "dir";
3407
+ fs5.symlinkSync(target, linkPath, symlinkType);
3408
+ logger.debug(`Created symlink: ${linkPath} -> ${target}`);
3409
+ return { success: true };
3410
+ } catch (err) {
3411
+ if (err.code === "ENOENT") {
3412
+ try {
3413
+ const symlinkType = (0, import_node_os2.platform)() === "win32" ? "junction" : "dir";
3414
+ fs5.symlinkSync(target, linkPath, symlinkType);
3415
+ logger.debug(`Created symlink: ${linkPath} -> ${target}`);
3416
+ return { success: true };
3417
+ } catch (innerErr) {
3418
+ return {
3419
+ success: false,
3420
+ error: innerErr.message
3421
+ };
3422
+ }
3423
+ }
3424
+ return {
3425
+ success: false,
3426
+ error: err.message
3427
+ };
3428
+ }
3429
+ }
3430
+ var fs5, path5, import_node_os2, SymlinkAdapter, symlinkAdapter;
3431
+ var init_symlink_adapter = __esm({
3432
+ "src/platform/symlink-adapter.ts"() {
3433
+ "use strict";
3434
+ init_cjs_shims();
3435
+ fs5 = __toESM(require("fs"));
3436
+ path5 = __toESM(require("path"));
3437
+ import_node_os2 = require("os");
3438
+ init_logger();
3439
+ init_paths();
3440
+ SymlinkAdapter = class {
3441
+ async deploy(skillName, sourcePath, agent, options) {
3442
+ const result = {
3443
+ success: false,
3444
+ agent: agent.name,
3445
+ skillName,
3446
+ deployedPath: null,
3447
+ sourcePath,
3448
+ isSymlink: true
3449
+ };
3450
+ let targetDir = null;
3451
+ if (options?.projectPath && agent.skillsDir) {
3452
+ targetDir = path5.join(options.projectPath, agent.skillsDir);
3453
+ } else {
3454
+ targetDir = agent.globalSkillsDir;
3455
+ }
3456
+ if (!targetDir) {
3457
+ result.error = `Agent ${agent.displayName} has no skills directory configured`;
3458
+ return result;
3459
+ }
3460
+ if (!fs5.existsSync(sourcePath)) {
3461
+ result.error = `Source skill directory does not exist: ${sourcePath}`;
3462
+ return result;
3463
+ }
3464
+ const linkPath = path5.join(targetDir, skillName);
3465
+ result.deployedPath = linkPath;
3466
+ if (fs5.existsSync(linkPath) && !options?.force) {
3467
+ const stat = fs5.lstatSync(linkPath);
3468
+ if (stat.isSymbolicLink()) {
3469
+ const existingTarget = fs5.readlinkSync(linkPath);
3470
+ const resolvedTarget = path5.resolve(path5.dirname(linkPath), existingTarget);
3471
+ if (resolvedTarget === sourcePath) {
3472
+ result.success = true;
3473
+ return result;
3474
+ }
3475
+ }
3476
+ result.error = `Skill already exists at ${linkPath}. Use --force to overwrite.`;
3477
+ return result;
3478
+ }
3479
+ const symlinkResult = await createSymlinkSafe(sourcePath, linkPath);
3480
+ if (!symlinkResult.success) {
3481
+ result.error = symlinkResult.error;
3482
+ return result;
3483
+ }
3484
+ result.success = true;
3485
+ logger.info(`Deployed ${skillName} to ${agent.displayName}: ${linkPath} -> ${sourcePath}`);
3486
+ return result;
3487
+ }
3488
+ async remove(skillName, agent, options) {
3489
+ const result = {
3490
+ success: false,
3491
+ agent: agent.name,
3492
+ skillName,
3493
+ removedPath: null
3494
+ };
3495
+ let targetDir = null;
3496
+ if (options?.projectPath && agent.skillsDir) {
3497
+ targetDir = path5.join(options.projectPath, agent.skillsDir);
3498
+ } else {
3499
+ targetDir = agent.globalSkillsDir;
3500
+ }
3501
+ if (!targetDir) {
3502
+ result.error = `Agent ${agent.displayName} has no skills directory configured`;
3503
+ return result;
3504
+ }
3505
+ const linkPath = path5.join(targetDir, skillName);
3506
+ result.removedPath = linkPath;
3507
+ try {
3508
+ if (!fs5.existsSync(linkPath)) {
3509
+ result.success = true;
3510
+ return result;
3511
+ }
3512
+ const stat = fs5.lstatSync(linkPath);
3513
+ if (!stat.isSymbolicLink()) {
3514
+ result.error = `Path is not a symlink: ${linkPath}`;
3515
+ return result;
3516
+ }
3517
+ fs5.unlinkSync(linkPath);
3518
+ result.success = true;
3519
+ logger.info(`Removed ${skillName} from ${agent.displayName}: ${linkPath}`);
3520
+ } catch (err) {
3521
+ result.error = err.message;
3522
+ }
3523
+ return result;
3524
+ }
3525
+ async list(agent, options) {
3526
+ const results = [];
3527
+ let targetDir = null;
3528
+ if (options?.projectPath && agent.skillsDir) {
3529
+ targetDir = path5.join(options.projectPath, agent.skillsDir);
3530
+ } else {
3531
+ targetDir = agent.globalSkillsDir;
3532
+ }
3533
+ if (!targetDir || !fs5.existsSync(targetDir)) {
3534
+ return results;
3535
+ }
3536
+ try {
3537
+ const entries = fs5.readdirSync(targetDir, { withFileTypes: true });
3538
+ for (const entry of entries) {
3539
+ const fullPath = path5.join(targetDir, entry.name);
3540
+ try {
3541
+ const stat = fs5.lstatSync(fullPath);
3542
+ if (stat.isSymbolicLink()) {
3543
+ const target = fs5.readlinkSync(fullPath);
3544
+ const resolvedTarget = path5.resolve(path5.dirname(fullPath), target);
3545
+ const isValid2 = fs5.existsSync(resolvedTarget);
3546
+ results.push({
3547
+ name: entry.name,
3548
+ agent: agent.name,
3549
+ path: fullPath,
3550
+ isValid: isValid2,
3551
+ target: resolvedTarget,
3552
+ isSymlink: true
3553
+ });
3554
+ } else if (stat.isDirectory()) {
3555
+ const skillMdPath = path5.join(fullPath, "SKILL.md");
3556
+ results.push({
3557
+ name: entry.name,
3558
+ agent: agent.name,
3559
+ path: fullPath,
3560
+ isValid: fs5.existsSync(skillMdPath),
3561
+ isSymlink: false
3562
+ });
3563
+ }
3564
+ } catch {
3565
+ }
3566
+ }
3567
+ } catch {
3568
+ }
3569
+ return results;
3570
+ }
3571
+ async isDeployed(skillName, agent, options) {
3572
+ let targetDir = null;
3573
+ if (options?.projectPath && agent.skillsDir) {
3574
+ targetDir = path5.join(options.projectPath, agent.skillsDir);
3575
+ } else {
3576
+ targetDir = agent.globalSkillsDir;
3577
+ }
3578
+ if (!targetDir) {
3579
+ return { deployed: false, valid: false };
3580
+ }
3581
+ const linkPath = path5.join(targetDir, skillName);
3582
+ try {
3583
+ if (!fs5.existsSync(linkPath)) {
3584
+ return { deployed: false, valid: false };
3585
+ }
3586
+ const stat = fs5.lstatSync(linkPath);
3587
+ if (!stat.isSymbolicLink()) {
3588
+ const skillMdPath = path5.join(linkPath, "SKILL.md");
3589
+ return {
3590
+ deployed: true,
3591
+ valid: fs5.existsSync(skillMdPath),
3592
+ path: linkPath
3593
+ };
3594
+ }
3595
+ const target = fs5.readlinkSync(linkPath);
3596
+ const resolvedTarget = path5.resolve(path5.dirname(linkPath), target);
3597
+ const isValid2 = fs5.existsSync(resolvedTarget);
3598
+ return {
3599
+ deployed: true,
3600
+ valid: isValid2,
3601
+ path: linkPath
3602
+ };
3603
+ } catch {
3604
+ return { deployed: false, valid: false };
3605
+ }
3606
+ }
3607
+ };
3608
+ symlinkAdapter = new SymlinkAdapter();
3609
+ }
3610
+ });
3611
+
3612
+ // src/platform/format-converter.ts
3613
+ function convertToMdc(skill) {
3614
+ const lines = [];
3615
+ lines.push("---");
3616
+ lines.push(`description: "${skill.description.replace(/"/g, '\\"')}"`);
3617
+ lines.push("globs:");
3618
+ lines.push("alwaysApply: false");
3619
+ lines.push("---");
3620
+ lines.push("");
3621
+ lines.push(`# ${skill.displayName || formatSkillName(skill.name)}`);
3622
+ lines.push("");
3623
+ lines.push(skill.description);
3624
+ lines.push("");
3625
+ lines.push(skill.body);
3626
+ if (skill.skillId || skill.workflowId) {
3627
+ lines.push("");
3628
+ lines.push("---");
3629
+ lines.push("");
3630
+ lines.push("## Refly Skill");
3631
+ lines.push("");
3632
+ if (skill.skillId) {
3633
+ lines.push(`- **Skill ID**: ${skill.skillId}`);
3634
+ }
3635
+ if (skill.workflowId) {
3636
+ lines.push(`- **Workflow ID**: ${skill.workflowId}`);
3637
+ }
3638
+ if (skill.installationId) {
3639
+ lines.push(`- **Installation ID**: ${skill.installationId}`);
3640
+ }
3641
+ const runId = skill.installationId || skill.workflowId || skill.name;
3642
+ lines.push(`- **Run**: \`refly skill run ${runId}\``);
3643
+ }
3644
+ return lines.join("\n");
3645
+ }
3646
+ function convertToRules(skill) {
3647
+ const lines = [];
3648
+ lines.push(`# ${skill.displayName || formatSkillName(skill.name)}`);
3649
+ lines.push("");
3650
+ lines.push(`> ${skill.description}`);
3651
+ lines.push("");
3652
+ if (skill.triggers && skill.triggers.length > 0) {
3653
+ lines.push("## Triggers");
3654
+ lines.push("");
3655
+ for (const trigger of skill.triggers) {
3656
+ lines.push(`- ${trigger}`);
3657
+ }
3658
+ lines.push("");
3659
+ }
3660
+ lines.push(skill.body);
3661
+ if (skill.skillId || skill.workflowId) {
3662
+ lines.push("");
3663
+ lines.push("---");
3664
+ lines.push("");
3665
+ lines.push("## Refly Skill");
3666
+ lines.push("");
3667
+ if (skill.skillId) {
3668
+ lines.push(`- **Skill ID**: ${skill.skillId}`);
3669
+ }
3670
+ if (skill.workflowId) {
3671
+ lines.push(`- **Workflow ID**: ${skill.workflowId}`);
3672
+ }
3673
+ if (skill.installationId) {
3674
+ lines.push(`- **Installation ID**: ${skill.installationId}`);
3675
+ }
3676
+ const runId = skill.installationId || skill.workflowId || skill.name;
3677
+ lines.push(`- **Run**: \`refly skill run ${runId}\``);
3678
+ }
3679
+ return lines.join("\n");
3680
+ }
3681
+ function formatSkillName(name) {
3682
+ return name.split("-").map((w) => w.charAt(0).toUpperCase() + w.slice(1)).join(" ");
3683
+ }
3684
+ function parseSkillMdLenient(content) {
3685
+ const frontmatterRegex = /^---\n([\s\S]*?)\n---\n?([\s\S]*)$/;
3686
+ const match = content.match(frontmatterRegex);
3687
+ if (!match) {
3688
+ return null;
3689
+ }
3690
+ const [, frontmatterStr, body] = match;
3691
+ const meta = {};
3692
+ const lines = frontmatterStr.split("\n");
3693
+ let currentKey = null;
3694
+ let currentArray = [];
3695
+ for (const line of lines) {
3696
+ const trimmed = line.trim();
3697
+ if (trimmed.startsWith("- ")) {
3698
+ if (currentKey) {
3699
+ currentArray.push(trimmed.slice(2).trim());
3700
+ }
3701
+ continue;
3702
+ }
3703
+ if (currentKey && currentArray.length > 0) {
3704
+ meta[currentKey] = currentArray;
3705
+ currentArray = [];
3706
+ currentKey = null;
3707
+ }
3708
+ const colonIndex = trimmed.indexOf(":");
3709
+ if (colonIndex > 0) {
3710
+ const key = trimmed.slice(0, colonIndex).trim();
3711
+ const value = trimmed.slice(colonIndex + 1).trim();
3712
+ if (value === "") {
3713
+ currentKey = key;
3714
+ currentArray = [];
3715
+ } else {
3716
+ meta[key] = value;
3717
+ }
3718
+ }
3719
+ }
3720
+ if (currentKey && currentArray.length > 0) {
3721
+ meta[currentKey] = currentArray;
3722
+ }
3723
+ if (!meta.name || !meta.description) {
3724
+ return null;
3725
+ }
3726
+ return {
3727
+ name: meta.name,
3728
+ displayName: meta.displayName,
3729
+ description: meta.description,
3730
+ skillId: meta.skillId,
3731
+ workflowId: meta.workflowId,
3732
+ installationId: meta.installationId,
3733
+ triggers: meta.triggers,
3734
+ tags: meta.tags,
3735
+ version: meta.version,
3736
+ body: body.trim()
3737
+ };
3738
+ }
3739
+ function readSkillMd(sourcePath) {
3740
+ const skillMdPath = path6.join(sourcePath, "SKILL.md");
3741
+ if (!fs6.existsSync(skillMdPath)) {
3742
+ return null;
3743
+ }
3744
+ try {
3745
+ const content = fs6.readFileSync(skillMdPath, "utf-8");
3746
+ return parseSkillMdLenient(content);
3747
+ } catch {
3748
+ return null;
3749
+ }
3750
+ }
3751
+ var fs6, path6, FormatConverterAdapter, formatConverterAdapter;
3752
+ var init_format_converter = __esm({
3753
+ "src/platform/format-converter.ts"() {
3754
+ "use strict";
3755
+ init_cjs_shims();
3756
+ fs6 = __toESM(require("fs"));
3757
+ path6 = __toESM(require("path"));
3758
+ init_logger();
3759
+ init_paths();
3760
+ FormatConverterAdapter = class {
3761
+ async deploy(skillName, sourcePath, agent, options) {
3762
+ const result = {
3763
+ success: false,
3764
+ agent: agent.name,
3765
+ skillName,
3766
+ deployedPath: null,
3767
+ sourcePath,
3768
+ isSymlink: false
3769
+ // We generate files, not symlinks
3770
+ };
3771
+ let targetDir = null;
3772
+ if (options?.projectPath && agent.skillsDir) {
3773
+ targetDir = path6.join(options.projectPath, agent.skillsDir);
3774
+ } else {
3775
+ targetDir = agent.globalSkillsDir;
3776
+ }
3777
+ if (!targetDir) {
3778
+ result.success = true;
3779
+ logger.debug(`Skipping ${skillName} for ${agent.displayName}: no global skills directory`);
3780
+ return result;
3781
+ }
3782
+ const skill = readSkillMd(sourcePath);
3783
+ if (!skill) {
3784
+ result.error = `Failed to read SKILL.md from ${sourcePath}`;
3785
+ return result;
3786
+ }
3787
+ const extension = agent.fileExtension || ".md";
3788
+ const filePath = path6.join(targetDir, `${skillName}${extension}`);
3789
+ result.deployedPath = filePath;
3790
+ if (fs6.existsSync(filePath) && !options?.force) {
3791
+ result.error = `Skill already exists at ${filePath}. Use --force to overwrite.`;
3792
+ return result;
3793
+ }
3794
+ let content;
3795
+ switch (agent.format) {
3796
+ case "cursor-mdc":
3797
+ content = convertToMdc(skill);
3798
+ break;
3799
+ case "rules-md":
3800
+ content = convertToRules(skill);
3801
+ break;
3802
+ default:
3803
+ result.error = `Unsupported format: ${agent.format}`;
3804
+ return result;
3805
+ }
3806
+ try {
3807
+ ensureDir(targetDir);
3808
+ fs6.writeFileSync(filePath, content, { encoding: "utf-8", mode: 420 });
3809
+ result.success = true;
3810
+ logger.info(`Deployed ${skillName} to ${agent.displayName}: ${filePath}`);
3811
+ } catch (err) {
3812
+ result.error = err.message;
3813
+ }
3814
+ return result;
3815
+ }
3816
+ async remove(skillName, agent, options) {
3817
+ const result = {
3818
+ success: false,
3819
+ agent: agent.name,
3820
+ skillName,
3821
+ removedPath: null
3822
+ };
3823
+ let targetDir = null;
3824
+ if (options?.projectPath && agent.skillsDir) {
3825
+ targetDir = path6.join(options.projectPath, agent.skillsDir);
3826
+ } else {
3827
+ targetDir = agent.globalSkillsDir;
3828
+ }
3829
+ if (!targetDir) {
3830
+ result.success = true;
3831
+ logger.debug(
3832
+ `Skipping ${skillName} removal for ${agent.displayName}: no global skills directory`
3833
+ );
3834
+ return result;
3835
+ }
3836
+ const extension = agent.fileExtension || ".md";
3837
+ const filePath = path6.join(targetDir, `${skillName}${extension}`);
3838
+ result.removedPath = filePath;
3839
+ try {
3840
+ if (!fs6.existsSync(filePath)) {
3841
+ result.success = true;
3842
+ return result;
3843
+ }
3844
+ fs6.unlinkSync(filePath);
3845
+ result.success = true;
3846
+ logger.info(`Removed ${skillName} from ${agent.displayName}: ${filePath}`);
3847
+ } catch (err) {
3848
+ result.error = err.message;
3849
+ }
3850
+ return result;
3851
+ }
3852
+ async list(agent, options) {
3853
+ const results = [];
3854
+ let targetDir = null;
3855
+ if (options?.projectPath && agent.skillsDir) {
3856
+ targetDir = path6.join(options.projectPath, agent.skillsDir);
3857
+ } else {
3858
+ targetDir = agent.globalSkillsDir;
3859
+ }
3860
+ if (!targetDir || !fs6.existsSync(targetDir)) {
3861
+ return results;
3862
+ }
3863
+ const extension = agent.fileExtension || ".md";
3864
+ try {
3865
+ const entries = fs6.readdirSync(targetDir, { withFileTypes: true });
3866
+ for (const entry of entries) {
3867
+ if (entry.isFile() && entry.name.endsWith(extension)) {
3868
+ const fullPath = path6.join(targetDir, entry.name);
3869
+ const skillName = entry.name.slice(0, -extension.length);
3870
+ let isReflySkill = false;
3871
+ try {
3872
+ const content = fs6.readFileSync(fullPath, "utf-8");
3873
+ isReflySkill = content.includes("## Refly Skill") || content.includes("Skill ID:");
3874
+ } catch {
3875
+ }
3876
+ results.push({
3877
+ name: skillName,
3878
+ agent: agent.name,
3879
+ path: fullPath,
3880
+ isValid: isReflySkill,
3881
+ isSymlink: false
3882
+ });
3883
+ }
3884
+ }
3885
+ } catch {
3886
+ }
3887
+ return results;
3888
+ }
3889
+ async isDeployed(skillName, agent, options) {
3890
+ let targetDir = null;
3891
+ if (options?.projectPath && agent.skillsDir) {
3892
+ targetDir = path6.join(options.projectPath, agent.skillsDir);
3893
+ } else {
3894
+ targetDir = agent.globalSkillsDir;
3895
+ }
3896
+ if (!targetDir) {
3897
+ return { deployed: false, valid: false };
3898
+ }
3899
+ const extension = agent.fileExtension || ".md";
3900
+ const filePath = path6.join(targetDir, `${skillName}${extension}`);
3901
+ if (!fs6.existsSync(filePath)) {
3902
+ return { deployed: false, valid: false };
3903
+ }
3904
+ let isValid2 = false;
3905
+ try {
3906
+ const content = fs6.readFileSync(filePath, "utf-8");
3907
+ isValid2 = content.includes("## Refly Skill") || content.includes("Skill ID:");
3908
+ } catch {
3909
+ }
3910
+ return {
3911
+ deployed: true,
3912
+ valid: isValid2,
3913
+ path: filePath
3914
+ };
3915
+ }
3916
+ };
3917
+ formatConverterAdapter = new FormatConverterAdapter();
3918
+ }
3919
+ });
3920
+
3921
+ // src/platform/manager.ts
3922
+ function getAdapter(agent) {
3923
+ switch (agent.format) {
3924
+ case "skill-md":
3925
+ return symlinkAdapter;
3926
+ case "cursor-mdc":
3927
+ case "rules-md":
3928
+ return formatConverterAdapter;
3929
+ default:
3930
+ return symlinkAdapter;
3931
+ }
3932
+ }
3933
+ async function detectInstalledAgents() {
3934
+ const installed = [];
3935
+ for (const agent of Object.values(agents)) {
3936
+ try {
3937
+ const isInstalled = await agent.detectInstalled();
3938
+ if (isInstalled) {
3939
+ installed.push(agent);
3940
+ }
3941
+ } catch (err) {
3942
+ logger.debug(`Error detecting ${agent.displayName}: ${err.message}`);
3943
+ }
3944
+ }
3945
+ return installed;
3946
+ }
3947
+ async function getDeployableAgents(options) {
3948
+ const installed = await detectInstalledAgents();
3949
+ if (options?.includeUnknown) {
3950
+ return installed;
3951
+ }
3952
+ return installed.filter((agent) => agent.format !== "unknown");
3953
+ }
3954
+ async function deploySkillToAllPlatforms(skillName, options) {
3955
+ const sourcePath = skillName === "refly" ? getReflyBaseSkillDir() : getReflyDomainSkillDir(skillName);
3956
+ const result = {
3957
+ skillName,
3958
+ sourcePath,
3959
+ results: /* @__PURE__ */ new Map(),
3960
+ successCount: 0,
3961
+ failureCount: 0
3962
+ };
3963
+ if (!fs7.existsSync(sourcePath)) {
3964
+ logger.error(`Source skill directory does not exist: ${sourcePath}`);
3965
+ return result;
3966
+ }
3967
+ let targetAgents;
3968
+ if (options?.agents && options.agents.length > 0) {
3969
+ targetAgents = options.agents.map((name) => agents[name]).filter(Boolean);
3970
+ } else {
3971
+ targetAgents = await getDeployableAgents();
3972
+ }
3973
+ for (const agent of targetAgents) {
3974
+ const adapter = getAdapter(agent);
3975
+ try {
3976
+ const deployResult = await adapter.deploy(skillName, sourcePath, agent, {
3977
+ force: options?.force,
3978
+ projectPath: options?.projectPath
3979
+ });
3980
+ result.results.set(agent.name, deployResult);
3981
+ if (deployResult.success) {
3982
+ result.successCount++;
3983
+ } else {
3984
+ result.failureCount++;
3985
+ }
3986
+ } catch (err) {
3987
+ result.results.set(agent.name, {
3988
+ success: false,
3989
+ agent: agent.name,
3990
+ skillName,
3991
+ deployedPath: null,
3992
+ sourcePath,
3993
+ isSymlink: false,
3994
+ error: err.message
3995
+ });
3996
+ result.failureCount++;
3997
+ }
3998
+ }
3999
+ return result;
4000
+ }
4001
+ async function removeSkillFromAllPlatforms(skillName, options) {
4002
+ const result = {
4003
+ skillName,
4004
+ results: /* @__PURE__ */ new Map(),
4005
+ successCount: 0,
4006
+ failureCount: 0
4007
+ };
4008
+ let targetAgents;
4009
+ if (options?.agents && options.agents.length > 0) {
4010
+ targetAgents = options.agents.map((name) => agents[name]).filter(Boolean);
4011
+ } else {
4012
+ targetAgents = await getDeployableAgents();
4013
+ }
4014
+ for (const agent of targetAgents) {
4015
+ const adapter = getAdapter(agent);
4016
+ try {
4017
+ const removeResult = await adapter.remove(skillName, agent, {
4018
+ projectPath: options?.projectPath
4019
+ });
4020
+ result.results.set(agent.name, removeResult);
4021
+ if (removeResult.success) {
4022
+ result.successCount++;
4023
+ } else {
4024
+ result.failureCount++;
4025
+ }
4026
+ } catch (err) {
4027
+ result.results.set(agent.name, {
4028
+ success: false,
4029
+ agent: agent.name,
4030
+ skillName,
4031
+ removedPath: null,
4032
+ error: err.message
4033
+ });
4034
+ result.failureCount++;
4035
+ }
4036
+ }
4037
+ return result;
4038
+ }
4039
+ async function listAllDeployedSkills(options) {
4040
+ const result = /* @__PURE__ */ new Map();
4041
+ let targetAgents;
4042
+ if (options?.agents && options.agents.length > 0) {
4043
+ targetAgents = options.agents.map((name) => agents[name]).filter(Boolean);
4044
+ } else {
4045
+ targetAgents = await getDeployableAgents();
4046
+ }
4047
+ for (const agent of targetAgents) {
4048
+ const adapter = getAdapter(agent);
4049
+ try {
4050
+ const skills = await adapter.list(agent, {
4051
+ projectPath: options?.projectPath
4052
+ });
4053
+ result.set(agent.name, skills);
4054
+ } catch (err) {
4055
+ logger.debug(`Error listing skills for ${agent.displayName}: ${err.message}`);
4056
+ result.set(agent.name, []);
4057
+ }
4058
+ }
4059
+ return result;
4060
+ }
4061
+ async function syncSkillToAllPlatforms(skillName, options) {
4062
+ const needsSync = /* @__PURE__ */ new Map();
4063
+ const synced = /* @__PURE__ */ new Map();
4064
+ const sourcePath = skillName === "refly" ? getReflyBaseSkillDir() : getReflyDomainSkillDir(skillName);
4065
+ let targetAgents;
4066
+ if (options?.agents && options.agents.length > 0) {
4067
+ targetAgents = options.agents.map((name) => agents[name]).filter(Boolean);
4068
+ } else {
4069
+ targetAgents = await getDeployableAgents();
4070
+ }
4071
+ for (const agent of targetAgents) {
4072
+ const adapter = getAdapter(agent);
4073
+ try {
4074
+ const status = await adapter.isDeployed(skillName, agent, {
4075
+ projectPath: options?.projectPath
4076
+ });
4077
+ needsSync.set(agent.name, status);
4078
+ if ((!status.deployed || !status.valid) && !options?.dryRun) {
4079
+ const deployResult = await adapter.deploy(skillName, sourcePath, agent, {
4080
+ force: true,
4081
+ // Force to repair
4082
+ projectPath: options?.projectPath
4083
+ });
4084
+ synced.set(agent.name, deployResult);
4085
+ }
4086
+ } catch (err) {
4087
+ logger.debug(
4088
+ `Error checking/syncing ${skillName} for ${agent.displayName}: ${err.message}`
4089
+ );
4090
+ }
4091
+ }
4092
+ return { needsSync, synced };
4093
+ }
4094
+ var fs7;
4095
+ var init_manager = __esm({
4096
+ "src/platform/manager.ts"() {
4097
+ "use strict";
4098
+ init_cjs_shims();
4099
+ fs7 = __toESM(require("fs"));
4100
+ init_registry();
4101
+ init_symlink_adapter();
4102
+ init_format_converter();
4103
+ init_paths();
4104
+ init_logger();
4105
+ }
4106
+ });
4107
+
3263
4108
  // src/skill/symlink.ts
3264
4109
  var symlink_exports = {};
3265
4110
  __export(symlink_exports, {
4111
+ createMultiPlatformSkill: () => createMultiPlatformSkill,
3266
4112
  createReflySkillWithSymlink: () => createReflySkillWithSymlink,
3267
4113
  createSkillSymlink: () => createSkillSymlink,
3268
4114
  deleteDomainSkillWithSymlink: () => deleteDomainSkillWithSymlink,
3269
4115
  generateReflySkillMd: () => generateReflySkillMd,
3270
4116
  initializeBaseSkillSymlink: () => initializeBaseSkillSymlink,
3271
4117
  isSkillSymlinkValid: () => isSkillSymlinkValid,
4118
+ listMultiPlatformSkills: () => listMultiPlatformSkills,
3272
4119
  listSkillSymlinks: () => listSkillSymlinks,
3273
4120
  parseReflySkillMd: () => parseReflySkillMd,
4121
+ removeMultiPlatformSkill: () => removeMultiPlatformSkill,
3274
4122
  removeSkillSymlink: () => removeSkillSymlink
3275
4123
  });
3276
4124
  function createSkillSymlink(skillName) {
@@ -3279,7 +4127,7 @@ function createSkillSymlink(skillName) {
3279
4127
  try {
3280
4128
  ensureReflySkillsDir();
3281
4129
  ensureClaudeSkillsDir();
3282
- if (!fs4.existsSync(reflyPath)) {
4130
+ if (!fs8.existsSync(reflyPath)) {
3283
4131
  return {
3284
4132
  success: false,
3285
4133
  skillName,
@@ -3288,10 +4136,10 @@ function createSkillSymlink(skillName) {
3288
4136
  error: `Source skill directory does not exist: ${reflyPath}`
3289
4137
  };
3290
4138
  }
3291
- if (fs4.existsSync(claudePath) || fs4.lstatSync(claudePath).isSymbolicLink()) {
3292
- const stat = fs4.lstatSync(claudePath);
4139
+ if (fs8.existsSync(claudePath) || fs8.lstatSync(claudePath).isSymbolicLink()) {
4140
+ const stat = fs8.lstatSync(claudePath);
3293
4141
  if (stat.isSymbolicLink()) {
3294
- fs4.unlinkSync(claudePath);
4142
+ fs8.unlinkSync(claudePath);
3295
4143
  logger.debug(`Removed existing symlink: ${claudePath}`);
3296
4144
  } else if (stat.isDirectory()) {
3297
4145
  logger.warn(`Cannot create symlink: ${claudePath} is a directory, not a symlink`);
@@ -3304,7 +4152,7 @@ function createSkillSymlink(skillName) {
3304
4152
  };
3305
4153
  }
3306
4154
  }
3307
- fs4.symlinkSync(reflyPath, claudePath, "dir");
4155
+ fs8.symlinkSync(reflyPath, claudePath, "dir");
3308
4156
  logger.info(`Created symlink: ${claudePath} -> ${reflyPath}`);
3309
4157
  return {
3310
4158
  success: true,
@@ -3315,7 +4163,7 @@ function createSkillSymlink(skillName) {
3315
4163
  } catch (err) {
3316
4164
  if (err.code === "ENOENT") {
3317
4165
  try {
3318
- fs4.symlinkSync(reflyPath, claudePath, "dir");
4166
+ fs8.symlinkSync(reflyPath, claudePath, "dir");
3319
4167
  logger.info(`Created symlink: ${claudePath} -> ${reflyPath}`);
3320
4168
  return {
3321
4169
  success: true,
@@ -3345,16 +4193,16 @@ function createSkillSymlink(skillName) {
3345
4193
  function removeSkillSymlink(skillName) {
3346
4194
  const claudePath = getClaudeSkillSymlinkPath(skillName);
3347
4195
  try {
3348
- if (!fs4.existsSync(claudePath)) {
4196
+ if (!fs8.existsSync(claudePath)) {
3349
4197
  logger.debug(`Symlink not found: ${claudePath}`);
3350
4198
  return false;
3351
4199
  }
3352
- const stat = fs4.lstatSync(claudePath);
4200
+ const stat = fs8.lstatSync(claudePath);
3353
4201
  if (!stat.isSymbolicLink()) {
3354
4202
  logger.warn(`Not a symlink: ${claudePath}`);
3355
4203
  return false;
3356
4204
  }
3357
- fs4.unlinkSync(claudePath);
4205
+ fs8.unlinkSync(claudePath);
3358
4206
  logger.info(`Removed symlink: ${claudePath}`);
3359
4207
  return true;
3360
4208
  } catch (err) {
@@ -3366,16 +4214,16 @@ function isSkillSymlinkValid(skillName) {
3366
4214
  const claudePath = getClaudeSkillSymlinkPath(skillName);
3367
4215
  const expectedTarget = skillName === "refly" ? getReflyBaseSkillDir() : getReflyDomainSkillDir(skillName);
3368
4216
  try {
3369
- if (!fs4.existsSync(claudePath)) {
4217
+ if (!fs8.existsSync(claudePath)) {
3370
4218
  return { exists: false, isSymlink: false, isValid: false };
3371
4219
  }
3372
- const stat = fs4.lstatSync(claudePath);
4220
+ const stat = fs8.lstatSync(claudePath);
3373
4221
  if (!stat.isSymbolicLink()) {
3374
4222
  return { exists: true, isSymlink: false, isValid: false };
3375
4223
  }
3376
- const target = fs4.readlinkSync(claudePath);
3377
- const resolvedTarget = path4.resolve(path4.dirname(claudePath), target);
3378
- const isValid2 = resolvedTarget === expectedTarget && fs4.existsSync(resolvedTarget);
4224
+ const target = fs8.readlinkSync(claudePath);
4225
+ const resolvedTarget = path7.resolve(path7.dirname(claudePath), target);
4226
+ const isValid2 = resolvedTarget === expectedTarget && fs8.existsSync(resolvedTarget);
3379
4227
  return {
3380
4228
  exists: true,
3381
4229
  isSymlink: true,
@@ -3389,17 +4237,17 @@ function isSkillSymlinkValid(skillName) {
3389
4237
  function initializeBaseSkillSymlink() {
3390
4238
  const baseDir = getReflyBaseSkillDir();
3391
4239
  ensureDir(baseDir);
3392
- ensureDir(path4.join(baseDir, "rules"));
4240
+ ensureDir(path7.join(baseDir, "rules"));
3393
4241
  return createSkillSymlink("refly");
3394
4242
  }
3395
4243
  function createReflySkillWithSymlink(skillName, skillMdContent, options) {
3396
4244
  const skillDir = getReflyDomainSkillDir(skillName);
3397
4245
  try {
3398
4246
  ensureReflySkillsDir();
3399
- if (fs4.existsSync(skillDir)) {
4247
+ if (fs8.existsSync(skillDir)) {
3400
4248
  if (options?.force) {
3401
- const skillMdPath2 = path4.join(skillDir, "SKILL.md");
3402
- fs4.writeFileSync(skillMdPath2, skillMdContent, { encoding: "utf-8", mode: 420 });
4249
+ const skillMdPath2 = path7.join(skillDir, "SKILL.md");
4250
+ fs8.writeFileSync(skillMdPath2, skillMdContent, { encoding: "utf-8", mode: 420 });
3403
4251
  logger.debug(`Updated SKILL.md (force): ${skillMdPath2}`);
3404
4252
  return createSkillSymlink(skillName);
3405
4253
  }
@@ -3411,9 +4259,9 @@ function createReflySkillWithSymlink(skillName, skillMdContent, options) {
3411
4259
  error: `Skill directory already exists: ${skillDir}`
3412
4260
  };
3413
4261
  }
3414
- fs4.mkdirSync(skillDir, { recursive: true, mode: 493 });
3415
- const skillMdPath = path4.join(skillDir, "SKILL.md");
3416
- fs4.writeFileSync(skillMdPath, skillMdContent, { encoding: "utf-8", mode: 420 });
4262
+ fs8.mkdirSync(skillDir, { recursive: true, mode: 493 });
4263
+ const skillMdPath = path7.join(skillDir, "SKILL.md");
4264
+ fs8.writeFileSync(skillMdPath, skillMdContent, { encoding: "utf-8", mode: 420 });
3417
4265
  logger.debug(`Created SKILL.md: ${skillMdPath}`);
3418
4266
  return createSkillSymlink(skillName);
3419
4267
  } catch (err) {
@@ -3431,8 +4279,8 @@ function deleteDomainSkillWithSymlink(skillName) {
3431
4279
  const skillDir = getReflyDomainSkillDir(skillName);
3432
4280
  let directoryRemoved = false;
3433
4281
  try {
3434
- if (fs4.existsSync(skillDir)) {
3435
- fs4.rmSync(skillDir, { recursive: true, force: true });
4282
+ if (fs8.existsSync(skillDir)) {
4283
+ fs8.rmSync(skillDir, { recursive: true, force: true });
3436
4284
  directoryRemoved = true;
3437
4285
  logger.info(`Removed skill directory: ${skillDir}`);
3438
4286
  }
@@ -3444,19 +4292,19 @@ function deleteDomainSkillWithSymlink(skillName) {
3444
4292
  function listSkillSymlinks() {
3445
4293
  const claudeSkillsDir = getClaudeSkillsDir();
3446
4294
  const results = [];
3447
- if (!fs4.existsSync(claudeSkillsDir)) {
4295
+ if (!fs8.existsSync(claudeSkillsDir)) {
3448
4296
  return results;
3449
4297
  }
3450
4298
  try {
3451
- const entries = fs4.readdirSync(claudeSkillsDir, { withFileTypes: true });
4299
+ const entries = fs8.readdirSync(claudeSkillsDir, { withFileTypes: true });
3452
4300
  for (const entry of entries) {
3453
- const fullPath = path4.join(claudeSkillsDir, entry.name);
4301
+ const fullPath = path7.join(claudeSkillsDir, entry.name);
3454
4302
  try {
3455
- const stat = fs4.lstatSync(fullPath);
4303
+ const stat = fs8.lstatSync(fullPath);
3456
4304
  if (stat.isSymbolicLink()) {
3457
- const target = fs4.readlinkSync(fullPath);
3458
- const resolvedTarget = path4.resolve(path4.dirname(fullPath), target);
3459
- const isValid2 = fs4.existsSync(resolvedTarget);
4305
+ const target = fs8.readlinkSync(fullPath);
4306
+ const resolvedTarget = path7.resolve(path7.dirname(fullPath), target);
4307
+ const isValid2 = fs8.existsSync(resolvedTarget);
3460
4308
  results.push({
3461
4309
  name: entry.name,
3462
4310
  claudePath: fullPath,
@@ -3471,6 +4319,12 @@ function listSkillSymlinks() {
3471
4319
  }
3472
4320
  return results;
3473
4321
  }
4322
+ function escapeYamlValue(value) {
4323
+ if (value.includes(":") || value.includes("#") || value.includes("'") || value.includes('"') || value.includes("\n") || value.startsWith(" ") || value.endsWith(" ") || value.startsWith("[") || value.startsWith("{")) {
4324
+ return `"${value.replace(/\\/g, "\\\\").replace(/"/g, '\\"')}"`;
4325
+ }
4326
+ return value;
4327
+ }
3474
4328
  function generateReflySkillMd(options) {
3475
4329
  const {
3476
4330
  name,
@@ -3485,21 +4339,21 @@ function generateReflySkillMd(options) {
3485
4339
  inputSchema,
3486
4340
  outputSchema
3487
4341
  } = options;
3488
- const frontmatterLines = ["---", `name: ${name}`];
3489
- frontmatterLines.push(`description: ${description}`);
4342
+ const frontmatterLines = ["---", `name: ${escapeYamlValue(name)}`];
4343
+ frontmatterLines.push(`description: ${escapeYamlValue(description)}`);
3490
4344
  if (tags.length > 0) {
3491
4345
  frontmatterLines.push("tags:");
3492
- frontmatterLines.push(...tags.map((t) => ` - ${t}`));
4346
+ frontmatterLines.push(...tags.map((t) => ` - ${escapeYamlValue(t)}`));
3493
4347
  }
3494
- frontmatterLines.push(`version: ${version}`);
3495
- frontmatterLines.push(`skillId: ${skillId}`);
3496
- frontmatterLines.push(`workflowId: ${workflowId}`);
4348
+ frontmatterLines.push(`version: ${escapeYamlValue(version)}`);
4349
+ frontmatterLines.push(`skillId: ${escapeYamlValue(skillId)}`);
4350
+ frontmatterLines.push(`workflowId: ${escapeYamlValue(workflowId)}`);
3497
4351
  if (installationId) {
3498
- frontmatterLines.push(`installationId: ${installationId}`);
4352
+ frontmatterLines.push(`installationId: ${escapeYamlValue(installationId)}`);
3499
4353
  }
3500
4354
  if (triggers.length > 0) {
3501
4355
  frontmatterLines.push("triggers:");
3502
- frontmatterLines.push(...triggers.map((t) => ` - ${t}`));
4356
+ frontmatterLines.push(...triggers.map((t) => ` - ${escapeYamlValue(t)}`));
3503
4357
  }
3504
4358
  frontmatterLines.push("---");
3505
4359
  const title = displayName || name.split("-").map((w) => w.charAt(0).toUpperCase() + w.slice(1)).join(" ");
@@ -3518,14 +4372,6 @@ ${JSON.stringify(outputSchema, null, 2)}
3518
4372
 
3519
4373
  ${description}
3520
4374
 
3521
- ## Usage
3522
-
3523
- This skill is executed via Refly CLI:
3524
-
3525
- \`\`\`bash
3526
- ${runCommand}
3527
- \`\`\`
3528
-
3529
4375
  ## Input
3530
4376
 
3531
4377
  Provide input as JSON:
@@ -3534,16 +4380,42 @@ Provide input as JSON:
3534
4380
  ${inputExample}
3535
4381
  \`\`\`
3536
4382
 
4383
+ ## Execution
4384
+
4385
+ **Follow this exact 4-step pattern:**
4386
+
4387
+ \`\`\`bash
4388
+ # Step 1: Run and capture RUN_ID (we-xxx format)
4389
+ RESULT=$(${runCommand})
4390
+ RUN_ID=$(echo "$RESULT" | jq -r '.payload.workflowExecutions[0].id')
4391
+ # RUN_ID is we-xxx format, use this for workflow commands below
4392
+
4393
+ # Step 2: Wait for completion (use RUN_ID, not installationId)
4394
+ refly workflow status "$RUN_ID" --watch --interval 30000
4395
+
4396
+ # Step 3: Get files from this run (use RUN_ID)
4397
+ FILES=$(refly workflow toolcalls "$RUN_ID" --files --latest | jq -r '.payload.files[]')
4398
+
4399
+ # Step 4: Download and open each file
4400
+ echo "$FILES" | jq -c '.' | while read -r file; do
4401
+ FILE_ID=$(echo "$file" | jq -r '.fileId')
4402
+ FILE_NAME=$(echo "$file" | jq -r '.name')
4403
+ if [ -n "$FILE_ID" ] && [ "$FILE_ID" != "null" ]; then
4404
+ OUTPUT_PATH="$HOME/Desktop/$FILE_NAME"
4405
+ refly file download "$FILE_ID" -o "$OUTPUT_PATH"
4406
+ open "$OUTPUT_PATH"
4407
+ fi
4408
+ done
4409
+ \`\`\`
4410
+
3537
4411
  ## Output
3538
4412
 
3539
4413
  ${outputSection}
3540
4414
 
3541
4415
  ## Rules
3542
4416
 
3543
- For workflow operations, refer to the base skill rules:
3544
- - Workflow: \`~/.claude/skills/refly/rules/workflow.md\`
3545
- - Node: \`~/.claude/skills/refly/rules/node.md\`
3546
- - File: \`~/.claude/skills/refly/rules/file.md\`
4417
+ For workflow operations, refer to the base skill:
4418
+ - Base skill: \`~/.claude/skills/refly/SKILL.md\`
3547
4419
  `;
3548
4420
  return frontmatterLines.join("\n") + content;
3549
4421
  }
@@ -3604,15 +4476,79 @@ function parseReflySkillMd(content) {
3604
4476
  raw: content
3605
4477
  };
3606
4478
  }
3607
- var fs4, path4;
4479
+ async function createMultiPlatformSkill(skillName, skillMdContent, options) {
4480
+ const skillDir = getReflyDomainSkillDir(skillName);
4481
+ ensureReflySkillsDir();
4482
+ if (fs8.existsSync(skillDir)) {
4483
+ if (options?.force) {
4484
+ const skillMdPath = path7.join(skillDir, "SKILL.md");
4485
+ fs8.writeFileSync(skillMdPath, skillMdContent, { encoding: "utf-8", mode: 420 });
4486
+ logger.debug(`Updated SKILL.md (force): ${skillMdPath}`);
4487
+ } else {
4488
+ return {
4489
+ skillName,
4490
+ sourcePath: skillDir,
4491
+ results: /* @__PURE__ */ new Map(),
4492
+ successCount: 0,
4493
+ failureCount: 1
4494
+ };
4495
+ }
4496
+ } else {
4497
+ fs8.mkdirSync(skillDir, { recursive: true, mode: 493 });
4498
+ const skillMdPath = path7.join(skillDir, "SKILL.md");
4499
+ fs8.writeFileSync(skillMdPath, skillMdContent, { encoding: "utf-8", mode: 420 });
4500
+ logger.debug(`Created SKILL.md: ${skillMdPath}`);
4501
+ }
4502
+ return deploySkillToAllPlatforms(skillName, {
4503
+ force: options?.force,
4504
+ agents: options?.agents
4505
+ });
4506
+ }
4507
+ async function removeMultiPlatformSkill(skillName, options) {
4508
+ const platformResults = await removeSkillFromAllPlatforms(skillName, {
4509
+ agents: options?.agents
4510
+ });
4511
+ let directoryRemoved = false;
4512
+ if (!options?.keepLocal) {
4513
+ const skillDir = getReflyDomainSkillDir(skillName);
4514
+ try {
4515
+ if (fs8.existsSync(skillDir)) {
4516
+ fs8.rmSync(skillDir, { recursive: true, force: true });
4517
+ directoryRemoved = true;
4518
+ logger.info(`Removed skill directory: ${skillDir}`);
4519
+ }
4520
+ } catch (err) {
4521
+ logger.error(`Failed to remove skill directory ${skillDir}:`, err);
4522
+ }
4523
+ }
4524
+ return { platformResults, directoryRemoved };
4525
+ }
4526
+ async function listMultiPlatformSkills(options) {
4527
+ const allDeployed = await listAllDeployedSkills({ agents: options?.agents });
4528
+ const result = /* @__PURE__ */ new Map();
4529
+ for (const [agent, skills] of allDeployed) {
4530
+ result.set(
4531
+ agent,
4532
+ skills.map((s) => ({
4533
+ name: s.name,
4534
+ path: s.path,
4535
+ isValid: s.isValid,
4536
+ isSymlink: s.isSymlink
4537
+ }))
4538
+ );
4539
+ }
4540
+ return result;
4541
+ }
4542
+ var fs8, path7;
3608
4543
  var init_symlink = __esm({
3609
4544
  "src/skill/symlink.ts"() {
3610
4545
  "use strict";
3611
4546
  init_cjs_shims();
3612
- fs4 = __toESM(require("fs"));
3613
- path4 = __toESM(require("path"));
4547
+ fs8 = __toESM(require("fs"));
4548
+ path7 = __toESM(require("path"));
3614
4549
  init_paths();
3615
4550
  init_logger();
4551
+ init_manager();
3616
4552
  }
3617
4553
  });
3618
4554
 
@@ -4303,8 +5239,21 @@ var OutputFormatter = class {
4303
5239
  }
4304
5240
  // === JSON Format ===
4305
5241
  outputJson(data) {
4306
- console.log(JSON.stringify(data, null, 2));
5242
+ console.log(JSON.stringify(data, this.sanitizeJsonReplacer, 2));
4307
5243
  }
5244
+ /**
5245
+ * JSON replacer that sanitizes control characters in strings.
5246
+ * Control characters (U+0000 to U+001F) can break jq parsing.
5247
+ */
5248
+ sanitizeJsonReplacer = (_key, value) => {
5249
+ if (typeof value === "string") {
5250
+ return value.split("").filter((char) => {
5251
+ const code = char.charCodeAt(0);
5252
+ return code >= 32 || code === 9 || code === 10 || code === 13;
5253
+ }).join("");
5254
+ }
5255
+ return value;
5256
+ };
4308
5257
  // === Pretty Format ===
4309
5258
  outputPretty(type, payload) {
4310
5259
  if (type === "workflow.status" || type === "workflow.progress") {
@@ -4893,8 +5842,8 @@ var ErrorCodes = {
4893
5842
  };
4894
5843
 
4895
5844
  // src/bin/refly.ts
4896
- var fs26 = __toESM(require("fs"));
4897
- var path21 = __toESM(require("path"));
5845
+ var fs31 = __toESM(require("fs"));
5846
+ var path24 = __toESM(require("path"));
4898
5847
 
4899
5848
  // src/commands/init.ts
4900
5849
  init_cjs_shims();
@@ -5399,8 +6348,8 @@ function getErrorMap() {
5399
6348
  // ../../node_modules/.pnpm/zod@3.25.76/node_modules/zod/v3/helpers/parseUtil.js
5400
6349
  init_cjs_shims();
5401
6350
  var makeIssue = (params) => {
5402
- const { data, path: path22, errorMaps, issueData } = params;
5403
- const fullPath = [...path22, ...issueData.path || []];
6351
+ const { data, path: path25, errorMaps, issueData } = params;
6352
+ const fullPath = [...path25, ...issueData.path || []];
5404
6353
  const fullIssue = {
5405
6354
  ...issueData,
5406
6355
  path: fullPath
@@ -5520,11 +6469,11 @@ var errorUtil;
5520
6469
 
5521
6470
  // ../../node_modules/.pnpm/zod@3.25.76/node_modules/zod/v3/types.js
5522
6471
  var ParseInputLazyPath = class {
5523
- constructor(parent, value, path22, key) {
6472
+ constructor(parent, value, path25, key) {
5524
6473
  this._cachedPath = [];
5525
6474
  this.parent = parent;
5526
6475
  this.data = value;
5527
- this._path = path22;
6476
+ this._path = path25;
5528
6477
  this._key = key;
5529
6478
  }
5530
6479
  get path() {
@@ -8968,6 +9917,23 @@ var NEVER = INVALID;
8968
9917
 
8969
9918
  // src/config/config.ts
8970
9919
  init_paths();
9920
+ var AgentTypeEnum = external_exports.enum([
9921
+ "claude-code",
9922
+ "codex",
9923
+ "antigravity",
9924
+ "github-copilot",
9925
+ "windsurf",
9926
+ "opencode",
9927
+ "moltbot",
9928
+ "cursor",
9929
+ "continue",
9930
+ "trae",
9931
+ "qoder"
9932
+ ]);
9933
+ var PlatformConfigSchema = external_exports.object({
9934
+ enabled: external_exports.boolean().default(true),
9935
+ globalPath: external_exports.string().optional()
9936
+ });
8971
9937
  var ConfigSchema = external_exports.object({
8972
9938
  version: external_exports.number().default(1),
8973
9939
  auth: external_exports.object({
@@ -8995,7 +9961,9 @@ var ConfigSchema = external_exports.object({
8995
9961
  skill: external_exports.object({
8996
9962
  installedVersion: external_exports.string().optional(),
8997
9963
  installedAt: external_exports.string().optional()
8998
- }).optional()
9964
+ }).optional(),
9965
+ // Multi-platform configuration
9966
+ platforms: external_exports.record(AgentTypeEnum, PlatformConfigSchema).optional()
8999
9967
  });
9000
9968
  var DEFAULT_API_ENDPOINT = "https://api.refly.ai";
9001
9969
  var DEFAULT_WEB_URL = "https://refly.ai";
@@ -9132,22 +10100,22 @@ init_paths();
9132
10100
 
9133
10101
  // src/skill/installer.ts
9134
10102
  init_cjs_shims();
9135
- var fs5 = __toESM(require("fs"));
9136
- var path5 = __toESM(require("path"));
10103
+ var fs9 = __toESM(require("fs"));
10104
+ var path8 = __toESM(require("path"));
9137
10105
  init_paths();
9138
10106
  init_logger();
9139
10107
  init_symlink();
9140
10108
  function removeOldSkillDirectory() {
9141
10109
  const claudeSkillPath = getClaudeSkillSymlinkPath("refly");
9142
- if (!fs5.existsSync(claudeSkillPath)) {
10110
+ if (!fs9.existsSync(claudeSkillPath)) {
9143
10111
  return;
9144
10112
  }
9145
10113
  try {
9146
- const stat = fs5.lstatSync(claudeSkillPath);
10114
+ const stat = fs9.lstatSync(claudeSkillPath);
9147
10115
  if (stat.isSymbolicLink()) {
9148
- fs5.unlinkSync(claudeSkillPath);
10116
+ fs9.unlinkSync(claudeSkillPath);
9149
10117
  } else if (stat.isDirectory()) {
9150
- fs5.rmSync(claudeSkillPath, { recursive: true, force: true });
10118
+ fs9.rmSync(claudeSkillPath, { recursive: true, force: true });
9151
10119
  logger.info("Removed old skill directory");
9152
10120
  }
9153
10121
  } catch (err) {
@@ -9156,17 +10124,17 @@ function removeOldSkillDirectory() {
9156
10124
  }
9157
10125
  function getPackageSkillDir() {
9158
10126
  const possiblePaths = [
9159
- path5.join(__dirname, "..", "..", "skill"),
10127
+ path8.join(__dirname, "..", "..", "skill"),
9160
10128
  // Built package: dist/bin/../../skill
9161
- path5.join(__dirname, "..", "..", "..", "skill"),
10129
+ path8.join(__dirname, "..", "..", "..", "skill"),
9162
10130
  // Development: dist/bin/../../../skill
9163
- path5.join(__dirname, "..", "skill")
10131
+ path8.join(__dirname, "..", "skill")
9164
10132
  // Alternative: dist/../skill
9165
10133
  ];
9166
10134
  logger.debug("Looking for skill files, __dirname:", __dirname);
9167
10135
  for (const p of possiblePaths) {
9168
- const resolved = path5.resolve(p);
9169
- const exists = fs5.existsSync(resolved);
10136
+ const resolved = path8.resolve(p);
10137
+ const exists = fs9.existsSync(resolved);
9170
10138
  logger.debug(` Checking path: ${resolved} - exists: ${exists}`);
9171
10139
  if (exists) {
9172
10140
  return resolved;
@@ -9190,30 +10158,30 @@ function installSkill() {
9190
10158
  logger.debug("Target skill directory:", targetDir);
9191
10159
  try {
9192
10160
  ensureDir(targetDir);
9193
- ensureDir(path5.join(targetDir, "rules"));
10161
+ ensureDir(path8.join(targetDir, "rules"));
9194
10162
  logger.debug("Created target directories");
9195
10163
  } catch (err) {
9196
10164
  logger.error("Failed to create target directories:", err);
9197
10165
  throw err;
9198
10166
  }
9199
- const skillSource = path5.join(sourceDir, "SKILL.md");
9200
- const skillTarget = path5.join(targetDir, "SKILL.md");
10167
+ const skillSource = path8.join(sourceDir, "SKILL.md");
10168
+ const skillTarget = path8.join(targetDir, "SKILL.md");
9201
10169
  logger.debug(`Copying SKILL.md: ${skillSource} -> ${skillTarget}`);
9202
- if (fs5.existsSync(skillSource)) {
9203
- fs5.copyFileSync(skillSource, skillTarget);
10170
+ if (fs9.existsSync(skillSource)) {
10171
+ fs9.copyFileSync(skillSource, skillTarget);
9204
10172
  result.skillInstalled = true;
9205
10173
  result.skillPath = targetDir;
9206
10174
  logger.debug("SKILL.md copied successfully");
9207
10175
  } else {
9208
10176
  logger.warn("SKILL.md source not found:", skillSource);
9209
10177
  }
9210
- const refsSource = path5.join(sourceDir, "references");
9211
- const rulesTarget = path5.join(targetDir, "rules");
9212
- if (fs5.existsSync(refsSource)) {
9213
- const files = fs5.readdirSync(refsSource);
10178
+ const refsSource = path8.join(sourceDir, "references");
10179
+ const rulesTarget = path8.join(targetDir, "rules");
10180
+ if (fs9.existsSync(refsSource)) {
10181
+ const files = fs9.readdirSync(refsSource);
9214
10182
  logger.debug(`Copying ${files.length} rule files`);
9215
10183
  for (const file of files) {
9216
- fs5.copyFileSync(path5.join(refsSource, file), path5.join(rulesTarget, file));
10184
+ fs9.copyFileSync(path8.join(refsSource, file), path8.join(rulesTarget, file));
9217
10185
  }
9218
10186
  }
9219
10187
  removeOldSkillDirectory();
@@ -9241,15 +10209,15 @@ function installSkill() {
9241
10209
  return result;
9242
10210
  }
9243
10211
  function installSlashCommands(sourceDir, targetDir) {
9244
- const commandsSource = path5.join(sourceDir, "..", "commands");
9245
- if (!fs5.existsSync(commandsSource)) {
10212
+ const commandsSource = path8.join(sourceDir, "..", "commands");
10213
+ if (!fs9.existsSync(commandsSource)) {
9246
10214
  return false;
9247
10215
  }
9248
10216
  try {
9249
- const files = fs5.readdirSync(commandsSource);
10217
+ const files = fs9.readdirSync(commandsSource);
9250
10218
  for (const file of files) {
9251
10219
  if (file.endsWith(".md")) {
9252
- fs5.copyFileSync(path5.join(commandsSource, file), path5.join(targetDir, file));
10220
+ fs9.copyFileSync(path8.join(commandsSource, file), path8.join(targetDir, file));
9253
10221
  }
9254
10222
  }
9255
10223
  return files.length > 0;
@@ -9259,8 +10227,8 @@ function installSlashCommands(sourceDir, targetDir) {
9259
10227
  }
9260
10228
  function getSkillVersion() {
9261
10229
  try {
9262
- const skillPath = path5.join(getPackageSkillDir(), "SKILL.md");
9263
- const content = fs5.readFileSync(skillPath, "utf-8");
10230
+ const skillPath = path8.join(getPackageSkillDir(), "SKILL.md");
10231
+ const content = fs9.readFileSync(skillPath, "utf-8");
9264
10232
  const versionMatch = content.match(/version:\s*(\d+\.\d+\.\d+)/);
9265
10233
  if (versionMatch) {
9266
10234
  return versionMatch[1];
@@ -9268,16 +10236,16 @@ function getSkillVersion() {
9268
10236
  } catch {
9269
10237
  }
9270
10238
  try {
9271
- const pkgPath = path5.join(__dirname, "..", "..", "package.json");
9272
- const pkg = JSON.parse(fs5.readFileSync(pkgPath, "utf-8"));
10239
+ const pkgPath = path8.join(__dirname, "..", "..", "package.json");
10240
+ const pkg = JSON.parse(fs9.readFileSync(pkgPath, "utf-8"));
9273
10241
  return pkg.version;
9274
10242
  } catch {
9275
10243
  return "0.1.0";
9276
10244
  }
9277
10245
  }
9278
10246
  function isSkillInstalled() {
9279
- const skillPath = path5.join(getReflyBaseSkillDir(), "SKILL.md");
9280
- if (!fs5.existsSync(skillPath)) {
10247
+ const skillPath = path8.join(getReflyBaseSkillDir(), "SKILL.md");
10248
+ if (!fs9.existsSync(skillPath)) {
9281
10249
  return { installed: false, upToDate: false };
9282
10250
  }
9283
10251
  const currentVersion = getSkillVersion();
@@ -9291,6 +10259,9 @@ function isSkillInstalled() {
9291
10259
  };
9292
10260
  }
9293
10261
 
10262
+ // src/commands/init.ts
10263
+ init_manager();
10264
+
9294
10265
  // src/utils/logo.ts
9295
10266
  init_cjs_shims();
9296
10267
  var REFLY_LOGO = `\u2588\u2580\u2588 \u2588\u2580\u2580 \u2588\u2580\u2580 \u2588 \u2588 \u2588 \u2588\u2580\u2588 \u2588
@@ -9349,7 +10320,7 @@ var import_promises = __toESM(require("fs/promises"), 1);
9349
10320
  // ../../node_modules/.pnpm/is-wsl@3.1.0/node_modules/is-wsl/index.js
9350
10321
  init_cjs_shims();
9351
10322
  var import_node_process = __toESM(require("process"), 1);
9352
- var import_node_os = __toESM(require("os"), 1);
10323
+ var import_node_os3 = __toESM(require("os"), 1);
9353
10324
  var import_node_fs3 = __toESM(require("fs"), 1);
9354
10325
 
9355
10326
  // ../../node_modules/.pnpm/is-inside-container@1.0.0/node_modules/is-inside-container/index.js
@@ -9404,7 +10375,7 @@ var isWsl = () => {
9404
10375
  if (import_node_process.default.platform !== "linux") {
9405
10376
  return false;
9406
10377
  }
9407
- if (import_node_os.default.release().toLowerCase().includes("microsoft")) {
10378
+ if (import_node_os3.default.release().toLowerCase().includes("microsoft")) {
9408
10379
  if (isInsideContainer()) {
9409
10380
  return false;
9410
10381
  }
@@ -9600,7 +10571,7 @@ async function defaultBrowser2() {
9600
10571
  var execFile5 = (0, import_node_util5.promisify)(import_node_child_process5.default.execFile);
9601
10572
  var __dirname2 = import_node_path.default.dirname((0, import_node_url.fileURLToPath)(importMetaUrl));
9602
10573
  var localXdgOpenPath = import_node_path.default.join(__dirname2, "xdg-open");
9603
- var { platform: platform2, arch } = import_node_process6.default;
10574
+ var { platform: platform3, arch } = import_node_process6.default;
9604
10575
  async function getWindowsDefaultBrowserFromWsl() {
9605
10576
  const powershellPath = await powerShellPath();
9606
10577
  const rawCommand = String.raw`(Get-ItemProperty -Path "HKCU:\Software\Microsoft\Windows\Shell\Associations\UrlAssociations\http\UserChoice").ProgId`;
@@ -9699,7 +10670,7 @@ var baseOpen = async (options) => {
9699
10670
  let command;
9700
10671
  const cliArguments = [];
9701
10672
  const childProcessOptions = {};
9702
- if (platform2 === "darwin") {
10673
+ if (platform3 === "darwin") {
9703
10674
  command = "open";
9704
10675
  if (options.wait) {
9705
10676
  cliArguments.push("--wait-apps");
@@ -9713,7 +10684,7 @@ var baseOpen = async (options) => {
9713
10684
  if (app) {
9714
10685
  cliArguments.push("-a", app);
9715
10686
  }
9716
- } else if (platform2 === "win32" || is_wsl_default && !isInsideContainer() && !app) {
10687
+ } else if (platform3 === "win32" || is_wsl_default && !isInsideContainer() && !app) {
9717
10688
  command = await powerShellPath();
9718
10689
  cliArguments.push(
9719
10690
  "-NoProfile",
@@ -9753,7 +10724,7 @@ var baseOpen = async (options) => {
9753
10724
  exeLocalXdgOpen = true;
9754
10725
  } catch {
9755
10726
  }
9756
- const useSystemXdgOpen = import_node_process6.default.versions.electron ?? (platform2 === "android" || isBundled || !exeLocalXdgOpen);
10727
+ const useSystemXdgOpen = import_node_process6.default.versions.electron ?? (platform3 === "android" || isBundled || !exeLocalXdgOpen);
9757
10728
  command = useSystemXdgOpen ? "xdg-open" : localXdgOpenPath;
9758
10729
  }
9759
10730
  if (appArguments.length > 0) {
@@ -9764,7 +10735,7 @@ var baseOpen = async (options) => {
9764
10735
  childProcessOptions.detached = true;
9765
10736
  }
9766
10737
  }
9767
- if (platform2 === "darwin" && appArguments.length > 0) {
10738
+ if (platform3 === "darwin" && appArguments.length > 0) {
9768
10739
  cliArguments.push("--args", ...appArguments);
9769
10740
  }
9770
10741
  if (options.target) {
@@ -9772,14 +10743,14 @@ var baseOpen = async (options) => {
9772
10743
  }
9773
10744
  const subprocess = import_node_child_process5.default.spawn(command, cliArguments, childProcessOptions);
9774
10745
  if (options.wait) {
9775
- return new Promise((resolve7, reject) => {
10746
+ return new Promise((resolve8, reject) => {
9776
10747
  subprocess.once("error", reject);
9777
10748
  subprocess.once("close", (exitCode) => {
9778
10749
  if (!options.allowNonzeroExitCode && exitCode > 0) {
9779
10750
  reject(new Error(`Exited with code ${exitCode}`));
9780
10751
  return;
9781
10752
  }
9782
- resolve7(subprocess);
10753
+ resolve8(subprocess);
9783
10754
  });
9784
10755
  });
9785
10756
  }
@@ -9805,12 +10776,12 @@ function detectArchBinary(binary) {
9805
10776
  }
9806
10777
  return archBinary;
9807
10778
  }
9808
- function detectPlatformBinary({ [platform2]: platformBinary }, { wsl }) {
10779
+ function detectPlatformBinary({ [platform3]: platformBinary }, { wsl }) {
9809
10780
  if (wsl && is_wsl_default) {
9810
10781
  return detectArchBinary(wsl);
9811
10782
  }
9812
10783
  if (!platformBinary) {
9813
- throw new Error(`${platform2} is not supported`);
10784
+ throw new Error(`${platform3} is not supported`);
9814
10785
  }
9815
10786
  return detectArchBinary(platformBinary);
9816
10787
  }
@@ -9855,9 +10826,9 @@ var open_default = open;
9855
10826
 
9856
10827
  // src/api/client.ts
9857
10828
  init_cjs_shims();
9858
- var fs11 = __toESM(require("fs"));
10829
+ var fs15 = __toESM(require("fs"));
9859
10830
  var import_node_fs4 = require("fs");
9860
- var path7 = __toESM(require("path"));
10831
+ var path10 = __toESM(require("path"));
9861
10832
  var import_mime = __toESM(require("mime"));
9862
10833
 
9863
10834
  // src/utils/errors.ts
@@ -9886,10 +10857,10 @@ var NetworkError = class extends CLIError {
9886
10857
  // src/api/client.ts
9887
10858
  init_logger();
9888
10859
  var DEFAULT_TIMEOUT = 3e4;
9889
- async function apiRequest(path22, options = {}) {
10860
+ async function apiRequest(path25, options = {}) {
9890
10861
  const { method = "GET", body, query, timeout = DEFAULT_TIMEOUT, requireAuth = true } = options;
9891
10862
  const endpoint = getApiEndpoint();
9892
- let url = `${endpoint}${path22}`;
10863
+ let url = `${endpoint}${path25}`;
9893
10864
  if (query && Object.keys(query).length > 0) {
9894
10865
  const params = new URLSearchParams(query);
9895
10866
  url = `${url}?${params.toString()}`;
@@ -9927,7 +10898,7 @@ async function apiRequest(path22, options = {}) {
9927
10898
  const controller = new AbortController();
9928
10899
  const timeoutId = setTimeout(() => controller.abort(), timeout);
9929
10900
  try {
9930
- logger.debug(`API Request: ${method} ${path22}`);
10901
+ logger.debug(`API Request: ${method} ${path25}`);
9931
10902
  const response = await fetch(url, {
9932
10903
  method,
9933
10904
  headers,
@@ -10042,10 +11013,10 @@ function mapAPIError(status, response) {
10042
11013
  }
10043
11014
  return new CLIError(errCode, errMsg);
10044
11015
  }
10045
- async function apiRequestStream(path22, options = {}) {
11016
+ async function apiRequestStream(path25, options = {}) {
10046
11017
  const { timeout = 3e5 } = options;
10047
11018
  const endpoint = getApiEndpoint();
10048
- const url = `${endpoint}${path22}`;
11019
+ const url = `${endpoint}${path25}`;
10049
11020
  const headers = {
10050
11021
  "User-Agent": "refly-cli/0.1.0"
10051
11022
  };
@@ -10076,7 +11047,7 @@ async function apiRequestStream(path22, options = {}) {
10076
11047
  const controller = new AbortController();
10077
11048
  const timeoutId = setTimeout(() => controller.abort(), timeout);
10078
11049
  try {
10079
- logger.debug(`API Stream Request: GET ${path22}`);
11050
+ logger.debug(`API Stream Request: GET ${path25}`);
10080
11051
  const response = await fetch(url, {
10081
11052
  method: "GET",
10082
11053
  headers,
@@ -10171,7 +11142,7 @@ async function uploadToPresignedUrl(presignedUrl, filePath, contentType, retryCo
10171
11142
  const controller = new AbortController();
10172
11143
  const timeoutId = setTimeout(() => controller.abort(), timeout);
10173
11144
  try {
10174
- const fileBuffer = await fs11.promises.readFile(filePath);
11145
+ const fileBuffer = await fs15.promises.readFile(filePath);
10175
11146
  const response = await fetch(presignedUrl, {
10176
11147
  method: "PUT",
10177
11148
  headers: {
@@ -10229,7 +11200,7 @@ async function apiGetWorkflow(workflowId) {
10229
11200
  return apiRequest(`/v1/cli/workflow/${workflowId}`);
10230
11201
  }
10231
11202
  async function apiUploadDriveFile(filePath, canvasId, options) {
10232
- const filename = path7.basename(filePath);
11203
+ const filename = path10.basename(filePath);
10233
11204
  const mimeType = getMimeType(filePath);
10234
11205
  const fileStats = (0, import_node_fs4.statSync)(filePath);
10235
11206
  logger.debug(`Starting presigned upload: ${filename} (${fileStats.size} bytes)`);
@@ -10492,7 +11463,7 @@ async function getUserInfoFromToken(accessToken) {
10492
11463
  };
10493
11464
  }
10494
11465
  function sleep(ms) {
10495
- return new Promise((resolve7) => setTimeout(resolve7, ms));
11466
+ return new Promise((resolve8) => setTimeout(resolve8, ms));
10496
11467
  }
10497
11468
 
10498
11469
  // src/commands/init.ts
@@ -10552,7 +11523,38 @@ var initCommand = new Command("init").description("Initialize Refly CLI, install
10552
11523
  printError2("Slash commands installation failed");
10553
11524
  }
10554
11525
  println("");
10555
- } else if (!pretty) {
11526
+ }
11527
+ const installedAgents = await detectInstalledAgents();
11528
+ const deployableAgents = installedAgents.filter((a) => a.format !== "unknown");
11529
+ if (pretty && tty && deployableAgents.length > 0) {
11530
+ println(`Found ${deployableAgents.length} installed agent(s):`);
11531
+ for (const agent of deployableAgents) {
11532
+ const dir = agent.globalSkillsDir || agent.skillsDir || "N/A";
11533
+ println(` \u2713 ${agent.displayName.padEnd(16)} ${dir}`);
11534
+ }
11535
+ println("");
11536
+ }
11537
+ const platformResults = [];
11538
+ if (deployableAgents.length > 0) {
11539
+ const deployResult = await deploySkillToAllPlatforms("refly", { force: true });
11540
+ for (const [agentName, result] of deployResult.results) {
11541
+ platformResults.push({
11542
+ agent: agentName,
11543
+ success: result.success,
11544
+ path: result.deployedPath || void 0
11545
+ });
11546
+ }
11547
+ if (pretty && tty) {
11548
+ const successCount = platformResults.filter((r) => r.success).length;
11549
+ if (successCount === deployableAgents.length) {
11550
+ printSuccess(`Synced to ${successCount} agent(s)`);
11551
+ } else {
11552
+ printDim(`Synced to ${successCount}/${deployableAgents.length} agent(s)`);
11553
+ }
11554
+ println("");
11555
+ }
11556
+ }
11557
+ if (!pretty) {
10556
11558
  print("init", {
10557
11559
  message: "Refly CLI initialized successfully",
10558
11560
  configDir: getReflyDir(),
@@ -10562,7 +11564,11 @@ var initCommand = new Command("init").description("Initialize Refly CLI, install
10562
11564
  symlinkPath: installResult.symlinkPath,
10563
11565
  commandsInstalled: installResult.commandsInstalled,
10564
11566
  commandsPath: installResult.commandsPath,
10565
- version: installResult.version
11567
+ version: installResult.version,
11568
+ platforms: {
11569
+ detected: installedAgents.map((a) => a.name),
11570
+ deployed: platformResults
11571
+ }
10566
11572
  });
10567
11573
  }
10568
11574
  if (!skipLogin && !isAuthenticated2) {
@@ -10750,7 +11756,7 @@ var import_node_child_process6 = require("child_process");
10750
11756
  var import_node_fs5 = __toESM(require("fs"));
10751
11757
  init_logger();
10752
11758
  init_paths();
10753
- var CLI_VERSION = "0.1.23";
11759
+ var CLI_VERSION = "0.1.25";
10754
11760
  var NPM_TAG = "latest";
10755
11761
  function compareSemver(a, b) {
10756
11762
  const parseVersion = (v) => {
@@ -11006,16 +12012,16 @@ configCommand.action(() => {
11006
12012
  };
11007
12013
  ok("config", safeConfig);
11008
12014
  });
11009
- function getNestedValue(obj, path22) {
11010
- return path22.split(".").reduce((current, key) => {
12015
+ function getNestedValue(obj, path25) {
12016
+ return path25.split(".").reduce((current, key) => {
11011
12017
  if (current && typeof current === "object" && key in current) {
11012
12018
  return current[key];
11013
12019
  }
11014
12020
  return void 0;
11015
12021
  }, obj);
11016
12022
  }
11017
- function setNestedValue(obj, path22, value) {
11018
- const keys = path22.split(".");
12023
+ function setNestedValue(obj, path25, value) {
12024
+ const keys = path25.split(".");
11019
12025
  const lastKey = keys.pop();
11020
12026
  let current = obj;
11021
12027
  for (const key of keys) {
@@ -11256,14 +12262,14 @@ var workflowDeleteCommand = new Command("delete").description("Delete a workflow
11256
12262
  init_cjs_shims();
11257
12263
  var readline2 = __toESM(require("readline/promises"));
11258
12264
  var import_node_process8 = require("process");
11259
- var path9 = __toESM(require("path"));
12265
+ var path12 = __toESM(require("path"));
11260
12266
 
11261
12267
  // src/utils/prompt.ts
11262
12268
  init_cjs_shims();
11263
12269
  var readline = __toESM(require("readline/promises"));
11264
12270
  var import_node_process7 = require("process");
11265
- var fs13 = __toESM(require("fs"));
11266
- var path8 = __toESM(require("path"));
12271
+ var fs17 = __toESM(require("fs"));
12272
+ var path11 = __toESM(require("path"));
11267
12273
  function isInteractive() {
11268
12274
  return process.stdin?.isTTY ?? false;
11269
12275
  }
@@ -11287,12 +12293,12 @@ async function promptForFilePath(variableName, resourceTypes, isRequired) {
11287
12293
  const homeDir = process.env.HOME || process.env.USERPROFILE || "";
11288
12294
  resolvedPath = resolvedPath.replace("~", homeDir);
11289
12295
  }
11290
- resolvedPath = path8.resolve(resolvedPath);
11291
- if (!fs13.existsSync(resolvedPath)) {
12296
+ resolvedPath = path11.resolve(resolvedPath);
12297
+ if (!fs17.existsSync(resolvedPath)) {
11292
12298
  console.log(` File not found: ${resolvedPath}`);
11293
12299
  continue;
11294
12300
  }
11295
- const stats = fs13.statSync(resolvedPath);
12301
+ const stats = fs17.statSync(resolvedPath);
11296
12302
  if (!stats.isFile()) {
11297
12303
  console.log(` Not a file: ${resolvedPath}`);
11298
12304
  continue;
@@ -11490,12 +12496,12 @@ async function pollToolsStatus(workflowId, maxWaitTime = 15 * 60 * 1e3, pollInte
11490
12496
  );
11491
12497
  previousRemainingCount = remainingCount;
11492
12498
  }
11493
- await new Promise((resolve7) => setTimeout(resolve7, pollInterval));
12499
+ await new Promise((resolve8) => setTimeout(resolve8, pollInterval));
11494
12500
  } catch (error) {
11495
12501
  console.log(`
11496
12502
  \u26A0\uFE0F Failed to check authorization status: ${error.message}`);
11497
12503
  console.log("Continuing to wait...");
11498
- await new Promise((resolve7) => setTimeout(resolve7, pollInterval));
12504
+ await new Promise((resolve8) => setTimeout(resolve8, pollInterval));
11499
12505
  }
11500
12506
  }
11501
12507
  console.log("\n\u23F0 Timeout waiting for tool authorization.");
@@ -11606,7 +12612,7 @@ ${details}`;
11606
12612
  if (!filePath) {
11607
12613
  continue;
11608
12614
  }
11609
- const filename = path9.basename(filePath);
12615
+ const filename = path12.basename(filePath);
11610
12616
  process.stdout.write(` Uploading ${filename}...`);
11611
12617
  try {
11612
12618
  const uploadResult = await apiUploadDriveFile(filePath, workflowId);
@@ -11988,7 +12994,7 @@ var workflowStatusCommand = new Command("status").description("Get detailed work
11988
12994
  });
11989
12995
  prevStatus = status;
11990
12996
  while (status.status === "init" || status.status === "executing") {
11991
- await new Promise((resolve7) => setTimeout(resolve7, pollInterval));
12997
+ await new Promise((resolve8) => setTimeout(resolve8, pollInterval));
11992
12998
  status = await fetchStatus();
11993
12999
  if (options.full || hasStatusChanged(prevStatus, status)) {
11994
13000
  if (options.full) {
@@ -12116,7 +13122,75 @@ var workflowDetailCommand = new Command("detail").description("Get detailed work
12116
13122
 
12117
13123
  // src/commands/workflow/toolcalls.ts
12118
13124
  init_cjs_shims();
12119
- var workflowToolcallsCommand = new Command("toolcalls").description("Get all tool calls for workflow execution").argument("<id>", "Workflow ID (c-xxx) or Run ID (we-xxx)").option("--node-id <nodeId>", "Filter by node ID").option("--toolset-id <toolsetId>", "Filter by toolset ID").option("--tool-name <toolName>", "Filter by tool name").option("--status <status>", "Filter by status (executing, completed, failed)").option("--limit <limit>", "Maximum number of results (default: 100)", "100").option("--offset <offset>", "Pagination offset (default: 0)", "0").option("--raw", "Disable output sanitization (show full tool outputs)").action(async (id, options) => {
13125
+ function extractNodeOutputs(toolCalls) {
13126
+ const outputs = [];
13127
+ for (const call of toolCalls) {
13128
+ if (!call.output || call.status !== "completed") continue;
13129
+ const output3 = call.output;
13130
+ const filesMap = /* @__PURE__ */ new Map();
13131
+ let content;
13132
+ if (Array.isArray(output3.files)) {
13133
+ for (const f of output3.files) {
13134
+ const file = f;
13135
+ if (file.fileId && !filesMap.has(String(file.fileId))) {
13136
+ filesMap.set(String(file.fileId), {
13137
+ fileId: String(file.fileId),
13138
+ name: String(file.name || ""),
13139
+ type: String(file.type || ""),
13140
+ category: file.category,
13141
+ size: file.size,
13142
+ url: file.url,
13143
+ source: file.source,
13144
+ createdAt: file.createdAt
13145
+ });
13146
+ }
13147
+ }
13148
+ }
13149
+ if (output3.data && typeof output3.data === "object") {
13150
+ const data = output3.data;
13151
+ if (data.fileId && !filesMap.has(String(data.fileId))) {
13152
+ filesMap.set(String(data.fileId), {
13153
+ fileId: String(data.fileId),
13154
+ name: String(data.name || ""),
13155
+ type: String(data.type || ""),
13156
+ category: data.category,
13157
+ size: data.size,
13158
+ url: data.url,
13159
+ source: data.source,
13160
+ createdAt: data.createdAt
13161
+ });
13162
+ }
13163
+ }
13164
+ if (output3.content) {
13165
+ content = String(output3.content).slice(0, 500);
13166
+ } else if (output3.data && typeof output3.data === "object") {
13167
+ const data = output3.data;
13168
+ if (data.candidates && Array.isArray(data.candidates)) {
13169
+ const parts = data.candidates[0]?.content;
13170
+ if (parts?.parts && Array.isArray(parts.parts)) {
13171
+ const textPart = parts.parts.find(
13172
+ (p) => typeof p.text === "string" && !p.thought
13173
+ );
13174
+ if (textPart) {
13175
+ content = String(textPart.text).slice(0, 500);
13176
+ }
13177
+ }
13178
+ }
13179
+ }
13180
+ const files = Array.from(filesMap.values());
13181
+ if (files.length > 0 || content) {
13182
+ outputs.push({
13183
+ nodeId: call.nodeId || "",
13184
+ nodeTitle: call.nodeTitle || call.toolName,
13185
+ toolName: call.toolName,
13186
+ content,
13187
+ files
13188
+ });
13189
+ }
13190
+ }
13191
+ return outputs;
13192
+ }
13193
+ var workflowToolcallsCommand = new Command("toolcalls").description("Get all tool calls for workflow execution").argument("<id>", "Workflow ID (c-xxx) or Run ID (we-xxx)").option("--node-id <nodeId>", "Filter by node ID").option("--toolset-id <toolsetId>", "Filter by toolset ID").option("--tool-name <toolName>", "Filter by tool name").option("--status <status>", "Filter by status (executing, completed, failed)").option("--limit <limit>", "Maximum number of results (default: 100)", "100").option("--offset <offset>", "Pagination offset (default: 0)", "0").option("--raw", "Disable output sanitization (show full tool outputs)").option("--files", "Show only files and content from each node (simplified output)").option("--latest", "With --files, only show files from the most recent toolcall").action(async (id, options) => {
12120
13194
  try {
12121
13195
  const params = new URLSearchParams();
12122
13196
  if (options.nodeId) {
@@ -12137,12 +13211,26 @@ var workflowToolcallsCommand = new Command("toolcalls").description("Get all too
12137
13211
  if (options.offset) {
12138
13212
  params.set("offset", options.offset);
12139
13213
  }
12140
- if (options.raw) {
13214
+ if (options.raw || options.files) {
12141
13215
  params.set("sanitizeForDisplay", "false");
12142
13216
  }
12143
13217
  const idType = detectIdType2(id);
12144
13218
  const url = buildWorkflowApiUrl(id, "toolcalls", params);
12145
13219
  const result = await apiRequest(url);
13220
+ if (options.files) {
13221
+ let nodeOutputs = extractNodeOutputs(result.toolCalls);
13222
+ if (options.latest && nodeOutputs.length > 0) {
13223
+ const lastWithFiles = nodeOutputs.filter((n) => n.files.length > 0).pop();
13224
+ nodeOutputs = lastWithFiles ? [lastWithFiles] : [];
13225
+ }
13226
+ const allFiles = nodeOutputs.flatMap((n) => n.files);
13227
+ ok("workflow.files", {
13228
+ runId: result.runId,
13229
+ workflowId: result.workflowId,
13230
+ files: allFiles,
13231
+ nodes: nodeOutputs
13232
+ });
13233
+ }
12146
13234
  ok("workflow.toolcalls", {
12147
13235
  runId: result.runId,
12148
13236
  workflowId: result.workflowId,
@@ -13305,16 +14393,16 @@ var fileGetCommand = new Command("get").description("Get file details").argument
13305
14393
 
13306
14394
  // src/commands/file/download.ts
13307
14395
  init_cjs_shims();
13308
- var fs14 = __toESM(require("fs"));
13309
- var path10 = __toESM(require("path"));
14396
+ var fs18 = __toESM(require("fs"));
14397
+ var path13 = __toESM(require("path"));
13310
14398
  var fileDownloadCommand = new Command("download").description("Download file to local filesystem").argument("<fileId>", "File ID").option("-o, --output <path>", "Output file path (defaults to original filename)").action(async (fileId, options) => {
13311
14399
  try {
13312
14400
  const { data, filename, contentType, size } = await apiRequestStream(
13313
14401
  `/v1/cli/drive/files/${fileId}/download`
13314
14402
  );
13315
14403
  const outputPath = options.output || filename || `${fileId}`;
13316
- const resolvedPath = path10.resolve(outputPath);
13317
- fs14.writeFileSync(resolvedPath, data);
14404
+ const resolvedPath = path13.resolve(outputPath);
14405
+ fs18.writeFileSync(resolvedPath, data);
13318
14406
  ok("file.download", {
13319
14407
  fileId,
13320
14408
  path: resolvedPath,
@@ -13339,8 +14427,8 @@ var fileDownloadCommand = new Command("download").description("Download file to
13339
14427
 
13340
14428
  // src/commands/file/upload.ts
13341
14429
  init_cjs_shims();
13342
- var fs15 = __toESM(require("fs"));
13343
- var path11 = __toESM(require("path"));
14430
+ var fs19 = __toESM(require("fs"));
14431
+ var path14 = __toESM(require("path"));
13344
14432
  var MAX_FILES = 10;
13345
14433
  function formatSize(bytes) {
13346
14434
  if (bytes < 1024) return `${bytes}B`;
@@ -13350,8 +14438,8 @@ function formatSize(bytes) {
13350
14438
  var fileUploadCommand = new Command("upload").description("Upload file(s) to a canvas").argument("<path>", "File or directory path").requiredOption("--canvas-id <id>", "Canvas ID (required)").option("--filter <extensions>", "Filter by extensions (e.g., pdf,docx,png)").action(async (inputPath, options) => {
13351
14439
  const formatter = getFormatter();
13352
14440
  try {
13353
- const resolvedPath = path11.resolve(inputPath);
13354
- if (!fs15.existsSync(resolvedPath)) {
14441
+ const resolvedPath = path14.resolve(inputPath);
14442
+ if (!fs19.existsSync(resolvedPath)) {
13355
14443
  fail(ErrorCodes.NOT_FOUND, `Path not found: ${inputPath}`, {
13356
14444
  hint: "Check if the file or directory exists"
13357
14445
  });
@@ -13369,8 +14457,8 @@ var fileUploadCommand = new Command("upload").description("Upload file(s) to a c
13369
14457
  const errors = [];
13370
14458
  for (let i = 0; i < files.length; i++) {
13371
14459
  const filePath = files[i];
13372
- const filename = path11.basename(filePath);
13373
- const fileStats = fs15.statSync(filePath);
14460
+ const filename = path14.basename(filePath);
14461
+ const fileStats = fs19.statSync(filePath);
13374
14462
  const sizeStr = formatSize(fileStats.size);
13375
14463
  let currentStage = "presign";
13376
14464
  const updateProgress = () => {
@@ -13451,11 +14539,11 @@ var fileUploadCommand = new Command("upload").description("Upload file(s) to a c
13451
14539
  }
13452
14540
  });
13453
14541
  function resolveFilesToUpload(inputPath, filter) {
13454
- const stats = fs15.statSync(inputPath);
14542
+ const stats = fs19.statSync(inputPath);
13455
14543
  if (stats.isFile()) {
13456
14544
  if (filter) {
13457
14545
  const filterExts = filter.split(",").map((e) => e.trim().toLowerCase());
13458
- const ext = path11.extname(inputPath).slice(1).toLowerCase();
14546
+ const ext = path14.extname(inputPath).slice(1).toLowerCase();
13459
14547
  if (!filterExts.includes(ext)) {
13460
14548
  return [];
13461
14549
  }
@@ -13463,21 +14551,21 @@ function resolveFilesToUpload(inputPath, filter) {
13463
14551
  return [inputPath];
13464
14552
  }
13465
14553
  if (stats.isDirectory()) {
13466
- const entries = fs15.readdirSync(inputPath);
14554
+ const entries = fs19.readdirSync(inputPath);
13467
14555
  const filterExts = filter?.split(",").map((e) => e.trim().toLowerCase());
13468
- const files = entries.map((e) => path11.join(inputPath, e)).filter((p) => {
14556
+ const files = entries.map((e) => path14.join(inputPath, e)).filter((p) => {
13469
14557
  try {
13470
- return fs15.statSync(p).isFile();
14558
+ return fs19.statSync(p).isFile();
13471
14559
  } catch {
13472
14560
  return false;
13473
14561
  }
13474
14562
  }).filter((p) => {
13475
14563
  if (!filterExts) return true;
13476
- const ext = path11.extname(p).slice(1).toLowerCase();
14564
+ const ext = path14.extname(p).slice(1).toLowerCase();
13477
14565
  return filterExts.includes(ext);
13478
14566
  }).sort((a, b) => {
13479
14567
  try {
13480
- return fs15.statSync(a).size - fs15.statSync(b).size;
14568
+ return fs19.statSync(a).size - fs19.statSync(b).size;
13481
14569
  } catch {
13482
14570
  return 0;
13483
14571
  }
@@ -13581,7 +14669,7 @@ var skillGetCommand = new Command("get").description("Get skill package details"
13581
14669
 
13582
14670
  // src/commands/skill/create.ts
13583
14671
  init_cjs_shims();
13584
- var fs16 = __toESM(require("fs"));
14672
+ var fs20 = __toESM(require("fs"));
13585
14673
  init_symlink();
13586
14674
  init_paths();
13587
14675
  init_logger();
@@ -13633,7 +14721,7 @@ var skillCreateCommand = new Command("create").description("Create a new skill p
13633
14721
  const localName = options.name.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "");
13634
14722
  const skillDir = getReflyDomainSkillDir(localName);
13635
14723
  const symlinkStatus = isSkillSymlinkValid(localName);
13636
- if (fs16.existsSync(skillDir) || symlinkStatus.exists) {
14724
+ if (fs20.existsSync(skillDir) || symlinkStatus.exists) {
13637
14725
  logger.debug(`Local skill '${localName}' already exists, skipping sync`);
13638
14726
  } else {
13639
14727
  const skillMdContent = generateReflySkillMd({
@@ -13695,8 +14783,8 @@ var skillCreateCommand = new Command("create").description("Create a new skill p
13695
14783
 
13696
14784
  // src/commands/skill/update.ts
13697
14785
  init_cjs_shims();
13698
- var fs17 = __toESM(require("fs"));
13699
- var path12 = __toESM(require("path"));
14786
+ var fs21 = __toESM(require("fs"));
14787
+ var path15 = __toESM(require("path"));
13700
14788
  init_paths();
13701
14789
  init_symlink();
13702
14790
  var MIN_DESCRIPTION_WORDS = 20;
@@ -13726,8 +14814,8 @@ var skillUpdateCommand = new Command("update").description("Update skill install
13726
14814
  try {
13727
14815
  const name = options.name;
13728
14816
  const skillDir = getReflyDomainSkillDir(name);
13729
- const skillMdPath = path12.join(skillDir, "SKILL.md");
13730
- if (!fs17.existsSync(skillMdPath)) {
14817
+ const skillMdPath = path15.join(skillDir, "SKILL.md");
14818
+ if (!fs21.existsSync(skillMdPath)) {
13731
14819
  const skillsDir = getReflySkillsDir();
13732
14820
  fail(ErrorCodes.NOT_FOUND, `SKILL.md not found at ${skillMdPath}`, {
13733
14821
  hint: `Make sure the skill '${name}' exists in ${skillsDir}/
@@ -13736,7 +14824,7 @@ To see installed skills: refly skill list`
13736
14824
  });
13737
14825
  return;
13738
14826
  }
13739
- const skillContent = fs17.readFileSync(skillMdPath, "utf-8");
14827
+ const skillContent = fs21.readFileSync(skillMdPath, "utf-8");
13740
14828
  let meta;
13741
14829
  try {
13742
14830
  const parsed = parseReflySkillMd(skillContent);
@@ -13819,8 +14907,8 @@ To see installed skills: refly skill list`
13819
14907
 
13820
14908
  // src/commands/skill/publish.ts
13821
14909
  init_cjs_shims();
13822
- var fs18 = __toESM(require("fs"));
13823
- var path13 = __toESM(require("path"));
14910
+ var fs22 = __toESM(require("fs"));
14911
+ var path16 = __toESM(require("path"));
13824
14912
  init_symlink();
13825
14913
  init_paths();
13826
14914
  var skillPublishCommand = new Command("publish").description("Publish a skill package using local SKILL.md").requiredOption("--name <name>", "Local skill name (directory in ~/.refly/skills/)").action(async (options) => {
@@ -13828,8 +14916,8 @@ var skillPublishCommand = new Command("publish").description("Publish a skill pa
13828
14916
  const skillsDir = getReflySkillsDir();
13829
14917
  const name = options.name;
13830
14918
  const skillDir = getReflyDomainSkillDir(name);
13831
- const skillMdPath = path13.join(skillDir, "SKILL.md");
13832
- if (!fs18.existsSync(skillMdPath)) {
14919
+ const skillMdPath = path16.join(skillDir, "SKILL.md");
14920
+ if (!fs22.existsSync(skillMdPath)) {
13833
14921
  fail(ErrorCodes.NOT_FOUND, `SKILL.md not found at ${skillMdPath}`, {
13834
14922
  hint: `Make sure the skill '${name}' exists in ${skillsDir}/
13835
14923
 
@@ -13838,7 +14926,7 @@ To create a new skill: refly skill create --name "${name}" --workflow-query "...
13838
14926
  });
13839
14927
  return;
13840
14928
  }
13841
- const skillContent = fs18.readFileSync(skillMdPath, "utf-8");
14929
+ const skillContent = fs22.readFileSync(skillMdPath, "utf-8");
13842
14930
  let parsedSkill;
13843
14931
  try {
13844
14932
  parsedSkill = parseReflySkillMd(skillContent);
@@ -13900,8 +14988,8 @@ To find available skills: refly skill list`
13900
14988
 
13901
14989
  // src/commands/skill/unpublish.ts
13902
14990
  init_cjs_shims();
13903
- var fs19 = __toESM(require("fs"));
13904
- var path14 = __toESM(require("path"));
14991
+ var fs23 = __toESM(require("fs"));
14992
+ var path17 = __toESM(require("path"));
13905
14993
  init_symlink();
13906
14994
  init_paths();
13907
14995
  var skillUnpublishCommand = new Command("unpublish").description("Unpublish a skill package to make it private").option("--id <skillId>", "Skill ID (skp-xxx)").option("--name <name>", "Local skill name (directory in ~/.refly/skills/)").action(async (options) => {
@@ -13936,8 +15024,8 @@ To find your skill name:
13936
15024
  return;
13937
15025
  }
13938
15026
  const skillDir = getReflyDomainSkillDir(name);
13939
- const skillMdPath = path14.join(skillDir, "SKILL.md");
13940
- if (!fs19.existsSync(skillMdPath)) {
15027
+ const skillMdPath = path17.join(skillDir, "SKILL.md");
15028
+ if (!fs23.existsSync(skillMdPath)) {
13941
15029
  fail(ErrorCodes.NOT_FOUND, `SKILL.md not found at ${skillMdPath}`, {
13942
15030
  hint: `Make sure the skill '${name}' exists in ${skillsDir}/
13943
15031
 
@@ -13945,7 +15033,7 @@ To see installed skills: refly skill list`
13945
15033
  });
13946
15034
  return;
13947
15035
  }
13948
- const skillContent = fs19.readFileSync(skillMdPath, "utf-8");
15036
+ const skillContent = fs23.readFileSync(skillMdPath, "utf-8");
13949
15037
  try {
13950
15038
  const { meta } = parseReflySkillMd(skillContent);
13951
15039
  skillId = options.id || meta.skillId;
@@ -13989,8 +15077,8 @@ To see installed skills: refly skill list`
13989
15077
 
13990
15078
  // src/commands/skill/run.ts
13991
15079
  init_cjs_shims();
13992
- var fs20 = __toESM(require("fs"));
13993
- var path15 = __toESM(require("path"));
15080
+ var fs24 = __toESM(require("fs"));
15081
+ var path18 = __toESM(require("path"));
13994
15082
  init_symlink();
13995
15083
  init_paths();
13996
15084
  var skillRunCommand = new Command("run").description("Run an installed skill").option("--id <installationId>", "Installation ID (skpi-xxx)").option("--name <name>", "Local skill name (directory in ~/.refly/skills/)").option("--input <json>", "Input JSON for the skill").option("--workflow <skillWorkflowId>", "Run specific workflow only").option("--async", "Run asynchronously").option("--no-prompt", "Disable interactive prompts (fail if required variables are missing)").action(async (options) => {
@@ -14015,8 +15103,8 @@ To find your skill name:
14015
15103
  if (options.name) {
14016
15104
  name = options.name;
14017
15105
  const skillDir = getReflyDomainSkillDir(options.name);
14018
- const skillMdPath = path15.join(skillDir, "SKILL.md");
14019
- if (!fs20.existsSync(skillMdPath)) {
15106
+ const skillMdPath = path18.join(skillDir, "SKILL.md");
15107
+ if (!fs24.existsSync(skillMdPath)) {
14020
15108
  fail(ErrorCodes.NOT_FOUND, `SKILL.md not found at ${skillMdPath}`, {
14021
15109
  hint: `Make sure the skill '${name}' exists in ${skillsDir}/
14022
15110
 
@@ -14025,7 +15113,7 @@ To install a skill: refly skill install <skillId>`
14025
15113
  });
14026
15114
  return;
14027
15115
  }
14028
- const skillContent = fs20.readFileSync(skillMdPath, "utf-8");
15116
+ const skillContent = fs24.readFileSync(skillMdPath, "utf-8");
14029
15117
  try {
14030
15118
  const { meta } = parseReflySkillMd(skillContent);
14031
15119
  skillId = meta.skillId;
@@ -14143,24 +15231,24 @@ To install: refly skill install ${meta.skillId}`
14143
15231
 
14144
15232
  // src/commands/skill/stop.ts
14145
15233
  init_cjs_shims();
14146
- var fs21 = __toESM(require("fs"));
14147
- var path16 = __toESM(require("path"));
15234
+ var fs25 = __toESM(require("fs"));
15235
+ var path19 = __toESM(require("path"));
14148
15236
  init_symlink();
14149
15237
  init_paths();
14150
15238
  function getLocalSkillNames() {
14151
15239
  const skillsDir = getReflySkillsDir();
14152
- if (!fs21.existsSync(skillsDir)) {
15240
+ if (!fs25.existsSync(skillsDir)) {
14153
15241
  return [];
14154
15242
  }
14155
- return fs21.readdirSync(skillsDir, { withFileTypes: true }).filter((dirent) => dirent.isDirectory()).map((dirent) => dirent.name);
15243
+ return fs25.readdirSync(skillsDir, { withFileTypes: true }).filter((dirent) => dirent.isDirectory()).map((dirent) => dirent.name);
14156
15244
  }
14157
15245
  var skillStopCommand = new Command("stop").description("Stop running skill executions").requiredOption("--name <name>", "Local skill name (directory in ~/.refly/skills/)").action(async (options) => {
14158
15246
  try {
14159
15247
  const skillsDir = getReflySkillsDir();
14160
15248
  const name = options.name;
14161
15249
  const skillDir = getReflyDomainSkillDir(name);
14162
- const skillMdPath = path16.join(skillDir, "SKILL.md");
14163
- if (!fs21.existsSync(skillMdPath)) {
15250
+ const skillMdPath = path19.join(skillDir, "SKILL.md");
15251
+ if (!fs25.existsSync(skillMdPath)) {
14164
15252
  const availableSkills = getLocalSkillNames();
14165
15253
  const skillList = availableSkills.length > 0 ? availableSkills.join(", ") : "(no skills installed)";
14166
15254
  fail(ErrorCodes.NOT_FOUND, `Skill "${name}" not found`, {
@@ -14169,7 +15257,7 @@ var skillStopCommand = new Command("stop").description("Stop running skill execu
14169
15257
  Skills directory: ${skillsDir}`
14170
15258
  });
14171
15259
  }
14172
- const skillContent = fs21.readFileSync(skillMdPath, "utf-8");
15260
+ const skillContent = fs25.readFileSync(skillMdPath, "utf-8");
14173
15261
  let installationId;
14174
15262
  try {
14175
15263
  const { meta } = parseReflySkillMd(skillContent);
@@ -14297,7 +15385,7 @@ var skillInstallCommand = new Command("install").description("Install a skill pa
14297
15385
  }
14298
15386
  );
14299
15387
  let localPath;
14300
- let symlinkPath;
15388
+ const platformResults = [];
14301
15389
  const skillName = result.skillPackage?.name;
14302
15390
  const workflowId = result.skillPackage?.workflowId;
14303
15391
  if (skillName && workflowId) {
@@ -14315,15 +15403,23 @@ var skillInstallCommand = new Command("install").description("Install a skill pa
14315
15403
  inputSchema: result.skillPackage?.inputSchema,
14316
15404
  outputSchema: result.skillPackage?.outputSchema
14317
15405
  });
14318
- const symlinkResult = createReflySkillWithSymlink(skillName, skillMdContent, {
15406
+ const deployResult = await createMultiPlatformSkill(skillName, skillMdContent, {
14319
15407
  force: options.force
14320
15408
  });
14321
- if (symlinkResult.success) {
14322
- localPath = symlinkResult.reflyPath;
14323
- symlinkPath = symlinkResult.claudePath;
14324
- logger.info(`Created local skill: ${localPath}`);
15409
+ localPath = deployResult.sourcePath;
15410
+ for (const [agentName, agentResult] of deployResult.results) {
15411
+ platformResults.push({
15412
+ agent: agentName,
15413
+ success: agentResult.success,
15414
+ path: agentResult.deployedPath || void 0
15415
+ });
15416
+ }
15417
+ if (deployResult.successCount > 0) {
15418
+ logger.info(
15419
+ `Created local skill: ${localPath}, deployed to ${deployResult.successCount} platform(s)`
15420
+ );
14325
15421
  } else {
14326
- logger.warn(`Failed to create local skill: ${symlinkResult.error}`);
15422
+ logger.warn("Failed to deploy skill to any platform");
14327
15423
  }
14328
15424
  } catch (err) {
14329
15425
  logger.warn(`Failed to create local skill: ${err.message}`);
@@ -14338,7 +15434,7 @@ var skillInstallCommand = new Command("install").description("Install a skill pa
14338
15434
  config: result.userConfig,
14339
15435
  installedAt: result.createdAt,
14340
15436
  localPath,
14341
- symlinkPath
15437
+ platforms: platformResults.length > 0 ? platformResults : void 0
14342
15438
  });
14343
15439
  } catch (error) {
14344
15440
  if (error instanceof CLIError) {
@@ -14358,8 +15454,8 @@ var skillInstallCommand = new Command("install").description("Install a skill pa
14358
15454
 
14359
15455
  // src/commands/skill/uninstall.ts
14360
15456
  init_cjs_shims();
14361
- var fs22 = __toESM(require("fs"));
14362
- var path17 = __toESM(require("path"));
15457
+ var fs26 = __toESM(require("fs"));
15458
+ var path20 = __toESM(require("path"));
14363
15459
  init_symlink();
14364
15460
  init_paths();
14365
15461
  init_logger();
@@ -14396,8 +15492,8 @@ To find your skill name:
14396
15492
  return;
14397
15493
  }
14398
15494
  const skillDir = getReflyDomainSkillDir(name);
14399
- const skillMdPath = path17.join(skillDir, "SKILL.md");
14400
- if (!fs22.existsSync(skillMdPath)) {
15495
+ const skillMdPath = path20.join(skillDir, "SKILL.md");
15496
+ if (!fs26.existsSync(skillMdPath)) {
14401
15497
  fail(ErrorCodes.NOT_FOUND, `SKILL.md not found at ${skillMdPath}`, {
14402
15498
  hint: `Make sure the skill '${name}' exists in ${skillsDir}/
14403
15499
 
@@ -14405,7 +15501,7 @@ To see installed skills: refly skill list`
14405
15501
  });
14406
15502
  return;
14407
15503
  }
14408
- const skillContent = fs22.readFileSync(skillMdPath, "utf-8");
15504
+ const skillContent = fs26.readFileSync(skillMdPath, "utf-8");
14409
15505
  try {
14410
15506
  const { meta } = parseReflySkillMd(skillContent);
14411
15507
  skillId = meta.skillId;
@@ -14436,14 +15532,21 @@ To see installed skills: refly skill list`
14436
15532
  }
14437
15533
  }
14438
15534
  }
14439
- let symlinkRemoved = false;
14440
15535
  let directoryRemoved = false;
15536
+ const platformResults = [];
14441
15537
  if (name && !options.keepLocal) {
14442
15538
  try {
14443
- const cleanup = deleteDomainSkillWithSymlink(name);
14444
- symlinkRemoved = cleanup.symlinkRemoved;
15539
+ const cleanup = await removeMultiPlatformSkill(name);
14445
15540
  directoryRemoved = cleanup.directoryRemoved;
14446
- logger.info(`Cleaned up local skill: ${name}`);
15541
+ for (const [agentName, result] of cleanup.platformResults.results) {
15542
+ platformResults.push({
15543
+ agent: agentName,
15544
+ success: result.success
15545
+ });
15546
+ }
15547
+ logger.info(
15548
+ `Cleaned up local skill: ${name}, removed from ${cleanup.platformResults.successCount} platform(s)`
15549
+ );
14447
15550
  } catch (err) {
14448
15551
  logger.warn(`Failed to clean up local skill: ${err.message}`);
14449
15552
  }
@@ -14454,8 +15557,8 @@ To see installed skills: refly skill list`
14454
15557
  installationId,
14455
15558
  uninstalled: true,
14456
15559
  localCleanup: {
14457
- symlinkRemoved,
14458
- directoryRemoved
15560
+ directoryRemoved,
15561
+ platforms: platformResults.length > 0 ? platformResults : void 0
14459
15562
  }
14460
15563
  });
14461
15564
  } catch (error) {
@@ -14521,8 +15624,8 @@ init_cjs_shims();
14521
15624
 
14522
15625
  // src/skill/loader.ts
14523
15626
  init_cjs_shims();
14524
- var fs23 = __toESM(require("fs"));
14525
- var path18 = __toESM(require("path"));
15627
+ var fs27 = __toESM(require("fs"));
15628
+ var path21 = __toESM(require("path"));
14526
15629
  var import_gray_matter = __toESM(require("gray-matter"));
14527
15630
  init_logger();
14528
15631
 
@@ -14702,23 +15805,23 @@ function extractSkillMetadata(content) {
14702
15805
 
14703
15806
  // src/commands/skill/validate.ts
14704
15807
  init_paths();
14705
- var fs24 = __toESM(require("fs"));
14706
- var path19 = __toESM(require("path"));
15808
+ var fs28 = __toESM(require("fs"));
15809
+ var path22 = __toESM(require("path"));
14707
15810
  var skillValidateCommand = new Command("validate").description("Validate local skill files").argument("[skillPath]", "Path to skill file or directory (defaults to ~/.refly/skills)").option("--fix", "Attempt to fix common issues").action(async (skillPath, _options) => {
14708
15811
  try {
14709
15812
  const results = [];
14710
15813
  let targetPath;
14711
15814
  if (skillPath) {
14712
- targetPath = path19.resolve(skillPath);
15815
+ targetPath = path22.resolve(skillPath);
14713
15816
  } else {
14714
15817
  await ensureSkillsDir();
14715
15818
  targetPath = getSkillsDir();
14716
15819
  }
14717
- if (!fs24.existsSync(targetPath)) {
15820
+ if (!fs28.existsSync(targetPath)) {
14718
15821
  fail(ErrorCodes.NOT_FOUND, `Path not found: ${targetPath}`);
14719
15822
  return;
14720
15823
  }
14721
- const stats = fs24.statSync(targetPath);
15824
+ const stats = fs28.statSync(targetPath);
14722
15825
  if (stats.isFile()) {
14723
15826
  const result = validateSkillFile(targetPath);
14724
15827
  results.push(result);
@@ -14751,7 +15854,7 @@ var skillValidateCommand = new Command("validate").description("Validate local s
14751
15854
  });
14752
15855
  function validateSkillFile(filePath) {
14753
15856
  try {
14754
- const content = fs24.readFileSync(filePath, "utf-8");
15857
+ const content = fs28.readFileSync(filePath, "utf-8");
14755
15858
  const { frontmatter, issues } = extractSkillMetadata(content);
14756
15859
  const errors = issues.map((i) => `${i.path}: ${i.message}`);
14757
15860
  const warnings = [];
@@ -14777,9 +15880,9 @@ function validateSkillFile(filePath) {
14777
15880
  }
14778
15881
  }
14779
15882
  function findSkillFiles(dir, files = []) {
14780
- const entries = fs24.readdirSync(dir, { withFileTypes: true });
15883
+ const entries = fs28.readdirSync(dir, { withFileTypes: true });
14781
15884
  for (const entry of entries) {
14782
- const fullPath = path19.join(dir, entry.name);
15885
+ const fullPath = path22.join(dir, entry.name);
14783
15886
  if (entry.isDirectory()) {
14784
15887
  if (!entry.name.startsWith(".")) {
14785
15888
  findSkillFiles(fullPath, files);
@@ -14793,12 +15896,73 @@ function findSkillFiles(dir, files = []) {
14793
15896
 
14794
15897
  // src/commands/skill/sync.ts
14795
15898
  init_cjs_shims();
15899
+ var fs29 = __toESM(require("fs"));
15900
+ var path23 = __toESM(require("path"));
14796
15901
  init_symlink();
15902
+ init_manager();
15903
+ init_registry();
14797
15904
  init_paths();
14798
- var fs25 = __toESM(require("fs"));
14799
- var path20 = __toESM(require("path"));
14800
- var skillSyncCommand = new Command("sync").description("Validate and repair skill symlinks").option("--dry-run", "Show issues without making changes").option("--fix", "Attempt to repair broken symlinks").option("--prune", "Remove orphan symlinks (symlinks without source directory)").action(async (options) => {
15905
+ var skillSyncCommand = new Command("sync").description("Validate and repair skill symlinks across all platforms").option("--dry-run", "Show issues without making changes").option("--fix", "Attempt to repair broken symlinks").option("--prune", "Remove orphan symlinks (symlinks without source directory)").option("--platform <platforms...>", "Sync to specific platforms only (comma-separated)").option("--all-platforms", "Sync to all installed platforms (not just Claude Code)").action(async (options) => {
14801
15906
  try {
15907
+ let targetAgents;
15908
+ if (options.platform) {
15909
+ const platformList = options.platform.flatMap((p) => p.split(","));
15910
+ targetAgents = [];
15911
+ for (const platform4 of platformList) {
15912
+ const trimmed = platform4.trim();
15913
+ if (!isValidAgentType(trimmed)) {
15914
+ return fail(ErrorCodes.INVALID_INPUT, `Unknown platform: ${trimmed}`, {
15915
+ hint: `Valid platforms: ${Object.keys(agents).join(", ")}`
15916
+ });
15917
+ }
15918
+ targetAgents.push(trimmed);
15919
+ }
15920
+ }
15921
+ if (options.allPlatforms) {
15922
+ const installedAgents = await detectInstalledAgents();
15923
+ const deployableAgents = installedAgents.filter((a) => a.format !== "unknown");
15924
+ const skillsDir2 = getReflySkillsDir();
15925
+ const baseSkillDir = getReflyBaseSkillDir();
15926
+ const skillsToSync = [];
15927
+ if (fs29.existsSync(baseSkillDir)) {
15928
+ skillsToSync.push("refly");
15929
+ }
15930
+ if (fs29.existsSync(skillsDir2)) {
15931
+ const entries = fs29.readdirSync(skillsDir2, { withFileTypes: true });
15932
+ for (const entry of entries) {
15933
+ if (entry.isDirectory() && entry.name !== "base") {
15934
+ skillsToSync.push(entry.name);
15935
+ }
15936
+ }
15937
+ }
15938
+ const platformResults = [];
15939
+ for (const skillName of skillsToSync) {
15940
+ const { needsSync, synced } = await syncSkillToAllPlatforms(skillName, {
15941
+ agents: targetAgents,
15942
+ dryRun: options.dryRun
15943
+ });
15944
+ platformResults.push({
15945
+ skillName,
15946
+ needsSync: Array.from(needsSync.entries()).map(([agent, status]) => ({
15947
+ agent,
15948
+ deployed: status.deployed,
15949
+ valid: status.valid
15950
+ })),
15951
+ synced: Array.from(synced.entries()).map(([agent, result]) => ({
15952
+ agent,
15953
+ success: result.success,
15954
+ path: result.deployedPath || void 0
15955
+ }))
15956
+ });
15957
+ }
15958
+ return ok("skill.sync", {
15959
+ dryRun: Boolean(options.dryRun),
15960
+ allPlatforms: true,
15961
+ installedAgents: deployableAgents.map((a) => a.name),
15962
+ skillsCount: skillsToSync.length,
15963
+ results: platformResults
15964
+ });
15965
+ }
14802
15966
  const symlinks = listSkillSymlinks();
14803
15967
  const warnings = [];
14804
15968
  const errors = [];
@@ -14823,14 +15987,14 @@ var skillSyncCommand = new Command("sync").description("Validate and repair skil
14823
15987
  }
14824
15988
  }
14825
15989
  const skillsDir = getReflySkillsDir();
14826
- if (fs25.existsSync(skillsDir)) {
14827
- const entries = fs25.readdirSync(skillsDir, { withFileTypes: true });
15990
+ if (fs29.existsSync(skillsDir)) {
15991
+ const entries = fs29.readdirSync(skillsDir, { withFileTypes: true });
14828
15992
  const symlinkNames = new Set(symlinks.map((s) => s.name));
14829
15993
  for (const entry of entries) {
14830
15994
  if (entry.isDirectory() && entry.name !== "base") {
14831
15995
  if (!symlinkNames.has(entry.name)) {
14832
15996
  orphans += 1;
14833
- warnings.push(`Orphan directory (no symlink): ${path20.join(skillsDir, entry.name)}`);
15997
+ warnings.push(`Orphan directory (no symlink): ${path23.join(skillsDir, entry.name)}`);
14834
15998
  if (options.prune && !options.dryRun) {
14835
15999
  const result = createSkillSymlink(entry.name);
14836
16000
  if (result.success) {
@@ -14877,11 +16041,178 @@ var skillSyncCommand = new Command("sync").description("Validate and repair skil
14877
16041
  // src/commands/skill/index.ts
14878
16042
  var skillCommand = new Command("skill").description("Manage skill packages and local skills").addCommand(skillListCommand).addCommand(skillGetCommand).addCommand(skillCreateCommand).addCommand(skillUpdateCommand).addCommand(skillPublishCommand).addCommand(skillUnpublishCommand).addCommand(skillSearchCommand).addCommand(skillInstallCommand).addCommand(skillUninstallCommand).addCommand(skillInstallationsCommand).addCommand(skillRunCommand).addCommand(skillStopCommand).addCommand(skillValidateCommand).addCommand(skillSyncCommand);
14879
16043
 
16044
+ // src/commands/platform/index.ts
16045
+ init_cjs_shims();
16046
+
16047
+ // src/commands/platform/sync.ts
16048
+ init_cjs_shims();
16049
+ var fs30 = __toESM(require("fs"));
16050
+ init_manager();
16051
+ init_registry();
16052
+ init_paths();
16053
+ var platformSyncCommand = new Command("sync").description("Detect installed agents and sync skills to all platforms").option("--agent <agents...>", "Specific agents to sync to (comma-separated)").option("--dry-run", "Show what would be done without making changes").option("--yes", "Skip confirmation prompts").action(async (options) => {
16054
+ try {
16055
+ const pretty = isPrettyOutput();
16056
+ const tty = isTTY();
16057
+ let targetAgents;
16058
+ if (options.agent) {
16059
+ const agentList = options.agent.flatMap((a) => a.split(","));
16060
+ const validatedAgents = [];
16061
+ for (const agent of agentList) {
16062
+ const trimmed = agent.trim();
16063
+ if (!isValidAgentType(trimmed)) {
16064
+ return fail(ErrorCodes.INVALID_INPUT, `Unknown agent: ${trimmed}`, {
16065
+ hint: `Valid agents: ${Object.keys(agents).join(", ")}`
16066
+ });
16067
+ }
16068
+ validatedAgents.push(trimmed);
16069
+ }
16070
+ targetAgents = validatedAgents;
16071
+ }
16072
+ if (pretty && tty) {
16073
+ println("Scanning for installed agents...");
16074
+ println("");
16075
+ }
16076
+ const installedAgents = targetAgents ? targetAgents.map((name) => agents[name]) : await detectInstalledAgents();
16077
+ const deployableAgents = installedAgents.filter((a) => a.format !== "unknown");
16078
+ if (deployableAgents.length === 0) {
16079
+ if (pretty && tty) {
16080
+ printError2("No supported agents found");
16081
+ printDim("Install an AI coding assistant and try again.");
16082
+ } else {
16083
+ ok("platform.sync", {
16084
+ message: "No supported agents found",
16085
+ installedAgents: [],
16086
+ skillsSynced: 0
16087
+ });
16088
+ }
16089
+ return;
16090
+ }
16091
+ if (pretty && tty) {
16092
+ println(`Found ${deployableAgents.length} installed agent(s):`);
16093
+ for (const agent of deployableAgents) {
16094
+ const dir = agent.globalSkillsDir || agent.skillsDir || "N/A";
16095
+ println(` \u2713 ${agent.displayName.padEnd(16)} ${dir}`);
16096
+ }
16097
+ println("");
16098
+ }
16099
+ const skillsDir = getReflySkillsDir();
16100
+ const baseSkillDir = getReflyBaseSkillDir();
16101
+ const skillsToSync = [];
16102
+ if (fs30.existsSync(baseSkillDir)) {
16103
+ skillsToSync.push("refly");
16104
+ }
16105
+ if (fs30.existsSync(skillsDir)) {
16106
+ const entries = fs30.readdirSync(skillsDir, { withFileTypes: true });
16107
+ for (const entry of entries) {
16108
+ if (entry.isDirectory() && entry.name !== "base") {
16109
+ skillsToSync.push(entry.name);
16110
+ }
16111
+ }
16112
+ }
16113
+ if (skillsToSync.length === 0) {
16114
+ if (pretty && tty) {
16115
+ printDim("No skills found to sync.");
16116
+ printDim("Run `refly init` to install the base skill.");
16117
+ } else {
16118
+ ok("platform.sync", {
16119
+ message: "No skills found to sync",
16120
+ installedAgents: deployableAgents.map((a) => a.name),
16121
+ skillsSynced: 0
16122
+ });
16123
+ }
16124
+ return;
16125
+ }
16126
+ if (pretty && tty) {
16127
+ println(`Syncing ${skillsToSync.length} skill(s) to all installed agents...`);
16128
+ }
16129
+ if (options.dryRun) {
16130
+ if (pretty && tty) {
16131
+ println("");
16132
+ println("Dry run - no changes made:");
16133
+ for (const skillName of skillsToSync) {
16134
+ const agentNames = deployableAgents.map((a) => a.displayName).join(", ");
16135
+ println(` ${skillName} -> ${agentNames}`);
16136
+ }
16137
+ } else {
16138
+ ok("platform.sync", {
16139
+ dryRun: true,
16140
+ installedAgents: deployableAgents.map((a) => a.name),
16141
+ skillsToSync
16142
+ });
16143
+ }
16144
+ return;
16145
+ }
16146
+ const results = [];
16147
+ for (const skillName of skillsToSync) {
16148
+ const deployResult = await deploySkillToAllPlatforms(skillName, {
16149
+ force: true,
16150
+ // Force to ensure repair
16151
+ agents: targetAgents
16152
+ });
16153
+ const details = [];
16154
+ for (const [agentName, result] of deployResult.results) {
16155
+ details.push({
16156
+ agent: agentName,
16157
+ success: result.success,
16158
+ path: result.deployedPath || void 0,
16159
+ error: result.error
16160
+ });
16161
+ }
16162
+ results.push({
16163
+ skillName,
16164
+ success: deployResult.successCount,
16165
+ failed: deployResult.failureCount,
16166
+ details
16167
+ });
16168
+ if (pretty && tty) {
16169
+ const statusParts = deployableAgents.map((agent) => {
16170
+ const result = deployResult.results.get(agent.name);
16171
+ return result?.success ? "\u2713" : "\u2717";
16172
+ });
16173
+ println(` ${skillName.padEnd(20)} ${statusParts.join(" ")}`);
16174
+ }
16175
+ }
16176
+ const totalSuccess = results.reduce((sum, r) => sum + r.success, 0);
16177
+ const totalFailed = results.reduce((sum, r) => sum + r.failed, 0);
16178
+ if (pretty && tty) {
16179
+ println("");
16180
+ printSuccess(
16181
+ `Done! ${deployableAgents.length} agent(s), ${skillsToSync.length} skill(s) synced.`
16182
+ );
16183
+ if (totalFailed > 0) {
16184
+ printError2(`${totalFailed} deployment(s) failed. Check logs for details.`);
16185
+ }
16186
+ } else {
16187
+ ok("platform.sync", {
16188
+ installedAgents: deployableAgents.map((a) => ({
16189
+ name: a.name,
16190
+ displayName: a.displayName,
16191
+ format: a.format,
16192
+ globalSkillsDir: a.globalSkillsDir
16193
+ })),
16194
+ skillsSynced: skillsToSync.length,
16195
+ totalSuccess,
16196
+ totalFailed,
16197
+ results
16198
+ });
16199
+ }
16200
+ } catch (error) {
16201
+ fail(
16202
+ ErrorCodes.INTERNAL_ERROR,
16203
+ error instanceof Error ? error.message : "Failed to sync platforms"
16204
+ );
16205
+ }
16206
+ });
16207
+
16208
+ // src/commands/platform/index.ts
16209
+ var platformCommand = new Command("platform").description("Manage multi-platform skill deployment").addCommand(platformSyncCommand);
16210
+
14880
16211
  // src/bin/refly.ts
14881
16212
  function getVersion() {
14882
16213
  try {
14883
- const pkgPath = path21.join(__dirname, "..", "..", "package.json");
14884
- const pkg = JSON.parse(fs26.readFileSync(pkgPath, "utf-8"));
16214
+ const pkgPath = path24.join(__dirname, "..", "..", "package.json");
16215
+ const pkg = JSON.parse(fs31.readFileSync(pkgPath, "utf-8"));
14885
16216
  return pkg.version || "0.1.0";
14886
16217
  } catch {
14887
16218
  return "0.1.0";
@@ -14922,6 +16253,7 @@ program2.addCommand(workflowCommand);
14922
16253
  program2.addCommand(toolCommand);
14923
16254
  program2.addCommand(fileCommand);
14924
16255
  program2.addCommand(skillCommand);
16256
+ program2.addCommand(platformCommand);
14925
16257
  program2.exitOverride((err) => {
14926
16258
  if (err.code === "commander.helpDisplayed" || err.code === "commander.version") {
14927
16259
  process.exit(0);