@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 +10 -2
- package/dist/cli/index.js +189 -24
- package/package.json +2 -2
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
|
-
|
|
24
|
+
bunx @iceinvein/agent-skills install design-review
|
|
17
25
|
|
|
18
26
|
# Install for a specific tool
|
|
19
|
-
|
|
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
|
|
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
|
|
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
|
|
493
|
-
var
|
|
494
|
-
var INDEX_URL = `https://raw.githubusercontent.com/${
|
|
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
|
|
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
|
|
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
|
|
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
|
|
527
|
-
const installResult = await
|
|
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
|
|
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: ${
|
|
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(`
|
|
719
|
+
console.log(` \u2713 ${tool}`);
|
|
570
720
|
for (const file of files) {
|
|
571
|
-
console.log(`
|
|
721
|
+
console.log(` \u2192 ${file}`);
|
|
572
722
|
}
|
|
573
723
|
}
|
|
574
724
|
for (const tool of skipped) {
|
|
575
|
-
console.log(`
|
|
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 (!
|
|
601
|
-
console.error(`Error: unknown tool '${flags.tool}'. Must be one of: ${
|
|
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
|
-
|
|
609
|
-
|
|
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
|
-
|
|
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(
|
|
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(
|
|
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" ? "
|
|
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.
|
|
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
|
|
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
|
},
|