@powerformer/refly-cli 0.1.23 → 0.1.24

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/bin/refly.js 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,18 @@ 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.replace(/[\x00-\x08\x0B\x0C\x0E-\x1F]/g, "");
5251
+ }
5252
+ return value;
5253
+ };
4308
5254
  // === Pretty Format ===
4309
5255
  outputPretty(type, payload) {
4310
5256
  if (type === "workflow.status" || type === "workflow.progress") {
@@ -4893,8 +5839,8 @@ var ErrorCodes = {
4893
5839
  };
4894
5840
 
4895
5841
  // src/bin/refly.ts
4896
- var fs26 = __toESM(require("fs"));
4897
- var path21 = __toESM(require("path"));
5842
+ var fs31 = __toESM(require("fs"));
5843
+ var path24 = __toESM(require("path"));
4898
5844
 
4899
5845
  // src/commands/init.ts
4900
5846
  init_cjs_shims();
@@ -5399,8 +6345,8 @@ function getErrorMap() {
5399
6345
  // ../../node_modules/.pnpm/zod@3.25.76/node_modules/zod/v3/helpers/parseUtil.js
5400
6346
  init_cjs_shims();
5401
6347
  var makeIssue = (params) => {
5402
- const { data, path: path22, errorMaps, issueData } = params;
5403
- const fullPath = [...path22, ...issueData.path || []];
6348
+ const { data, path: path25, errorMaps, issueData } = params;
6349
+ const fullPath = [...path25, ...issueData.path || []];
5404
6350
  const fullIssue = {
5405
6351
  ...issueData,
5406
6352
  path: fullPath
@@ -5520,11 +6466,11 @@ var errorUtil;
5520
6466
 
5521
6467
  // ../../node_modules/.pnpm/zod@3.25.76/node_modules/zod/v3/types.js
5522
6468
  var ParseInputLazyPath = class {
5523
- constructor(parent, value, path22, key) {
6469
+ constructor(parent, value, path25, key) {
5524
6470
  this._cachedPath = [];
5525
6471
  this.parent = parent;
5526
6472
  this.data = value;
5527
- this._path = path22;
6473
+ this._path = path25;
5528
6474
  this._key = key;
5529
6475
  }
5530
6476
  get path() {
@@ -8968,6 +9914,23 @@ var NEVER = INVALID;
8968
9914
 
8969
9915
  // src/config/config.ts
8970
9916
  init_paths();
9917
+ var AgentTypeEnum = external_exports.enum([
9918
+ "claude-code",
9919
+ "codex",
9920
+ "antigravity",
9921
+ "github-copilot",
9922
+ "windsurf",
9923
+ "opencode",
9924
+ "moltbot",
9925
+ "cursor",
9926
+ "continue",
9927
+ "trae",
9928
+ "qoder"
9929
+ ]);
9930
+ var PlatformConfigSchema = external_exports.object({
9931
+ enabled: external_exports.boolean().default(true),
9932
+ globalPath: external_exports.string().optional()
9933
+ });
8971
9934
  var ConfigSchema = external_exports.object({
8972
9935
  version: external_exports.number().default(1),
8973
9936
  auth: external_exports.object({
@@ -8995,7 +9958,9 @@ var ConfigSchema = external_exports.object({
8995
9958
  skill: external_exports.object({
8996
9959
  installedVersion: external_exports.string().optional(),
8997
9960
  installedAt: external_exports.string().optional()
8998
- }).optional()
9961
+ }).optional(),
9962
+ // Multi-platform configuration
9963
+ platforms: external_exports.record(AgentTypeEnum, PlatformConfigSchema).optional()
8999
9964
  });
9000
9965
  var DEFAULT_API_ENDPOINT = "https://api.refly.ai";
9001
9966
  var DEFAULT_WEB_URL = "https://refly.ai";
@@ -9132,22 +10097,22 @@ init_paths();
9132
10097
 
9133
10098
  // src/skill/installer.ts
9134
10099
  init_cjs_shims();
9135
- var fs5 = __toESM(require("fs"));
9136
- var path5 = __toESM(require("path"));
10100
+ var fs9 = __toESM(require("fs"));
10101
+ var path8 = __toESM(require("path"));
9137
10102
  init_paths();
9138
10103
  init_logger();
9139
10104
  init_symlink();
9140
10105
  function removeOldSkillDirectory() {
9141
10106
  const claudeSkillPath = getClaudeSkillSymlinkPath("refly");
9142
- if (!fs5.existsSync(claudeSkillPath)) {
10107
+ if (!fs9.existsSync(claudeSkillPath)) {
9143
10108
  return;
9144
10109
  }
9145
10110
  try {
9146
- const stat = fs5.lstatSync(claudeSkillPath);
10111
+ const stat = fs9.lstatSync(claudeSkillPath);
9147
10112
  if (stat.isSymbolicLink()) {
9148
- fs5.unlinkSync(claudeSkillPath);
10113
+ fs9.unlinkSync(claudeSkillPath);
9149
10114
  } else if (stat.isDirectory()) {
9150
- fs5.rmSync(claudeSkillPath, { recursive: true, force: true });
10115
+ fs9.rmSync(claudeSkillPath, { recursive: true, force: true });
9151
10116
  logger.info("Removed old skill directory");
9152
10117
  }
9153
10118
  } catch (err) {
@@ -9156,17 +10121,17 @@ function removeOldSkillDirectory() {
9156
10121
  }
9157
10122
  function getPackageSkillDir() {
9158
10123
  const possiblePaths = [
9159
- path5.join(__dirname, "..", "..", "skill"),
10124
+ path8.join(__dirname, "..", "..", "skill"),
9160
10125
  // Built package: dist/bin/../../skill
9161
- path5.join(__dirname, "..", "..", "..", "skill"),
10126
+ path8.join(__dirname, "..", "..", "..", "skill"),
9162
10127
  // Development: dist/bin/../../../skill
9163
- path5.join(__dirname, "..", "skill")
10128
+ path8.join(__dirname, "..", "skill")
9164
10129
  // Alternative: dist/../skill
9165
10130
  ];
9166
10131
  logger.debug("Looking for skill files, __dirname:", __dirname);
9167
10132
  for (const p of possiblePaths) {
9168
- const resolved = path5.resolve(p);
9169
- const exists = fs5.existsSync(resolved);
10133
+ const resolved = path8.resolve(p);
10134
+ const exists = fs9.existsSync(resolved);
9170
10135
  logger.debug(` Checking path: ${resolved} - exists: ${exists}`);
9171
10136
  if (exists) {
9172
10137
  return resolved;
@@ -9190,30 +10155,30 @@ function installSkill() {
9190
10155
  logger.debug("Target skill directory:", targetDir);
9191
10156
  try {
9192
10157
  ensureDir(targetDir);
9193
- ensureDir(path5.join(targetDir, "rules"));
10158
+ ensureDir(path8.join(targetDir, "rules"));
9194
10159
  logger.debug("Created target directories");
9195
10160
  } catch (err) {
9196
10161
  logger.error("Failed to create target directories:", err);
9197
10162
  throw err;
9198
10163
  }
9199
- const skillSource = path5.join(sourceDir, "SKILL.md");
9200
- const skillTarget = path5.join(targetDir, "SKILL.md");
10164
+ const skillSource = path8.join(sourceDir, "SKILL.md");
10165
+ const skillTarget = path8.join(targetDir, "SKILL.md");
9201
10166
  logger.debug(`Copying SKILL.md: ${skillSource} -> ${skillTarget}`);
9202
- if (fs5.existsSync(skillSource)) {
9203
- fs5.copyFileSync(skillSource, skillTarget);
10167
+ if (fs9.existsSync(skillSource)) {
10168
+ fs9.copyFileSync(skillSource, skillTarget);
9204
10169
  result.skillInstalled = true;
9205
10170
  result.skillPath = targetDir;
9206
10171
  logger.debug("SKILL.md copied successfully");
9207
10172
  } else {
9208
10173
  logger.warn("SKILL.md source not found:", skillSource);
9209
10174
  }
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);
10175
+ const refsSource = path8.join(sourceDir, "references");
10176
+ const rulesTarget = path8.join(targetDir, "rules");
10177
+ if (fs9.existsSync(refsSource)) {
10178
+ const files = fs9.readdirSync(refsSource);
9214
10179
  logger.debug(`Copying ${files.length} rule files`);
9215
10180
  for (const file of files) {
9216
- fs5.copyFileSync(path5.join(refsSource, file), path5.join(rulesTarget, file));
10181
+ fs9.copyFileSync(path8.join(refsSource, file), path8.join(rulesTarget, file));
9217
10182
  }
9218
10183
  }
9219
10184
  removeOldSkillDirectory();
@@ -9241,15 +10206,15 @@ function installSkill() {
9241
10206
  return result;
9242
10207
  }
9243
10208
  function installSlashCommands(sourceDir, targetDir) {
9244
- const commandsSource = path5.join(sourceDir, "..", "commands");
9245
- if (!fs5.existsSync(commandsSource)) {
10209
+ const commandsSource = path8.join(sourceDir, "..", "commands");
10210
+ if (!fs9.existsSync(commandsSource)) {
9246
10211
  return false;
9247
10212
  }
9248
10213
  try {
9249
- const files = fs5.readdirSync(commandsSource);
10214
+ const files = fs9.readdirSync(commandsSource);
9250
10215
  for (const file of files) {
9251
10216
  if (file.endsWith(".md")) {
9252
- fs5.copyFileSync(path5.join(commandsSource, file), path5.join(targetDir, file));
10217
+ fs9.copyFileSync(path8.join(commandsSource, file), path8.join(targetDir, file));
9253
10218
  }
9254
10219
  }
9255
10220
  return files.length > 0;
@@ -9259,8 +10224,8 @@ function installSlashCommands(sourceDir, targetDir) {
9259
10224
  }
9260
10225
  function getSkillVersion() {
9261
10226
  try {
9262
- const skillPath = path5.join(getPackageSkillDir(), "SKILL.md");
9263
- const content = fs5.readFileSync(skillPath, "utf-8");
10227
+ const skillPath = path8.join(getPackageSkillDir(), "SKILL.md");
10228
+ const content = fs9.readFileSync(skillPath, "utf-8");
9264
10229
  const versionMatch = content.match(/version:\s*(\d+\.\d+\.\d+)/);
9265
10230
  if (versionMatch) {
9266
10231
  return versionMatch[1];
@@ -9268,16 +10233,16 @@ function getSkillVersion() {
9268
10233
  } catch {
9269
10234
  }
9270
10235
  try {
9271
- const pkgPath = path5.join(__dirname, "..", "..", "package.json");
9272
- const pkg = JSON.parse(fs5.readFileSync(pkgPath, "utf-8"));
10236
+ const pkgPath = path8.join(__dirname, "..", "..", "package.json");
10237
+ const pkg = JSON.parse(fs9.readFileSync(pkgPath, "utf-8"));
9273
10238
  return pkg.version;
9274
10239
  } catch {
9275
10240
  return "0.1.0";
9276
10241
  }
9277
10242
  }
9278
10243
  function isSkillInstalled() {
9279
- const skillPath = path5.join(getReflyBaseSkillDir(), "SKILL.md");
9280
- if (!fs5.existsSync(skillPath)) {
10244
+ const skillPath = path8.join(getReflyBaseSkillDir(), "SKILL.md");
10245
+ if (!fs9.existsSync(skillPath)) {
9281
10246
  return { installed: false, upToDate: false };
9282
10247
  }
9283
10248
  const currentVersion = getSkillVersion();
@@ -9291,6 +10256,9 @@ function isSkillInstalled() {
9291
10256
  };
9292
10257
  }
9293
10258
 
10259
+ // src/commands/init.ts
10260
+ init_manager();
10261
+
9294
10262
  // src/utils/logo.ts
9295
10263
  init_cjs_shims();
9296
10264
  var REFLY_LOGO = `\u2588\u2580\u2588 \u2588\u2580\u2580 \u2588\u2580\u2580 \u2588 \u2588 \u2588 \u2588\u2580\u2588 \u2588
@@ -9349,7 +10317,7 @@ var import_promises = __toESM(require("fs/promises"), 1);
9349
10317
  // ../../node_modules/.pnpm/is-wsl@3.1.0/node_modules/is-wsl/index.js
9350
10318
  init_cjs_shims();
9351
10319
  var import_node_process = __toESM(require("process"), 1);
9352
- var import_node_os = __toESM(require("os"), 1);
10320
+ var import_node_os3 = __toESM(require("os"), 1);
9353
10321
  var import_node_fs3 = __toESM(require("fs"), 1);
9354
10322
 
9355
10323
  // ../../node_modules/.pnpm/is-inside-container@1.0.0/node_modules/is-inside-container/index.js
@@ -9404,7 +10372,7 @@ var isWsl = () => {
9404
10372
  if (import_node_process.default.platform !== "linux") {
9405
10373
  return false;
9406
10374
  }
9407
- if (import_node_os.default.release().toLowerCase().includes("microsoft")) {
10375
+ if (import_node_os3.default.release().toLowerCase().includes("microsoft")) {
9408
10376
  if (isInsideContainer()) {
9409
10377
  return false;
9410
10378
  }
@@ -9600,7 +10568,7 @@ async function defaultBrowser2() {
9600
10568
  var execFile5 = (0, import_node_util5.promisify)(import_node_child_process5.default.execFile);
9601
10569
  var __dirname2 = import_node_path.default.dirname((0, import_node_url.fileURLToPath)(importMetaUrl));
9602
10570
  var localXdgOpenPath = import_node_path.default.join(__dirname2, "xdg-open");
9603
- var { platform: platform2, arch } = import_node_process6.default;
10571
+ var { platform: platform3, arch } = import_node_process6.default;
9604
10572
  async function getWindowsDefaultBrowserFromWsl() {
9605
10573
  const powershellPath = await powerShellPath();
9606
10574
  const rawCommand = String.raw`(Get-ItemProperty -Path "HKCU:\Software\Microsoft\Windows\Shell\Associations\UrlAssociations\http\UserChoice").ProgId`;
@@ -9699,7 +10667,7 @@ var baseOpen = async (options) => {
9699
10667
  let command;
9700
10668
  const cliArguments = [];
9701
10669
  const childProcessOptions = {};
9702
- if (platform2 === "darwin") {
10670
+ if (platform3 === "darwin") {
9703
10671
  command = "open";
9704
10672
  if (options.wait) {
9705
10673
  cliArguments.push("--wait-apps");
@@ -9713,7 +10681,7 @@ var baseOpen = async (options) => {
9713
10681
  if (app) {
9714
10682
  cliArguments.push("-a", app);
9715
10683
  }
9716
- } else if (platform2 === "win32" || is_wsl_default && !isInsideContainer() && !app) {
10684
+ } else if (platform3 === "win32" || is_wsl_default && !isInsideContainer() && !app) {
9717
10685
  command = await powerShellPath();
9718
10686
  cliArguments.push(
9719
10687
  "-NoProfile",
@@ -9753,7 +10721,7 @@ var baseOpen = async (options) => {
9753
10721
  exeLocalXdgOpen = true;
9754
10722
  } catch {
9755
10723
  }
9756
- const useSystemXdgOpen = import_node_process6.default.versions.electron ?? (platform2 === "android" || isBundled || !exeLocalXdgOpen);
10724
+ const useSystemXdgOpen = import_node_process6.default.versions.electron ?? (platform3 === "android" || isBundled || !exeLocalXdgOpen);
9757
10725
  command = useSystemXdgOpen ? "xdg-open" : localXdgOpenPath;
9758
10726
  }
9759
10727
  if (appArguments.length > 0) {
@@ -9764,7 +10732,7 @@ var baseOpen = async (options) => {
9764
10732
  childProcessOptions.detached = true;
9765
10733
  }
9766
10734
  }
9767
- if (platform2 === "darwin" && appArguments.length > 0) {
10735
+ if (platform3 === "darwin" && appArguments.length > 0) {
9768
10736
  cliArguments.push("--args", ...appArguments);
9769
10737
  }
9770
10738
  if (options.target) {
@@ -9772,14 +10740,14 @@ var baseOpen = async (options) => {
9772
10740
  }
9773
10741
  const subprocess = import_node_child_process5.default.spawn(command, cliArguments, childProcessOptions);
9774
10742
  if (options.wait) {
9775
- return new Promise((resolve7, reject) => {
10743
+ return new Promise((resolve8, reject) => {
9776
10744
  subprocess.once("error", reject);
9777
10745
  subprocess.once("close", (exitCode) => {
9778
10746
  if (!options.allowNonzeroExitCode && exitCode > 0) {
9779
10747
  reject(new Error(`Exited with code ${exitCode}`));
9780
10748
  return;
9781
10749
  }
9782
- resolve7(subprocess);
10750
+ resolve8(subprocess);
9783
10751
  });
9784
10752
  });
9785
10753
  }
@@ -9805,12 +10773,12 @@ function detectArchBinary(binary) {
9805
10773
  }
9806
10774
  return archBinary;
9807
10775
  }
9808
- function detectPlatformBinary({ [platform2]: platformBinary }, { wsl }) {
10776
+ function detectPlatformBinary({ [platform3]: platformBinary }, { wsl }) {
9809
10777
  if (wsl && is_wsl_default) {
9810
10778
  return detectArchBinary(wsl);
9811
10779
  }
9812
10780
  if (!platformBinary) {
9813
- throw new Error(`${platform2} is not supported`);
10781
+ throw new Error(`${platform3} is not supported`);
9814
10782
  }
9815
10783
  return detectArchBinary(platformBinary);
9816
10784
  }
@@ -9855,9 +10823,9 @@ var open_default = open;
9855
10823
 
9856
10824
  // src/api/client.ts
9857
10825
  init_cjs_shims();
9858
- var fs11 = __toESM(require("fs"));
10826
+ var fs15 = __toESM(require("fs"));
9859
10827
  var import_node_fs4 = require("fs");
9860
- var path7 = __toESM(require("path"));
10828
+ var path10 = __toESM(require("path"));
9861
10829
  var import_mime = __toESM(require("mime"));
9862
10830
 
9863
10831
  // src/utils/errors.ts
@@ -9886,10 +10854,10 @@ var NetworkError = class extends CLIError {
9886
10854
  // src/api/client.ts
9887
10855
  init_logger();
9888
10856
  var DEFAULT_TIMEOUT = 3e4;
9889
- async function apiRequest(path22, options = {}) {
10857
+ async function apiRequest(path25, options = {}) {
9890
10858
  const { method = "GET", body, query, timeout = DEFAULT_TIMEOUT, requireAuth = true } = options;
9891
10859
  const endpoint = getApiEndpoint();
9892
- let url = `${endpoint}${path22}`;
10860
+ let url = `${endpoint}${path25}`;
9893
10861
  if (query && Object.keys(query).length > 0) {
9894
10862
  const params = new URLSearchParams(query);
9895
10863
  url = `${url}?${params.toString()}`;
@@ -9927,7 +10895,7 @@ async function apiRequest(path22, options = {}) {
9927
10895
  const controller = new AbortController();
9928
10896
  const timeoutId = setTimeout(() => controller.abort(), timeout);
9929
10897
  try {
9930
- logger.debug(`API Request: ${method} ${path22}`);
10898
+ logger.debug(`API Request: ${method} ${path25}`);
9931
10899
  const response = await fetch(url, {
9932
10900
  method,
9933
10901
  headers,
@@ -10042,10 +11010,10 @@ function mapAPIError(status, response) {
10042
11010
  }
10043
11011
  return new CLIError(errCode, errMsg);
10044
11012
  }
10045
- async function apiRequestStream(path22, options = {}) {
11013
+ async function apiRequestStream(path25, options = {}) {
10046
11014
  const { timeout = 3e5 } = options;
10047
11015
  const endpoint = getApiEndpoint();
10048
- const url = `${endpoint}${path22}`;
11016
+ const url = `${endpoint}${path25}`;
10049
11017
  const headers = {
10050
11018
  "User-Agent": "refly-cli/0.1.0"
10051
11019
  };
@@ -10076,7 +11044,7 @@ async function apiRequestStream(path22, options = {}) {
10076
11044
  const controller = new AbortController();
10077
11045
  const timeoutId = setTimeout(() => controller.abort(), timeout);
10078
11046
  try {
10079
- logger.debug(`API Stream Request: GET ${path22}`);
11047
+ logger.debug(`API Stream Request: GET ${path25}`);
10080
11048
  const response = await fetch(url, {
10081
11049
  method: "GET",
10082
11050
  headers,
@@ -10171,7 +11139,7 @@ async function uploadToPresignedUrl(presignedUrl, filePath, contentType, retryCo
10171
11139
  const controller = new AbortController();
10172
11140
  const timeoutId = setTimeout(() => controller.abort(), timeout);
10173
11141
  try {
10174
- const fileBuffer = await fs11.promises.readFile(filePath);
11142
+ const fileBuffer = await fs15.promises.readFile(filePath);
10175
11143
  const response = await fetch(presignedUrl, {
10176
11144
  method: "PUT",
10177
11145
  headers: {
@@ -10229,7 +11197,7 @@ async function apiGetWorkflow(workflowId) {
10229
11197
  return apiRequest(`/v1/cli/workflow/${workflowId}`);
10230
11198
  }
10231
11199
  async function apiUploadDriveFile(filePath, canvasId, options) {
10232
- const filename = path7.basename(filePath);
11200
+ const filename = path10.basename(filePath);
10233
11201
  const mimeType = getMimeType(filePath);
10234
11202
  const fileStats = (0, import_node_fs4.statSync)(filePath);
10235
11203
  logger.debug(`Starting presigned upload: ${filename} (${fileStats.size} bytes)`);
@@ -10492,7 +11460,7 @@ async function getUserInfoFromToken(accessToken) {
10492
11460
  };
10493
11461
  }
10494
11462
  function sleep(ms) {
10495
- return new Promise((resolve7) => setTimeout(resolve7, ms));
11463
+ return new Promise((resolve8) => setTimeout(resolve8, ms));
10496
11464
  }
10497
11465
 
10498
11466
  // src/commands/init.ts
@@ -10552,7 +11520,38 @@ var initCommand = new Command("init").description("Initialize Refly CLI, install
10552
11520
  printError2("Slash commands installation failed");
10553
11521
  }
10554
11522
  println("");
10555
- } else if (!pretty) {
11523
+ }
11524
+ const installedAgents = await detectInstalledAgents();
11525
+ const deployableAgents = installedAgents.filter((a) => a.format !== "unknown");
11526
+ if (pretty && tty && deployableAgents.length > 0) {
11527
+ println(`Found ${deployableAgents.length} installed agent(s):`);
11528
+ for (const agent of deployableAgents) {
11529
+ const dir = agent.globalSkillsDir || agent.skillsDir || "N/A";
11530
+ println(` \u2713 ${agent.displayName.padEnd(16)} ${dir}`);
11531
+ }
11532
+ println("");
11533
+ }
11534
+ const platformResults = [];
11535
+ if (deployableAgents.length > 0) {
11536
+ const deployResult = await deploySkillToAllPlatforms("refly", { force: true });
11537
+ for (const [agentName, result] of deployResult.results) {
11538
+ platformResults.push({
11539
+ agent: agentName,
11540
+ success: result.success,
11541
+ path: result.deployedPath || void 0
11542
+ });
11543
+ }
11544
+ if (pretty && tty) {
11545
+ const successCount = platformResults.filter((r) => r.success).length;
11546
+ if (successCount === deployableAgents.length) {
11547
+ printSuccess(`Synced to ${successCount} agent(s)`);
11548
+ } else {
11549
+ printDim(`Synced to ${successCount}/${deployableAgents.length} agent(s)`);
11550
+ }
11551
+ println("");
11552
+ }
11553
+ }
11554
+ if (!pretty) {
10556
11555
  print("init", {
10557
11556
  message: "Refly CLI initialized successfully",
10558
11557
  configDir: getReflyDir(),
@@ -10562,7 +11561,11 @@ var initCommand = new Command("init").description("Initialize Refly CLI, install
10562
11561
  symlinkPath: installResult.symlinkPath,
10563
11562
  commandsInstalled: installResult.commandsInstalled,
10564
11563
  commandsPath: installResult.commandsPath,
10565
- version: installResult.version
11564
+ version: installResult.version,
11565
+ platforms: {
11566
+ detected: installedAgents.map((a) => a.name),
11567
+ deployed: platformResults
11568
+ }
10566
11569
  });
10567
11570
  }
10568
11571
  if (!skipLogin && !isAuthenticated2) {
@@ -10750,7 +11753,7 @@ var import_node_child_process6 = require("child_process");
10750
11753
  var import_node_fs5 = __toESM(require("fs"));
10751
11754
  init_logger();
10752
11755
  init_paths();
10753
- var CLI_VERSION = "0.1.23";
11756
+ var CLI_VERSION = "0.1.24";
10754
11757
  var NPM_TAG = "latest";
10755
11758
  function compareSemver(a, b) {
10756
11759
  const parseVersion = (v) => {
@@ -11006,16 +12009,16 @@ configCommand.action(() => {
11006
12009
  };
11007
12010
  ok("config", safeConfig);
11008
12011
  });
11009
- function getNestedValue(obj, path22) {
11010
- return path22.split(".").reduce((current, key) => {
12012
+ function getNestedValue(obj, path25) {
12013
+ return path25.split(".").reduce((current, key) => {
11011
12014
  if (current && typeof current === "object" && key in current) {
11012
12015
  return current[key];
11013
12016
  }
11014
12017
  return void 0;
11015
12018
  }, obj);
11016
12019
  }
11017
- function setNestedValue(obj, path22, value) {
11018
- const keys = path22.split(".");
12020
+ function setNestedValue(obj, path25, value) {
12021
+ const keys = path25.split(".");
11019
12022
  const lastKey = keys.pop();
11020
12023
  let current = obj;
11021
12024
  for (const key of keys) {
@@ -11256,14 +12259,14 @@ var workflowDeleteCommand = new Command("delete").description("Delete a workflow
11256
12259
  init_cjs_shims();
11257
12260
  var readline2 = __toESM(require("readline/promises"));
11258
12261
  var import_node_process8 = require("process");
11259
- var path9 = __toESM(require("path"));
12262
+ var path12 = __toESM(require("path"));
11260
12263
 
11261
12264
  // src/utils/prompt.ts
11262
12265
  init_cjs_shims();
11263
12266
  var readline = __toESM(require("readline/promises"));
11264
12267
  var import_node_process7 = require("process");
11265
- var fs13 = __toESM(require("fs"));
11266
- var path8 = __toESM(require("path"));
12268
+ var fs17 = __toESM(require("fs"));
12269
+ var path11 = __toESM(require("path"));
11267
12270
  function isInteractive() {
11268
12271
  return process.stdin?.isTTY ?? false;
11269
12272
  }
@@ -11287,12 +12290,12 @@ async function promptForFilePath(variableName, resourceTypes, isRequired) {
11287
12290
  const homeDir = process.env.HOME || process.env.USERPROFILE || "";
11288
12291
  resolvedPath = resolvedPath.replace("~", homeDir);
11289
12292
  }
11290
- resolvedPath = path8.resolve(resolvedPath);
11291
- if (!fs13.existsSync(resolvedPath)) {
12293
+ resolvedPath = path11.resolve(resolvedPath);
12294
+ if (!fs17.existsSync(resolvedPath)) {
11292
12295
  console.log(` File not found: ${resolvedPath}`);
11293
12296
  continue;
11294
12297
  }
11295
- const stats = fs13.statSync(resolvedPath);
12298
+ const stats = fs17.statSync(resolvedPath);
11296
12299
  if (!stats.isFile()) {
11297
12300
  console.log(` Not a file: ${resolvedPath}`);
11298
12301
  continue;
@@ -11490,12 +12493,12 @@ async function pollToolsStatus(workflowId, maxWaitTime = 15 * 60 * 1e3, pollInte
11490
12493
  );
11491
12494
  previousRemainingCount = remainingCount;
11492
12495
  }
11493
- await new Promise((resolve7) => setTimeout(resolve7, pollInterval));
12496
+ await new Promise((resolve8) => setTimeout(resolve8, pollInterval));
11494
12497
  } catch (error) {
11495
12498
  console.log(`
11496
12499
  \u26A0\uFE0F Failed to check authorization status: ${error.message}`);
11497
12500
  console.log("Continuing to wait...");
11498
- await new Promise((resolve7) => setTimeout(resolve7, pollInterval));
12501
+ await new Promise((resolve8) => setTimeout(resolve8, pollInterval));
11499
12502
  }
11500
12503
  }
11501
12504
  console.log("\n\u23F0 Timeout waiting for tool authorization.");
@@ -11606,7 +12609,7 @@ ${details}`;
11606
12609
  if (!filePath) {
11607
12610
  continue;
11608
12611
  }
11609
- const filename = path9.basename(filePath);
12612
+ const filename = path12.basename(filePath);
11610
12613
  process.stdout.write(` Uploading ${filename}...`);
11611
12614
  try {
11612
12615
  const uploadResult = await apiUploadDriveFile(filePath, workflowId);
@@ -11988,7 +12991,7 @@ var workflowStatusCommand = new Command("status").description("Get detailed work
11988
12991
  });
11989
12992
  prevStatus = status;
11990
12993
  while (status.status === "init" || status.status === "executing") {
11991
- await new Promise((resolve7) => setTimeout(resolve7, pollInterval));
12994
+ await new Promise((resolve8) => setTimeout(resolve8, pollInterval));
11992
12995
  status = await fetchStatus();
11993
12996
  if (options.full || hasStatusChanged(prevStatus, status)) {
11994
12997
  if (options.full) {
@@ -12116,7 +13119,75 @@ var workflowDetailCommand = new Command("detail").description("Get detailed work
12116
13119
 
12117
13120
  // src/commands/workflow/toolcalls.ts
12118
13121
  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) => {
13122
+ function extractNodeOutputs(toolCalls) {
13123
+ const outputs = [];
13124
+ for (const call of toolCalls) {
13125
+ if (!call.output || call.status !== "completed") continue;
13126
+ const output3 = call.output;
13127
+ const filesMap = /* @__PURE__ */ new Map();
13128
+ let content;
13129
+ if (Array.isArray(output3.files)) {
13130
+ for (const f of output3.files) {
13131
+ const file = f;
13132
+ if (file.fileId && !filesMap.has(String(file.fileId))) {
13133
+ filesMap.set(String(file.fileId), {
13134
+ fileId: String(file.fileId),
13135
+ name: String(file.name || ""),
13136
+ type: String(file.type || ""),
13137
+ category: file.category,
13138
+ size: file.size,
13139
+ url: file.url,
13140
+ source: file.source,
13141
+ createdAt: file.createdAt
13142
+ });
13143
+ }
13144
+ }
13145
+ }
13146
+ if (output3.data && typeof output3.data === "object") {
13147
+ const data = output3.data;
13148
+ if (data.fileId && !filesMap.has(String(data.fileId))) {
13149
+ filesMap.set(String(data.fileId), {
13150
+ fileId: String(data.fileId),
13151
+ name: String(data.name || ""),
13152
+ type: String(data.type || ""),
13153
+ category: data.category,
13154
+ size: data.size,
13155
+ url: data.url,
13156
+ source: data.source,
13157
+ createdAt: data.createdAt
13158
+ });
13159
+ }
13160
+ }
13161
+ if (output3.content) {
13162
+ content = String(output3.content).slice(0, 500);
13163
+ } else if (output3.data && typeof output3.data === "object") {
13164
+ const data = output3.data;
13165
+ if (data.candidates && Array.isArray(data.candidates)) {
13166
+ const parts = data.candidates[0]?.content;
13167
+ if (parts?.parts && Array.isArray(parts.parts)) {
13168
+ const textPart = parts.parts.find(
13169
+ (p) => typeof p.text === "string" && !p.thought
13170
+ );
13171
+ if (textPart) {
13172
+ content = String(textPart.text).slice(0, 500);
13173
+ }
13174
+ }
13175
+ }
13176
+ }
13177
+ const files = Array.from(filesMap.values());
13178
+ if (files.length > 0 || content) {
13179
+ outputs.push({
13180
+ nodeId: call.nodeId || "",
13181
+ nodeTitle: call.nodeTitle || call.toolName,
13182
+ toolName: call.toolName,
13183
+ content,
13184
+ files
13185
+ });
13186
+ }
13187
+ }
13188
+ return outputs;
13189
+ }
13190
+ 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
13191
  try {
12121
13192
  const params = new URLSearchParams();
12122
13193
  if (options.nodeId) {
@@ -12137,12 +13208,26 @@ var workflowToolcallsCommand = new Command("toolcalls").description("Get all too
12137
13208
  if (options.offset) {
12138
13209
  params.set("offset", options.offset);
12139
13210
  }
12140
- if (options.raw) {
13211
+ if (options.raw || options.files) {
12141
13212
  params.set("sanitizeForDisplay", "false");
12142
13213
  }
12143
13214
  const idType = detectIdType2(id);
12144
13215
  const url = buildWorkflowApiUrl(id, "toolcalls", params);
12145
13216
  const result = await apiRequest(url);
13217
+ if (options.files) {
13218
+ let nodeOutputs = extractNodeOutputs(result.toolCalls);
13219
+ if (options.latest && nodeOutputs.length > 0) {
13220
+ const lastWithFiles = nodeOutputs.filter((n) => n.files.length > 0).pop();
13221
+ nodeOutputs = lastWithFiles ? [lastWithFiles] : [];
13222
+ }
13223
+ const allFiles = nodeOutputs.flatMap((n) => n.files);
13224
+ ok("workflow.files", {
13225
+ runId: result.runId,
13226
+ workflowId: result.workflowId,
13227
+ files: allFiles,
13228
+ nodes: nodeOutputs
13229
+ });
13230
+ }
12146
13231
  ok("workflow.toolcalls", {
12147
13232
  runId: result.runId,
12148
13233
  workflowId: result.workflowId,
@@ -13305,16 +14390,16 @@ var fileGetCommand = new Command("get").description("Get file details").argument
13305
14390
 
13306
14391
  // src/commands/file/download.ts
13307
14392
  init_cjs_shims();
13308
- var fs14 = __toESM(require("fs"));
13309
- var path10 = __toESM(require("path"));
14393
+ var fs18 = __toESM(require("fs"));
14394
+ var path13 = __toESM(require("path"));
13310
14395
  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
14396
  try {
13312
14397
  const { data, filename, contentType, size } = await apiRequestStream(
13313
14398
  `/v1/cli/drive/files/${fileId}/download`
13314
14399
  );
13315
14400
  const outputPath = options.output || filename || `${fileId}`;
13316
- const resolvedPath = path10.resolve(outputPath);
13317
- fs14.writeFileSync(resolvedPath, data);
14401
+ const resolvedPath = path13.resolve(outputPath);
14402
+ fs18.writeFileSync(resolvedPath, data);
13318
14403
  ok("file.download", {
13319
14404
  fileId,
13320
14405
  path: resolvedPath,
@@ -13339,8 +14424,8 @@ var fileDownloadCommand = new Command("download").description("Download file to
13339
14424
 
13340
14425
  // src/commands/file/upload.ts
13341
14426
  init_cjs_shims();
13342
- var fs15 = __toESM(require("fs"));
13343
- var path11 = __toESM(require("path"));
14427
+ var fs19 = __toESM(require("fs"));
14428
+ var path14 = __toESM(require("path"));
13344
14429
  var MAX_FILES = 10;
13345
14430
  function formatSize(bytes) {
13346
14431
  if (bytes < 1024) return `${bytes}B`;
@@ -13350,8 +14435,8 @@ function formatSize(bytes) {
13350
14435
  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
14436
  const formatter = getFormatter();
13352
14437
  try {
13353
- const resolvedPath = path11.resolve(inputPath);
13354
- if (!fs15.existsSync(resolvedPath)) {
14438
+ const resolvedPath = path14.resolve(inputPath);
14439
+ if (!fs19.existsSync(resolvedPath)) {
13355
14440
  fail(ErrorCodes.NOT_FOUND, `Path not found: ${inputPath}`, {
13356
14441
  hint: "Check if the file or directory exists"
13357
14442
  });
@@ -13369,8 +14454,8 @@ var fileUploadCommand = new Command("upload").description("Upload file(s) to a c
13369
14454
  const errors = [];
13370
14455
  for (let i = 0; i < files.length; i++) {
13371
14456
  const filePath = files[i];
13372
- const filename = path11.basename(filePath);
13373
- const fileStats = fs15.statSync(filePath);
14457
+ const filename = path14.basename(filePath);
14458
+ const fileStats = fs19.statSync(filePath);
13374
14459
  const sizeStr = formatSize(fileStats.size);
13375
14460
  let currentStage = "presign";
13376
14461
  const updateProgress = () => {
@@ -13451,11 +14536,11 @@ var fileUploadCommand = new Command("upload").description("Upload file(s) to a c
13451
14536
  }
13452
14537
  });
13453
14538
  function resolveFilesToUpload(inputPath, filter) {
13454
- const stats = fs15.statSync(inputPath);
14539
+ const stats = fs19.statSync(inputPath);
13455
14540
  if (stats.isFile()) {
13456
14541
  if (filter) {
13457
14542
  const filterExts = filter.split(",").map((e) => e.trim().toLowerCase());
13458
- const ext = path11.extname(inputPath).slice(1).toLowerCase();
14543
+ const ext = path14.extname(inputPath).slice(1).toLowerCase();
13459
14544
  if (!filterExts.includes(ext)) {
13460
14545
  return [];
13461
14546
  }
@@ -13463,21 +14548,21 @@ function resolveFilesToUpload(inputPath, filter) {
13463
14548
  return [inputPath];
13464
14549
  }
13465
14550
  if (stats.isDirectory()) {
13466
- const entries = fs15.readdirSync(inputPath);
14551
+ const entries = fs19.readdirSync(inputPath);
13467
14552
  const filterExts = filter?.split(",").map((e) => e.trim().toLowerCase());
13468
- const files = entries.map((e) => path11.join(inputPath, e)).filter((p) => {
14553
+ const files = entries.map((e) => path14.join(inputPath, e)).filter((p) => {
13469
14554
  try {
13470
- return fs15.statSync(p).isFile();
14555
+ return fs19.statSync(p).isFile();
13471
14556
  } catch {
13472
14557
  return false;
13473
14558
  }
13474
14559
  }).filter((p) => {
13475
14560
  if (!filterExts) return true;
13476
- const ext = path11.extname(p).slice(1).toLowerCase();
14561
+ const ext = path14.extname(p).slice(1).toLowerCase();
13477
14562
  return filterExts.includes(ext);
13478
14563
  }).sort((a, b) => {
13479
14564
  try {
13480
- return fs15.statSync(a).size - fs15.statSync(b).size;
14565
+ return fs19.statSync(a).size - fs19.statSync(b).size;
13481
14566
  } catch {
13482
14567
  return 0;
13483
14568
  }
@@ -13581,7 +14666,7 @@ var skillGetCommand = new Command("get").description("Get skill package details"
13581
14666
 
13582
14667
  // src/commands/skill/create.ts
13583
14668
  init_cjs_shims();
13584
- var fs16 = __toESM(require("fs"));
14669
+ var fs20 = __toESM(require("fs"));
13585
14670
  init_symlink();
13586
14671
  init_paths();
13587
14672
  init_logger();
@@ -13633,7 +14718,7 @@ var skillCreateCommand = new Command("create").description("Create a new skill p
13633
14718
  const localName = options.name.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "");
13634
14719
  const skillDir = getReflyDomainSkillDir(localName);
13635
14720
  const symlinkStatus = isSkillSymlinkValid(localName);
13636
- if (fs16.existsSync(skillDir) || symlinkStatus.exists) {
14721
+ if (fs20.existsSync(skillDir) || symlinkStatus.exists) {
13637
14722
  logger.debug(`Local skill '${localName}' already exists, skipping sync`);
13638
14723
  } else {
13639
14724
  const skillMdContent = generateReflySkillMd({
@@ -13695,8 +14780,8 @@ var skillCreateCommand = new Command("create").description("Create a new skill p
13695
14780
 
13696
14781
  // src/commands/skill/update.ts
13697
14782
  init_cjs_shims();
13698
- var fs17 = __toESM(require("fs"));
13699
- var path12 = __toESM(require("path"));
14783
+ var fs21 = __toESM(require("fs"));
14784
+ var path15 = __toESM(require("path"));
13700
14785
  init_paths();
13701
14786
  init_symlink();
13702
14787
  var MIN_DESCRIPTION_WORDS = 20;
@@ -13726,8 +14811,8 @@ var skillUpdateCommand = new Command("update").description("Update skill install
13726
14811
  try {
13727
14812
  const name = options.name;
13728
14813
  const skillDir = getReflyDomainSkillDir(name);
13729
- const skillMdPath = path12.join(skillDir, "SKILL.md");
13730
- if (!fs17.existsSync(skillMdPath)) {
14814
+ const skillMdPath = path15.join(skillDir, "SKILL.md");
14815
+ if (!fs21.existsSync(skillMdPath)) {
13731
14816
  const skillsDir = getReflySkillsDir();
13732
14817
  fail(ErrorCodes.NOT_FOUND, `SKILL.md not found at ${skillMdPath}`, {
13733
14818
  hint: `Make sure the skill '${name}' exists in ${skillsDir}/
@@ -13736,7 +14821,7 @@ To see installed skills: refly skill list`
13736
14821
  });
13737
14822
  return;
13738
14823
  }
13739
- const skillContent = fs17.readFileSync(skillMdPath, "utf-8");
14824
+ const skillContent = fs21.readFileSync(skillMdPath, "utf-8");
13740
14825
  let meta;
13741
14826
  try {
13742
14827
  const parsed = parseReflySkillMd(skillContent);
@@ -13819,8 +14904,8 @@ To see installed skills: refly skill list`
13819
14904
 
13820
14905
  // src/commands/skill/publish.ts
13821
14906
  init_cjs_shims();
13822
- var fs18 = __toESM(require("fs"));
13823
- var path13 = __toESM(require("path"));
14907
+ var fs22 = __toESM(require("fs"));
14908
+ var path16 = __toESM(require("path"));
13824
14909
  init_symlink();
13825
14910
  init_paths();
13826
14911
  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 +14913,8 @@ var skillPublishCommand = new Command("publish").description("Publish a skill pa
13828
14913
  const skillsDir = getReflySkillsDir();
13829
14914
  const name = options.name;
13830
14915
  const skillDir = getReflyDomainSkillDir(name);
13831
- const skillMdPath = path13.join(skillDir, "SKILL.md");
13832
- if (!fs18.existsSync(skillMdPath)) {
14916
+ const skillMdPath = path16.join(skillDir, "SKILL.md");
14917
+ if (!fs22.existsSync(skillMdPath)) {
13833
14918
  fail(ErrorCodes.NOT_FOUND, `SKILL.md not found at ${skillMdPath}`, {
13834
14919
  hint: `Make sure the skill '${name}' exists in ${skillsDir}/
13835
14920
 
@@ -13838,7 +14923,7 @@ To create a new skill: refly skill create --name "${name}" --workflow-query "...
13838
14923
  });
13839
14924
  return;
13840
14925
  }
13841
- const skillContent = fs18.readFileSync(skillMdPath, "utf-8");
14926
+ const skillContent = fs22.readFileSync(skillMdPath, "utf-8");
13842
14927
  let parsedSkill;
13843
14928
  try {
13844
14929
  parsedSkill = parseReflySkillMd(skillContent);
@@ -13900,8 +14985,8 @@ To find available skills: refly skill list`
13900
14985
 
13901
14986
  // src/commands/skill/unpublish.ts
13902
14987
  init_cjs_shims();
13903
- var fs19 = __toESM(require("fs"));
13904
- var path14 = __toESM(require("path"));
14988
+ var fs23 = __toESM(require("fs"));
14989
+ var path17 = __toESM(require("path"));
13905
14990
  init_symlink();
13906
14991
  init_paths();
13907
14992
  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 +15021,8 @@ To find your skill name:
13936
15021
  return;
13937
15022
  }
13938
15023
  const skillDir = getReflyDomainSkillDir(name);
13939
- const skillMdPath = path14.join(skillDir, "SKILL.md");
13940
- if (!fs19.existsSync(skillMdPath)) {
15024
+ const skillMdPath = path17.join(skillDir, "SKILL.md");
15025
+ if (!fs23.existsSync(skillMdPath)) {
13941
15026
  fail(ErrorCodes.NOT_FOUND, `SKILL.md not found at ${skillMdPath}`, {
13942
15027
  hint: `Make sure the skill '${name}' exists in ${skillsDir}/
13943
15028
 
@@ -13945,7 +15030,7 @@ To see installed skills: refly skill list`
13945
15030
  });
13946
15031
  return;
13947
15032
  }
13948
- const skillContent = fs19.readFileSync(skillMdPath, "utf-8");
15033
+ const skillContent = fs23.readFileSync(skillMdPath, "utf-8");
13949
15034
  try {
13950
15035
  const { meta } = parseReflySkillMd(skillContent);
13951
15036
  skillId = options.id || meta.skillId;
@@ -13989,8 +15074,8 @@ To see installed skills: refly skill list`
13989
15074
 
13990
15075
  // src/commands/skill/run.ts
13991
15076
  init_cjs_shims();
13992
- var fs20 = __toESM(require("fs"));
13993
- var path15 = __toESM(require("path"));
15077
+ var fs24 = __toESM(require("fs"));
15078
+ var path18 = __toESM(require("path"));
13994
15079
  init_symlink();
13995
15080
  init_paths();
13996
15081
  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 +15100,8 @@ To find your skill name:
14015
15100
  if (options.name) {
14016
15101
  name = options.name;
14017
15102
  const skillDir = getReflyDomainSkillDir(options.name);
14018
- const skillMdPath = path15.join(skillDir, "SKILL.md");
14019
- if (!fs20.existsSync(skillMdPath)) {
15103
+ const skillMdPath = path18.join(skillDir, "SKILL.md");
15104
+ if (!fs24.existsSync(skillMdPath)) {
14020
15105
  fail(ErrorCodes.NOT_FOUND, `SKILL.md not found at ${skillMdPath}`, {
14021
15106
  hint: `Make sure the skill '${name}' exists in ${skillsDir}/
14022
15107
 
@@ -14025,7 +15110,7 @@ To install a skill: refly skill install <skillId>`
14025
15110
  });
14026
15111
  return;
14027
15112
  }
14028
- const skillContent = fs20.readFileSync(skillMdPath, "utf-8");
15113
+ const skillContent = fs24.readFileSync(skillMdPath, "utf-8");
14029
15114
  try {
14030
15115
  const { meta } = parseReflySkillMd(skillContent);
14031
15116
  skillId = meta.skillId;
@@ -14143,24 +15228,24 @@ To install: refly skill install ${meta.skillId}`
14143
15228
 
14144
15229
  // src/commands/skill/stop.ts
14145
15230
  init_cjs_shims();
14146
- var fs21 = __toESM(require("fs"));
14147
- var path16 = __toESM(require("path"));
15231
+ var fs25 = __toESM(require("fs"));
15232
+ var path19 = __toESM(require("path"));
14148
15233
  init_symlink();
14149
15234
  init_paths();
14150
15235
  function getLocalSkillNames() {
14151
15236
  const skillsDir = getReflySkillsDir();
14152
- if (!fs21.existsSync(skillsDir)) {
15237
+ if (!fs25.existsSync(skillsDir)) {
14153
15238
  return [];
14154
15239
  }
14155
- return fs21.readdirSync(skillsDir, { withFileTypes: true }).filter((dirent) => dirent.isDirectory()).map((dirent) => dirent.name);
15240
+ return fs25.readdirSync(skillsDir, { withFileTypes: true }).filter((dirent) => dirent.isDirectory()).map((dirent) => dirent.name);
14156
15241
  }
14157
15242
  var skillStopCommand = new Command("stop").description("Stop running skill executions").requiredOption("--name <name>", "Local skill name (directory in ~/.refly/skills/)").action(async (options) => {
14158
15243
  try {
14159
15244
  const skillsDir = getReflySkillsDir();
14160
15245
  const name = options.name;
14161
15246
  const skillDir = getReflyDomainSkillDir(name);
14162
- const skillMdPath = path16.join(skillDir, "SKILL.md");
14163
- if (!fs21.existsSync(skillMdPath)) {
15247
+ const skillMdPath = path19.join(skillDir, "SKILL.md");
15248
+ if (!fs25.existsSync(skillMdPath)) {
14164
15249
  const availableSkills = getLocalSkillNames();
14165
15250
  const skillList = availableSkills.length > 0 ? availableSkills.join(", ") : "(no skills installed)";
14166
15251
  fail(ErrorCodes.NOT_FOUND, `Skill "${name}" not found`, {
@@ -14169,7 +15254,7 @@ var skillStopCommand = new Command("stop").description("Stop running skill execu
14169
15254
  Skills directory: ${skillsDir}`
14170
15255
  });
14171
15256
  }
14172
- const skillContent = fs21.readFileSync(skillMdPath, "utf-8");
15257
+ const skillContent = fs25.readFileSync(skillMdPath, "utf-8");
14173
15258
  let installationId;
14174
15259
  try {
14175
15260
  const { meta } = parseReflySkillMd(skillContent);
@@ -14297,7 +15382,7 @@ var skillInstallCommand = new Command("install").description("Install a skill pa
14297
15382
  }
14298
15383
  );
14299
15384
  let localPath;
14300
- let symlinkPath;
15385
+ const platformResults = [];
14301
15386
  const skillName = result.skillPackage?.name;
14302
15387
  const workflowId = result.skillPackage?.workflowId;
14303
15388
  if (skillName && workflowId) {
@@ -14315,15 +15400,23 @@ var skillInstallCommand = new Command("install").description("Install a skill pa
14315
15400
  inputSchema: result.skillPackage?.inputSchema,
14316
15401
  outputSchema: result.skillPackage?.outputSchema
14317
15402
  });
14318
- const symlinkResult = createReflySkillWithSymlink(skillName, skillMdContent, {
15403
+ const deployResult = await createMultiPlatformSkill(skillName, skillMdContent, {
14319
15404
  force: options.force
14320
15405
  });
14321
- if (symlinkResult.success) {
14322
- localPath = symlinkResult.reflyPath;
14323
- symlinkPath = symlinkResult.claudePath;
14324
- logger.info(`Created local skill: ${localPath}`);
15406
+ localPath = deployResult.sourcePath;
15407
+ for (const [agentName, agentResult] of deployResult.results) {
15408
+ platformResults.push({
15409
+ agent: agentName,
15410
+ success: agentResult.success,
15411
+ path: agentResult.deployedPath || void 0
15412
+ });
15413
+ }
15414
+ if (deployResult.successCount > 0) {
15415
+ logger.info(
15416
+ `Created local skill: ${localPath}, deployed to ${deployResult.successCount} platform(s)`
15417
+ );
14325
15418
  } else {
14326
- logger.warn(`Failed to create local skill: ${symlinkResult.error}`);
15419
+ logger.warn("Failed to deploy skill to any platform");
14327
15420
  }
14328
15421
  } catch (err) {
14329
15422
  logger.warn(`Failed to create local skill: ${err.message}`);
@@ -14338,7 +15431,7 @@ var skillInstallCommand = new Command("install").description("Install a skill pa
14338
15431
  config: result.userConfig,
14339
15432
  installedAt: result.createdAt,
14340
15433
  localPath,
14341
- symlinkPath
15434
+ platforms: platformResults.length > 0 ? platformResults : void 0
14342
15435
  });
14343
15436
  } catch (error) {
14344
15437
  if (error instanceof CLIError) {
@@ -14358,8 +15451,8 @@ var skillInstallCommand = new Command("install").description("Install a skill pa
14358
15451
 
14359
15452
  // src/commands/skill/uninstall.ts
14360
15453
  init_cjs_shims();
14361
- var fs22 = __toESM(require("fs"));
14362
- var path17 = __toESM(require("path"));
15454
+ var fs26 = __toESM(require("fs"));
15455
+ var path20 = __toESM(require("path"));
14363
15456
  init_symlink();
14364
15457
  init_paths();
14365
15458
  init_logger();
@@ -14396,8 +15489,8 @@ To find your skill name:
14396
15489
  return;
14397
15490
  }
14398
15491
  const skillDir = getReflyDomainSkillDir(name);
14399
- const skillMdPath = path17.join(skillDir, "SKILL.md");
14400
- if (!fs22.existsSync(skillMdPath)) {
15492
+ const skillMdPath = path20.join(skillDir, "SKILL.md");
15493
+ if (!fs26.existsSync(skillMdPath)) {
14401
15494
  fail(ErrorCodes.NOT_FOUND, `SKILL.md not found at ${skillMdPath}`, {
14402
15495
  hint: `Make sure the skill '${name}' exists in ${skillsDir}/
14403
15496
 
@@ -14405,7 +15498,7 @@ To see installed skills: refly skill list`
14405
15498
  });
14406
15499
  return;
14407
15500
  }
14408
- const skillContent = fs22.readFileSync(skillMdPath, "utf-8");
15501
+ const skillContent = fs26.readFileSync(skillMdPath, "utf-8");
14409
15502
  try {
14410
15503
  const { meta } = parseReflySkillMd(skillContent);
14411
15504
  skillId = meta.skillId;
@@ -14436,14 +15529,21 @@ To see installed skills: refly skill list`
14436
15529
  }
14437
15530
  }
14438
15531
  }
14439
- let symlinkRemoved = false;
14440
15532
  let directoryRemoved = false;
15533
+ const platformResults = [];
14441
15534
  if (name && !options.keepLocal) {
14442
15535
  try {
14443
- const cleanup = deleteDomainSkillWithSymlink(name);
14444
- symlinkRemoved = cleanup.symlinkRemoved;
15536
+ const cleanup = await removeMultiPlatformSkill(name);
14445
15537
  directoryRemoved = cleanup.directoryRemoved;
14446
- logger.info(`Cleaned up local skill: ${name}`);
15538
+ for (const [agentName, result] of cleanup.platformResults.results) {
15539
+ platformResults.push({
15540
+ agent: agentName,
15541
+ success: result.success
15542
+ });
15543
+ }
15544
+ logger.info(
15545
+ `Cleaned up local skill: ${name}, removed from ${cleanup.platformResults.successCount} platform(s)`
15546
+ );
14447
15547
  } catch (err) {
14448
15548
  logger.warn(`Failed to clean up local skill: ${err.message}`);
14449
15549
  }
@@ -14454,8 +15554,8 @@ To see installed skills: refly skill list`
14454
15554
  installationId,
14455
15555
  uninstalled: true,
14456
15556
  localCleanup: {
14457
- symlinkRemoved,
14458
- directoryRemoved
15557
+ directoryRemoved,
15558
+ platforms: platformResults.length > 0 ? platformResults : void 0
14459
15559
  }
14460
15560
  });
14461
15561
  } catch (error) {
@@ -14521,8 +15621,8 @@ init_cjs_shims();
14521
15621
 
14522
15622
  // src/skill/loader.ts
14523
15623
  init_cjs_shims();
14524
- var fs23 = __toESM(require("fs"));
14525
- var path18 = __toESM(require("path"));
15624
+ var fs27 = __toESM(require("fs"));
15625
+ var path21 = __toESM(require("path"));
14526
15626
  var import_gray_matter = __toESM(require("gray-matter"));
14527
15627
  init_logger();
14528
15628
 
@@ -14702,23 +15802,23 @@ function extractSkillMetadata(content) {
14702
15802
 
14703
15803
  // src/commands/skill/validate.ts
14704
15804
  init_paths();
14705
- var fs24 = __toESM(require("fs"));
14706
- var path19 = __toESM(require("path"));
15805
+ var fs28 = __toESM(require("fs"));
15806
+ var path22 = __toESM(require("path"));
14707
15807
  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
15808
  try {
14709
15809
  const results = [];
14710
15810
  let targetPath;
14711
15811
  if (skillPath) {
14712
- targetPath = path19.resolve(skillPath);
15812
+ targetPath = path22.resolve(skillPath);
14713
15813
  } else {
14714
15814
  await ensureSkillsDir();
14715
15815
  targetPath = getSkillsDir();
14716
15816
  }
14717
- if (!fs24.existsSync(targetPath)) {
15817
+ if (!fs28.existsSync(targetPath)) {
14718
15818
  fail(ErrorCodes.NOT_FOUND, `Path not found: ${targetPath}`);
14719
15819
  return;
14720
15820
  }
14721
- const stats = fs24.statSync(targetPath);
15821
+ const stats = fs28.statSync(targetPath);
14722
15822
  if (stats.isFile()) {
14723
15823
  const result = validateSkillFile(targetPath);
14724
15824
  results.push(result);
@@ -14751,7 +15851,7 @@ var skillValidateCommand = new Command("validate").description("Validate local s
14751
15851
  });
14752
15852
  function validateSkillFile(filePath) {
14753
15853
  try {
14754
- const content = fs24.readFileSync(filePath, "utf-8");
15854
+ const content = fs28.readFileSync(filePath, "utf-8");
14755
15855
  const { frontmatter, issues } = extractSkillMetadata(content);
14756
15856
  const errors = issues.map((i) => `${i.path}: ${i.message}`);
14757
15857
  const warnings = [];
@@ -14777,9 +15877,9 @@ function validateSkillFile(filePath) {
14777
15877
  }
14778
15878
  }
14779
15879
  function findSkillFiles(dir, files = []) {
14780
- const entries = fs24.readdirSync(dir, { withFileTypes: true });
15880
+ const entries = fs28.readdirSync(dir, { withFileTypes: true });
14781
15881
  for (const entry of entries) {
14782
- const fullPath = path19.join(dir, entry.name);
15882
+ const fullPath = path22.join(dir, entry.name);
14783
15883
  if (entry.isDirectory()) {
14784
15884
  if (!entry.name.startsWith(".")) {
14785
15885
  findSkillFiles(fullPath, files);
@@ -14793,12 +15893,73 @@ function findSkillFiles(dir, files = []) {
14793
15893
 
14794
15894
  // src/commands/skill/sync.ts
14795
15895
  init_cjs_shims();
15896
+ var fs29 = __toESM(require("fs"));
15897
+ var path23 = __toESM(require("path"));
14796
15898
  init_symlink();
15899
+ init_manager();
15900
+ init_registry();
14797
15901
  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) => {
15902
+ 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
15903
  try {
15904
+ let targetAgents;
15905
+ if (options.platform) {
15906
+ const platformList = options.platform.flatMap((p) => p.split(","));
15907
+ targetAgents = [];
15908
+ for (const platform4 of platformList) {
15909
+ const trimmed = platform4.trim();
15910
+ if (!isValidAgentType(trimmed)) {
15911
+ return fail(ErrorCodes.INVALID_INPUT, `Unknown platform: ${trimmed}`, {
15912
+ hint: `Valid platforms: ${Object.keys(agents).join(", ")}`
15913
+ });
15914
+ }
15915
+ targetAgents.push(trimmed);
15916
+ }
15917
+ }
15918
+ if (options.allPlatforms) {
15919
+ const installedAgents = await detectInstalledAgents();
15920
+ const deployableAgents = installedAgents.filter((a) => a.format !== "unknown");
15921
+ const skillsDir2 = getReflySkillsDir();
15922
+ const baseSkillDir = getReflyBaseSkillDir();
15923
+ const skillsToSync = [];
15924
+ if (fs29.existsSync(baseSkillDir)) {
15925
+ skillsToSync.push("refly");
15926
+ }
15927
+ if (fs29.existsSync(skillsDir2)) {
15928
+ const entries = fs29.readdirSync(skillsDir2, { withFileTypes: true });
15929
+ for (const entry of entries) {
15930
+ if (entry.isDirectory() && entry.name !== "base") {
15931
+ skillsToSync.push(entry.name);
15932
+ }
15933
+ }
15934
+ }
15935
+ const platformResults = [];
15936
+ for (const skillName of skillsToSync) {
15937
+ const { needsSync, synced } = await syncSkillToAllPlatforms(skillName, {
15938
+ agents: targetAgents,
15939
+ dryRun: options.dryRun
15940
+ });
15941
+ platformResults.push({
15942
+ skillName,
15943
+ needsSync: Array.from(needsSync.entries()).map(([agent, status]) => ({
15944
+ agent,
15945
+ deployed: status.deployed,
15946
+ valid: status.valid
15947
+ })),
15948
+ synced: Array.from(synced.entries()).map(([agent, result]) => ({
15949
+ agent,
15950
+ success: result.success,
15951
+ path: result.deployedPath || void 0
15952
+ }))
15953
+ });
15954
+ }
15955
+ return ok("skill.sync", {
15956
+ dryRun: Boolean(options.dryRun),
15957
+ allPlatforms: true,
15958
+ installedAgents: deployableAgents.map((a) => a.name),
15959
+ skillsCount: skillsToSync.length,
15960
+ results: platformResults
15961
+ });
15962
+ }
14802
15963
  const symlinks = listSkillSymlinks();
14803
15964
  const warnings = [];
14804
15965
  const errors = [];
@@ -14823,14 +15984,14 @@ var skillSyncCommand = new Command("sync").description("Validate and repair skil
14823
15984
  }
14824
15985
  }
14825
15986
  const skillsDir = getReflySkillsDir();
14826
- if (fs25.existsSync(skillsDir)) {
14827
- const entries = fs25.readdirSync(skillsDir, { withFileTypes: true });
15987
+ if (fs29.existsSync(skillsDir)) {
15988
+ const entries = fs29.readdirSync(skillsDir, { withFileTypes: true });
14828
15989
  const symlinkNames = new Set(symlinks.map((s) => s.name));
14829
15990
  for (const entry of entries) {
14830
15991
  if (entry.isDirectory() && entry.name !== "base") {
14831
15992
  if (!symlinkNames.has(entry.name)) {
14832
15993
  orphans += 1;
14833
- warnings.push(`Orphan directory (no symlink): ${path20.join(skillsDir, entry.name)}`);
15994
+ warnings.push(`Orphan directory (no symlink): ${path23.join(skillsDir, entry.name)}`);
14834
15995
  if (options.prune && !options.dryRun) {
14835
15996
  const result = createSkillSymlink(entry.name);
14836
15997
  if (result.success) {
@@ -14877,11 +16038,178 @@ var skillSyncCommand = new Command("sync").description("Validate and repair skil
14877
16038
  // src/commands/skill/index.ts
14878
16039
  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
16040
 
16041
+ // src/commands/platform/index.ts
16042
+ init_cjs_shims();
16043
+
16044
+ // src/commands/platform/sync.ts
16045
+ init_cjs_shims();
16046
+ var fs30 = __toESM(require("fs"));
16047
+ init_manager();
16048
+ init_registry();
16049
+ init_paths();
16050
+ 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) => {
16051
+ try {
16052
+ const pretty = isPrettyOutput();
16053
+ const tty = isTTY();
16054
+ let targetAgents;
16055
+ if (options.agent) {
16056
+ const agentList = options.agent.flatMap((a) => a.split(","));
16057
+ const validatedAgents = [];
16058
+ for (const agent of agentList) {
16059
+ const trimmed = agent.trim();
16060
+ if (!isValidAgentType(trimmed)) {
16061
+ return fail(ErrorCodes.INVALID_INPUT, `Unknown agent: ${trimmed}`, {
16062
+ hint: `Valid agents: ${Object.keys(agents).join(", ")}`
16063
+ });
16064
+ }
16065
+ validatedAgents.push(trimmed);
16066
+ }
16067
+ targetAgents = validatedAgents;
16068
+ }
16069
+ if (pretty && tty) {
16070
+ println("Scanning for installed agents...");
16071
+ println("");
16072
+ }
16073
+ const installedAgents = targetAgents ? targetAgents.map((name) => agents[name]) : await detectInstalledAgents();
16074
+ const deployableAgents = installedAgents.filter((a) => a.format !== "unknown");
16075
+ if (deployableAgents.length === 0) {
16076
+ if (pretty && tty) {
16077
+ printError2("No supported agents found");
16078
+ printDim("Install an AI coding assistant and try again.");
16079
+ } else {
16080
+ ok("platform.sync", {
16081
+ message: "No supported agents found",
16082
+ installedAgents: [],
16083
+ skillsSynced: 0
16084
+ });
16085
+ }
16086
+ return;
16087
+ }
16088
+ if (pretty && tty) {
16089
+ println(`Found ${deployableAgents.length} installed agent(s):`);
16090
+ for (const agent of deployableAgents) {
16091
+ const dir = agent.globalSkillsDir || agent.skillsDir || "N/A";
16092
+ println(` \u2713 ${agent.displayName.padEnd(16)} ${dir}`);
16093
+ }
16094
+ println("");
16095
+ }
16096
+ const skillsDir = getReflySkillsDir();
16097
+ const baseSkillDir = getReflyBaseSkillDir();
16098
+ const skillsToSync = [];
16099
+ if (fs30.existsSync(baseSkillDir)) {
16100
+ skillsToSync.push("refly");
16101
+ }
16102
+ if (fs30.existsSync(skillsDir)) {
16103
+ const entries = fs30.readdirSync(skillsDir, { withFileTypes: true });
16104
+ for (const entry of entries) {
16105
+ if (entry.isDirectory() && entry.name !== "base") {
16106
+ skillsToSync.push(entry.name);
16107
+ }
16108
+ }
16109
+ }
16110
+ if (skillsToSync.length === 0) {
16111
+ if (pretty && tty) {
16112
+ printDim("No skills found to sync.");
16113
+ printDim("Run `refly init` to install the base skill.");
16114
+ } else {
16115
+ ok("platform.sync", {
16116
+ message: "No skills found to sync",
16117
+ installedAgents: deployableAgents.map((a) => a.name),
16118
+ skillsSynced: 0
16119
+ });
16120
+ }
16121
+ return;
16122
+ }
16123
+ if (pretty && tty) {
16124
+ println(`Syncing ${skillsToSync.length} skill(s) to all installed agents...`);
16125
+ }
16126
+ if (options.dryRun) {
16127
+ if (pretty && tty) {
16128
+ println("");
16129
+ println("Dry run - no changes made:");
16130
+ for (const skillName of skillsToSync) {
16131
+ const agentNames = deployableAgents.map((a) => a.displayName).join(", ");
16132
+ println(` ${skillName} -> ${agentNames}`);
16133
+ }
16134
+ } else {
16135
+ ok("platform.sync", {
16136
+ dryRun: true,
16137
+ installedAgents: deployableAgents.map((a) => a.name),
16138
+ skillsToSync
16139
+ });
16140
+ }
16141
+ return;
16142
+ }
16143
+ const results = [];
16144
+ for (const skillName of skillsToSync) {
16145
+ const deployResult = await deploySkillToAllPlatforms(skillName, {
16146
+ force: true,
16147
+ // Force to ensure repair
16148
+ agents: targetAgents
16149
+ });
16150
+ const details = [];
16151
+ for (const [agentName, result] of deployResult.results) {
16152
+ details.push({
16153
+ agent: agentName,
16154
+ success: result.success,
16155
+ path: result.deployedPath || void 0,
16156
+ error: result.error
16157
+ });
16158
+ }
16159
+ results.push({
16160
+ skillName,
16161
+ success: deployResult.successCount,
16162
+ failed: deployResult.failureCount,
16163
+ details
16164
+ });
16165
+ if (pretty && tty) {
16166
+ const statusParts = deployableAgents.map((agent) => {
16167
+ const result = deployResult.results.get(agent.name);
16168
+ return result?.success ? "\u2713" : "\u2717";
16169
+ });
16170
+ println(` ${skillName.padEnd(20)} ${statusParts.join(" ")}`);
16171
+ }
16172
+ }
16173
+ const totalSuccess = results.reduce((sum, r) => sum + r.success, 0);
16174
+ const totalFailed = results.reduce((sum, r) => sum + r.failed, 0);
16175
+ if (pretty && tty) {
16176
+ println("");
16177
+ printSuccess(
16178
+ `Done! ${deployableAgents.length} agent(s), ${skillsToSync.length} skill(s) synced.`
16179
+ );
16180
+ if (totalFailed > 0) {
16181
+ printError2(`${totalFailed} deployment(s) failed. Check logs for details.`);
16182
+ }
16183
+ } else {
16184
+ ok("platform.sync", {
16185
+ installedAgents: deployableAgents.map((a) => ({
16186
+ name: a.name,
16187
+ displayName: a.displayName,
16188
+ format: a.format,
16189
+ globalSkillsDir: a.globalSkillsDir
16190
+ })),
16191
+ skillsSynced: skillsToSync.length,
16192
+ totalSuccess,
16193
+ totalFailed,
16194
+ results
16195
+ });
16196
+ }
16197
+ } catch (error) {
16198
+ fail(
16199
+ ErrorCodes.INTERNAL_ERROR,
16200
+ error instanceof Error ? error.message : "Failed to sync platforms"
16201
+ );
16202
+ }
16203
+ });
16204
+
16205
+ // src/commands/platform/index.ts
16206
+ var platformCommand = new Command("platform").description("Manage multi-platform skill deployment").addCommand(platformSyncCommand);
16207
+
14880
16208
  // src/bin/refly.ts
14881
16209
  function getVersion() {
14882
16210
  try {
14883
- const pkgPath = path21.join(__dirname, "..", "..", "package.json");
14884
- const pkg = JSON.parse(fs26.readFileSync(pkgPath, "utf-8"));
16211
+ const pkgPath = path24.join(__dirname, "..", "..", "package.json");
16212
+ const pkg = JSON.parse(fs31.readFileSync(pkgPath, "utf-8"));
14885
16213
  return pkg.version || "0.1.0";
14886
16214
  } catch {
14887
16215
  return "0.1.0";
@@ -14922,6 +16250,7 @@ program2.addCommand(workflowCommand);
14922
16250
  program2.addCommand(toolCommand);
14923
16251
  program2.addCommand(fileCommand);
14924
16252
  program2.addCommand(skillCommand);
16253
+ program2.addCommand(platformCommand);
14925
16254
  program2.exitOverride((err) => {
14926
16255
  if (err.code === "commander.helpDisplayed" || err.code === "commander.version") {
14927
16256
  process.exit(0);