@powerformer/refly-cli 0.1.22 → 0.1.24

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