@iceinvein/agent-skills 0.1.4 → 0.1.6

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/README.md CHANGED
@@ -9,14 +9,22 @@
9
9
 
10
10
  Install agent skills into AI coding tools — Claude Code, Cursor, Codex, Gemini CLI.
11
11
 
12
+ ## Prerequisites
13
+
14
+ [Bun](https://bun.sh) is required. Install it with:
15
+
16
+ ```bash
17
+ curl -fsSL https://bun.sh/install | bash
18
+ ```
19
+
12
20
  ## Quick Start
13
21
 
14
22
  ```bash
15
23
  # Install a skill (auto-detects your tools)
16
- npx @iceinvein/agent-skills install design-review
24
+ bunx @iceinvein/agent-skills install design-review
17
25
 
18
26
  # Install for a specific tool
19
- npx @iceinvein/agent-skills install design-review --tool claude
27
+ bunx @iceinvein/agent-skills install design-review --tool claude
20
28
  ```
21
29
 
22
30
  ## Commands
package/dist/cli/index.js CHANGED
@@ -1,4 +1,5 @@
1
- #!/usr/bin/env node
1
+ #!/usr/bin/env bun
2
+ // @bun
2
3
  import { createRequire } from "node:module";
3
4
  var __require = /* @__PURE__ */ createRequire(import.meta.url);
4
5
 
@@ -449,6 +450,53 @@ async function installSkill(cwd, manifest, files, targetTools) {
449
450
  return { ok: true, installed, skipped };
450
451
  }
451
452
 
453
+ // src/cli/github.ts
454
+ var REPO2 = "iceinvein/agent-skills";
455
+ var BRANCH2 = "master";
456
+ var BASE2 = `https://raw.githubusercontent.com/${REPO2}/${BRANCH2}`;
457
+ function buildRawUrl2(skillName, filePath) {
458
+ return `${BASE2}/skills/${skillName}/${filePath}`;
459
+ }
460
+ async function fetchSkillManifest2(skillName) {
461
+ const url = buildRawUrl2(skillName, "skill.json");
462
+ const res = await fetch(url);
463
+ if (res.status === 404) {
464
+ return { ok: false, error: `Skill '${skillName}' not found` };
465
+ }
466
+ if (!res.ok) {
467
+ return { ok: false, error: `Failed to fetch manifest: HTTP ${res.status}` };
468
+ }
469
+ const data = await res.json();
470
+ return validateManifest(data);
471
+ }
472
+ async function fetchSkillFile2(skillName, filePath) {
473
+ const url = buildRawUrl2(skillName, filePath);
474
+ const res = await fetch(url);
475
+ if (!res.ok) {
476
+ return { ok: false, error: `Failed to fetch '${filePath}': HTTP ${res.status}` };
477
+ }
478
+ const content = await res.text();
479
+ return { ok: true, content };
480
+ }
481
+ async function fetchAllSkillFiles2(skillName, manifest) {
482
+ const files = new Map;
483
+ if (manifest.files?.prompt) {
484
+ const result = await fetchSkillFile2(skillName, manifest.files.prompt);
485
+ if (!result.ok)
486
+ return { error: result.error };
487
+ files.set(manifest.files.prompt, result.content);
488
+ }
489
+ if (manifest.files?.supporting) {
490
+ for (const supportFile of manifest.files.supporting) {
491
+ const result = await fetchSkillFile2(skillName, supportFile);
492
+ if (!result.ok)
493
+ return { error: result.error };
494
+ files.set(supportFile, result.content);
495
+ }
496
+ }
497
+ return files;
498
+ }
499
+
452
500
  // src/cli/commands/remove.ts
453
501
  async function removeSkill(cwd, skillName) {
454
502
  const lockfile = await readLockfile(cwd);
@@ -456,7 +504,7 @@ async function removeSkill(cwd, skillName) {
456
504
  if (!entry) {
457
505
  return { ok: false, error: `Skill '${skillName}' is not installed` };
458
506
  }
459
- const manifestResult = await fetchSkillManifest(skillName);
507
+ const manifestResult = await fetchSkillManifest2(skillName);
460
508
  if (manifestResult.ok) {
461
509
  for (const tool of entry.tools) {
462
510
  const adapter = getAdapter(tool);
@@ -489,9 +537,9 @@ async function removeSkill(cwd, skillName) {
489
537
  }
490
538
 
491
539
  // src/cli/commands/list.ts
492
- var REPO2 = "iceinvein/agent-skills";
493
- var BRANCH2 = "master";
494
- var INDEX_URL = `https://raw.githubusercontent.com/${REPO2}/${BRANCH2}/skills/index.json`;
540
+ var REPO3 = "iceinvein/agent-skills";
541
+ var BRANCH3 = "master";
542
+ var INDEX_URL = `https://raw.githubusercontent.com/${REPO3}/${BRANCH3}/skills/index.json`;
495
543
  async function listSkills() {
496
544
  const res = await fetch(INDEX_URL);
497
545
  if (!res.ok) {
@@ -503,7 +551,73 @@ async function listSkills() {
503
551
 
504
552
  // src/cli/commands/info.ts
505
553
  async function infoSkill(skillName) {
506
- return fetchSkillManifest(skillName);
554
+ return fetchSkillManifest2(skillName);
555
+ }
556
+
557
+ // src/cli/commands/remove.ts
558
+ async function removeSkill2(cwd, skillName) {
559
+ const lockfile = await readLockfile(cwd);
560
+ const entry = lockfile.skills[skillName];
561
+ if (!entry) {
562
+ return { ok: false, error: `Skill '${skillName}' is not installed` };
563
+ }
564
+ const manifestResult = await fetchSkillManifest2(skillName);
565
+ if (manifestResult.ok) {
566
+ for (const tool of entry.tools) {
567
+ const adapter = getAdapter(tool);
568
+ const toolFiles = entry.files.filter((f) => {
569
+ const config = manifestResult.manifest.install[tool];
570
+ if (!config)
571
+ return false;
572
+ if (config.prompt && f === config.prompt)
573
+ return true;
574
+ if (config.supporting && Object.values(config.supporting).includes(f))
575
+ return true;
576
+ if (config.mcpServers && (f.includes(".claude/settings") || f.includes(".cursor/mcp") || f.includes(".gemini/settings")))
577
+ return true;
578
+ return false;
579
+ });
580
+ await adapter.remove(cwd, manifestResult.manifest, toolFiles);
581
+ }
582
+ } else {
583
+ const { unlinkSync: unlinkSync4, existsSync: existsSync6 } = await import("node:fs");
584
+ const { join: join7 } = await import("node:path");
585
+ for (const file of entry.files) {
586
+ const fullPath = join7(cwd, file);
587
+ if (existsSync6(fullPath)) {
588
+ unlinkSync4(fullPath);
589
+ }
590
+ }
591
+ }
592
+ await removeSkillFromLockfile(cwd, skillName);
593
+ return { ok: true, removed: entry.files };
594
+ }
595
+
596
+ // src/cli/commands/install.ts
597
+ async function installSkill2(cwd, manifest, files, targetTools) {
598
+ const compatibleTools = targetTools.filter((t) => manifest.tools.includes(t));
599
+ const skipped = targetTools.filter((t) => !manifest.tools.includes(t));
600
+ if (compatibleTools.length === 0) {
601
+ return {
602
+ ok: false,
603
+ error: `Skill '${manifest.name}' does not support any of: ${targetTools.join(", ")}. Supported: ${manifest.tools.join(", ")}`
604
+ };
605
+ }
606
+ const installed = {};
607
+ const allFiles = [];
608
+ for (const tool of compatibleTools) {
609
+ const adapter = getAdapter(tool);
610
+ const toolFiles = await adapter.install(cwd, manifest, files);
611
+ installed[tool] = toolFiles;
612
+ allFiles.push(...toolFiles);
613
+ }
614
+ await addSkillToLockfile(cwd, manifest.name, {
615
+ version: manifest.version,
616
+ tools: compatibleTools,
617
+ installedAt: new Date().toISOString(),
618
+ files: allFiles
619
+ });
620
+ return { ok: true, installed, skipped };
507
621
  }
508
622
 
509
623
  // src/cli/commands/update.ts
@@ -515,23 +629,59 @@ async function updateSkill(cwd, skillName) {
515
629
  }
516
630
  const oldVersion = entry.version;
517
631
  const tools = entry.tools;
518
- const manifestResult = await fetchSkillManifest(skillName);
632
+ const manifestResult = await fetchSkillManifest2(skillName);
519
633
  if (!manifestResult.ok) {
520
634
  return { ok: false, error: manifestResult.error };
521
635
  }
522
- const filesResult = await fetchAllSkillFiles(skillName, manifestResult.manifest);
636
+ const filesResult = await fetchAllSkillFiles2(skillName, manifestResult.manifest);
523
637
  if ("error" in filesResult) {
524
638
  return { ok: false, error: filesResult.error };
525
639
  }
526
- await removeSkill(cwd, skillName);
527
- const installResult = await installSkill(cwd, manifestResult.manifest, filesResult, tools);
640
+ await removeSkill2(cwd, skillName);
641
+ const installResult = await installSkill2(cwd, manifestResult.manifest, filesResult, tools);
528
642
  if (!installResult.ok) {
529
643
  return { ok: false, error: installResult.error };
530
644
  }
531
645
  return { ok: true, from: oldVersion, to: manifestResult.manifest.version };
532
646
  }
533
647
 
648
+ // src/cli/types.ts
649
+ var TOOL_NAMES2 = ["claude", "cursor", "codex", "gemini"];
650
+
651
+ // src/cli/prompt.ts
652
+ import { createInterface } from "node:readline";
653
+ var rl = createInterface({ input: process.stdin, output: process.stdout });
654
+ function ask(question) {
655
+ return new Promise((resolve) => {
656
+ rl.question(question, (answer) => resolve(answer.trim()));
657
+ });
658
+ }
659
+ async function promptSelect(message, options) {
660
+ console.log(`
661
+ ${message}
662
+ `);
663
+ for (let i = 0;i < options.length; i++) {
664
+ console.log(` ${i + 1}) ${options[i].label}`);
665
+ }
666
+ console.log(` ${options.length + 1}) All of the above`);
667
+ const answer = await ask(`
668
+ Select (comma-separated numbers, e.g. 1,3): `);
669
+ rl.close();
670
+ const nums = answer.split(",").map((s) => parseInt(s.trim(), 10));
671
+ if (nums.includes(options.length + 1)) {
672
+ return options.map((o) => o.value);
673
+ }
674
+ const selected = nums.filter((n) => n >= 1 && n <= options.length).map((n) => options[n - 1].value);
675
+ if (selected.length === 0) {
676
+ console.error("No valid selection. Exiting.");
677
+ process.exit(1);
678
+ }
679
+ return selected;
680
+ }
681
+
534
682
  // src/cli/index.ts
683
+ import { mkdirSync as mkdirSync4 } from "fs";
684
+ import { join as join7 } from "path";
535
685
  function parseArgs(argv) {
536
686
  if (argv.length === 0)
537
687
  return { command: "help", args: [], flags: {} };
@@ -550,7 +700,7 @@ function parseArgs(argv) {
550
700
  }
551
701
  function printHelp() {
552
702
  console.log(`
553
- @iceinvein/agent-skills Install agent skills into AI coding tools
703
+ @iceinvein/agent-skills \u2014 Install agent skills into AI coding tools
554
704
 
555
705
  Usage:
556
706
  agent-skills install <skill> [--tool <tool>] Install a skill
@@ -559,20 +709,20 @@ Usage:
559
709
  agent-skills list List available skills
560
710
  agent-skills info <skill> Show skill details
561
711
 
562
- Tools: ${TOOL_NAMES.join(", ")}
712
+ Tools: ${TOOL_NAMES2.join(", ")}
563
713
 
564
714
  If --tool is omitted, auto-detects tools in the current directory.
565
715
  `);
566
716
  }
567
717
  function printInstalled(result, skipped) {
568
718
  for (const [tool, files] of Object.entries(result)) {
569
- console.log(` ${tool}`);
719
+ console.log(` \u2713 ${tool}`);
570
720
  for (const file of files) {
571
- console.log(` ${file}`);
721
+ console.log(` \u2192 ${file}`);
572
722
  }
573
723
  }
574
724
  for (const tool of skipped) {
575
- console.log(` ${tool} (skill does not support this tool)`);
725
+ console.log(` \u2298 ${tool} (skill does not support this tool)`);
576
726
  }
577
727
  }
578
728
  async function main() {
@@ -597,18 +747,33 @@ async function main() {
597
747
  }
598
748
  let tools;
599
749
  if (flags.tool) {
600
- if (!TOOL_NAMES.includes(flags.tool)) {
601
- console.error(`Error: unknown tool '${flags.tool}'. Must be one of: ${TOOL_NAMES.join(", ")}`);
750
+ if (!TOOL_NAMES2.includes(flags.tool)) {
751
+ console.error(`Error: unknown tool '${flags.tool}'. Must be one of: ${TOOL_NAMES2.join(", ")}`);
602
752
  process.exit(1);
603
753
  }
604
754
  tools = [flags.tool];
605
755
  } else {
606
756
  tools = await detectTools(process.cwd());
607
757
  if (tools.length === 0) {
608
- console.error("Error: no supported tools detected. Use --tool to specify one.");
609
- process.exit(1);
758
+ const supportedTools = manifestResult.manifest.tools;
759
+ const selected = await promptSelect("No tools detected in this directory. Which tools do you use?", supportedTools.map((t) => ({
760
+ label: { claude: "Claude Code", cursor: "Cursor", codex: "Codex", gemini: "Gemini CLI" }[t],
761
+ value: t
762
+ })));
763
+ tools = selected;
764
+ for (const tool of tools) {
765
+ const dirs = {
766
+ claude: ".claude",
767
+ cursor: ".cursor",
768
+ gemini: ".gemini"
769
+ };
770
+ if (dirs[tool]) {
771
+ mkdirSync4(join7(process.cwd(), dirs[tool]), { recursive: true });
772
+ }
773
+ }
774
+ } else {
775
+ console.log(`Detected tools: ${tools.join(", ")}`);
610
776
  }
611
- console.log(`Detected tools: ${tools.join(", ")}`);
612
777
  }
613
778
  const result = await installSkill(process.cwd(), manifestResult.manifest, filesResult, tools);
614
779
  if (!result.ok) {
@@ -616,7 +781,7 @@ async function main() {
616
781
  process.exit(1);
617
782
  }
618
783
  console.log(`
619
- Installed '${skillName}' v${manifestResult.manifest.version}:`);
784
+ \u2713 Installed '${skillName}' v${manifestResult.manifest.version}:`);
620
785
  printInstalled(result.installed, result.skipped);
621
786
  break;
622
787
  }
@@ -631,7 +796,7 @@ async function main() {
631
796
  console.error(`Error: ${result.error}`);
632
797
  process.exit(1);
633
798
  }
634
- console.log(`✓ Removed '${skillName}'`);
799
+ console.log(`\u2713 Removed '${skillName}'`);
635
800
  break;
636
801
  }
637
802
  case "update": {
@@ -646,7 +811,7 @@ async function main() {
646
811
  console.error(`Error: ${result.error}`);
647
812
  process.exit(1);
648
813
  }
649
- console.log(`✓ Updated '${skillName}' from v${result.from} to v${result.to}`);
814
+ console.log(`\u2713 Updated '${skillName}' from v${result.from} to v${result.to}`);
650
815
  break;
651
816
  }
652
817
  case "list": {
@@ -658,7 +823,7 @@ async function main() {
658
823
  process.exit(1);
659
824
  }
660
825
  for (const skill of result.skills) {
661
- const typeTag = skill.type === "prompt" ? "\uD83D\uDCDD" : skill.type === "code" ? "⚙️" : "\uD83D\uDD00";
826
+ const typeTag = skill.type === "prompt" ? "\uD83D\uDCDD" : skill.type === "code" ? "\u2699\uFE0F" : "\uD83D\uDD00";
662
827
  console.log(` ${typeTag} ${skill.name} (v${skill.version})`);
663
828
  console.log(` ${skill.description}
664
829
  `);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@iceinvein/agent-skills",
3
- "version": "0.1.4",
3
+ "version": "0.1.6",
4
4
  "description": "Install agent skills into AI coding tools",
5
5
  "author": "iceinvein",
6
6
  "license": "MIT",
@@ -13,7 +13,7 @@
13
13
  "skills"
14
14
  ],
15
15
  "scripts": {
16
- "build": "bun build src/cli/index.ts --outdir dist/cli --target node && sed -i'' -e '1s|#!/usr/bin/env bun|#!/usr/bin/env node|' dist/cli/index.js",
16
+ "build": "bun build src/cli/index.ts --outdir dist/cli --target bun",
17
17
  "test": "bun test",
18
18
  "dev": "bun run src/cli/index.ts"
19
19
  },