@skill-toolbox/cli 0.0.1
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 +62 -0
- package/dist/index.js +220 -0
- package/package.json +56 -0
package/README.md
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
# @skill-toolbox/cli
|
|
2
|
+
|
|
3
|
+
Command-line interface for managing Claude Code skills.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
pnpm add -g @skill-toolbox/cli
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Usage
|
|
12
|
+
|
|
13
|
+
### Install a Skill
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
# From GitHub
|
|
17
|
+
skill-toolbox install github:user/skill-repo
|
|
18
|
+
|
|
19
|
+
# From user/repo shorthand
|
|
20
|
+
skill-toolbox install user/skill-repo
|
|
21
|
+
|
|
22
|
+
# From local path
|
|
23
|
+
skill-toolbox install ./local/skill
|
|
24
|
+
|
|
25
|
+
# Custom installation directory
|
|
26
|
+
skill-toolbox install user/skill-repo --dir ./my-skills
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
### List Installed Skills
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
skill-toolbox list
|
|
33
|
+
|
|
34
|
+
# Custom skills directory
|
|
35
|
+
skill-toolbox list --dir ./my-skills
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
### Validate a Skill
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
# Validate skill file
|
|
42
|
+
skill-toolbox validate ./skills/my-skill/SKILL.md
|
|
43
|
+
|
|
44
|
+
# Validate skill directory
|
|
45
|
+
skill-toolbox validate ./skills/my-skill
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
## Commands
|
|
49
|
+
|
|
50
|
+
- `install <source>` - Install a skill from git or local path
|
|
51
|
+
- `list` - List installed skills
|
|
52
|
+
- `validate <path>` - Validate skill format
|
|
53
|
+
|
|
54
|
+
## Options
|
|
55
|
+
|
|
56
|
+
- `-d, --dir <directory>` - Skills directory (default: ./skills)
|
|
57
|
+
- `-h, --help` - Show help
|
|
58
|
+
- `-V, --version` - Show version
|
|
59
|
+
|
|
60
|
+
## License
|
|
61
|
+
|
|
62
|
+
MIT
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
"use strict";
|
|
3
|
+
var __create = Object.create;
|
|
4
|
+
var __defProp = Object.defineProperty;
|
|
5
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
6
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
7
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
8
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
9
|
+
var __copyProps = (to, from, except, desc) => {
|
|
10
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
11
|
+
for (let key of __getOwnPropNames(from))
|
|
12
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
13
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
14
|
+
}
|
|
15
|
+
return to;
|
|
16
|
+
};
|
|
17
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
18
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
19
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
20
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
21
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
22
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
23
|
+
mod
|
|
24
|
+
));
|
|
25
|
+
|
|
26
|
+
// src/index.ts
|
|
27
|
+
var import_commander = require("commander");
|
|
28
|
+
|
|
29
|
+
// src/commands/list.ts
|
|
30
|
+
var import_chalk = __toESM(require("chalk"));
|
|
31
|
+
|
|
32
|
+
// src/registry.ts
|
|
33
|
+
var import_fs_extra = __toESM(require("fs-extra"));
|
|
34
|
+
var import_path = __toESM(require("path"));
|
|
35
|
+
var import_core = require("@skill-toolbox/core");
|
|
36
|
+
var import_plugin_metadata = require("@skill-toolbox/plugin-metadata");
|
|
37
|
+
var import_utils = require("@skill-toolbox/utils");
|
|
38
|
+
var SkillRegistry = class {
|
|
39
|
+
constructor(skillsDir) {
|
|
40
|
+
this.skillsDir = skillsDir;
|
|
41
|
+
}
|
|
42
|
+
async listAll() {
|
|
43
|
+
const skills = [];
|
|
44
|
+
if (!await import_fs_extra.default.pathExists(this.skillsDir)) {
|
|
45
|
+
return skills;
|
|
46
|
+
}
|
|
47
|
+
const entries = await import_fs_extra.default.readdir(this.skillsDir, { withFileTypes: true });
|
|
48
|
+
for (const entry of entries) {
|
|
49
|
+
if (!entry.isDirectory()) continue;
|
|
50
|
+
const skill = await this.get(entry.name);
|
|
51
|
+
if (skill) {
|
|
52
|
+
skills.push(skill);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
return skills;
|
|
56
|
+
}
|
|
57
|
+
async get(name) {
|
|
58
|
+
const skillPath = import_path.default.join(this.skillsDir, name);
|
|
59
|
+
if (!await import_fs_extra.default.pathExists(skillPath)) {
|
|
60
|
+
return null;
|
|
61
|
+
}
|
|
62
|
+
const skillFile = await (0, import_utils.findSkillFile)(skillPath);
|
|
63
|
+
if (!skillFile) {
|
|
64
|
+
return null;
|
|
65
|
+
}
|
|
66
|
+
const markdown = await import_fs_extra.default.readFile(skillFile, "utf-8");
|
|
67
|
+
const parser = new import_core.SkillParser().use((0, import_plugin_metadata.metadataPlugin)());
|
|
68
|
+
return parser.parse(markdown);
|
|
69
|
+
}
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
// src/commands/list.ts
|
|
73
|
+
async function listCommand(skillsDir) {
|
|
74
|
+
const registry = new SkillRegistry(skillsDir);
|
|
75
|
+
const skills = await registry.listAll();
|
|
76
|
+
if (skills.length === 0) {
|
|
77
|
+
console.log(import_chalk.default.yellow("No skills found."));
|
|
78
|
+
console.log(import_chalk.default.gray("\nInstall skills with: skill-toolbox install <source>"));
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
console.log(import_chalk.default.bold("\nInstalled Skills:\n"));
|
|
82
|
+
for (const skill of skills) {
|
|
83
|
+
console.log(import_chalk.default.green(` ${skill.metadata.name}`) + import_chalk.default.gray(`@${skill.metadata.version}`));
|
|
84
|
+
if (skill.metadata.description) {
|
|
85
|
+
console.log(import_chalk.default.gray(` ${skill.metadata.description}`));
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
console.log(import_chalk.default.gray(`
|
|
89
|
+
Total: ${skills.length} skill(s)
|
|
90
|
+
`));
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// src/commands/validate.ts
|
|
94
|
+
var import_chalk2 = __toESM(require("chalk"));
|
|
95
|
+
var import_fs_extra2 = __toESM(require("fs-extra"));
|
|
96
|
+
var import_core2 = require("@skill-toolbox/core");
|
|
97
|
+
var import_plugin_metadata2 = require("@skill-toolbox/plugin-metadata");
|
|
98
|
+
var import_utils2 = require("@skill-toolbox/utils");
|
|
99
|
+
async function validateCommand(skillPath) {
|
|
100
|
+
const parser = new import_core2.SkillParser().use((0, import_plugin_metadata2.metadataPlugin)());
|
|
101
|
+
try {
|
|
102
|
+
const stat = await import_fs_extra2.default.stat(skillPath);
|
|
103
|
+
if (stat.isDirectory()) {
|
|
104
|
+
const skillFile = await (0, import_utils2.findSkillFile)(skillPath);
|
|
105
|
+
if (!skillFile) {
|
|
106
|
+
console.log(import_chalk2.default.red("\u2717"), skillPath);
|
|
107
|
+
console.log(import_chalk2.default.red(" Error: No skill file found (SKILL.md or README.md)"));
|
|
108
|
+
process.exit(1);
|
|
109
|
+
}
|
|
110
|
+
skillPath = skillFile;
|
|
111
|
+
}
|
|
112
|
+
const markdown = await import_fs_extra2.default.readFile(skillPath, "utf-8");
|
|
113
|
+
const skill = await parser.parse(markdown);
|
|
114
|
+
if (!skill.metadata.name) {
|
|
115
|
+
console.log(import_chalk2.default.red("\u2717"), skillPath);
|
|
116
|
+
console.log(import_chalk2.default.red(" Error: Missing required metadata field: name"));
|
|
117
|
+
process.exit(1);
|
|
118
|
+
}
|
|
119
|
+
if (!skill.metadata.version) {
|
|
120
|
+
console.log(import_chalk2.default.red("\u2717"), skillPath);
|
|
121
|
+
console.log(import_chalk2.default.red(" Error: Missing required metadata field: version"));
|
|
122
|
+
process.exit(1);
|
|
123
|
+
}
|
|
124
|
+
console.log(import_chalk2.default.green("\u2713"), skillPath);
|
|
125
|
+
console.log(import_chalk2.default.gray(` Name: ${skill.metadata.name}`));
|
|
126
|
+
console.log(import_chalk2.default.gray(` Version: ${skill.metadata.version}`));
|
|
127
|
+
if (skill.metadata.description) {
|
|
128
|
+
console.log(import_chalk2.default.gray(` Description: ${skill.metadata.description}`));
|
|
129
|
+
}
|
|
130
|
+
console.log();
|
|
131
|
+
} catch (error) {
|
|
132
|
+
console.log(import_chalk2.default.red("\u2717"), skillPath);
|
|
133
|
+
console.log(import_chalk2.default.red(` Error: ${error instanceof Error ? error.message : "Unknown error"}`));
|
|
134
|
+
process.exit(1);
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
// src/commands/install.ts
|
|
139
|
+
var import_chalk3 = __toESM(require("chalk"));
|
|
140
|
+
var import_ora = __toESM(require("ora"));
|
|
141
|
+
var import_fs_extra3 = __toESM(require("fs-extra"));
|
|
142
|
+
var import_path2 = __toESM(require("path"));
|
|
143
|
+
var import_git_source = require("@skill-toolbox/git-source");
|
|
144
|
+
var import_filesystem_source = require("@skill-toolbox/filesystem-source");
|
|
145
|
+
var import_plugin_metadata3 = require("@skill-toolbox/plugin-metadata");
|
|
146
|
+
var import_core3 = require("@skill-toolbox/core");
|
|
147
|
+
function isGitSource(source) {
|
|
148
|
+
return source.startsWith("github:") || source.startsWith("https://") || source.startsWith("git@") || source.endsWith(".git") || /^[\w-]+\/[\w-]+(:[\w\/-]*)?$/.test(source);
|
|
149
|
+
}
|
|
150
|
+
async function installCommand(source, options) {
|
|
151
|
+
const spinner = (0, import_ora.default)("Installing skill...").start();
|
|
152
|
+
try {
|
|
153
|
+
let skillSource;
|
|
154
|
+
if (isGitSource(source)) {
|
|
155
|
+
spinner.text = "Cloning repository...";
|
|
156
|
+
skillSource = new import_git_source.GitSource({
|
|
157
|
+
source,
|
|
158
|
+
skillPath: ""
|
|
159
|
+
// Auto-discover
|
|
160
|
+
});
|
|
161
|
+
} else {
|
|
162
|
+
spinner.text = "Loading from local path...";
|
|
163
|
+
skillSource = new import_filesystem_source.FilesystemSource({
|
|
164
|
+
path: source
|
|
165
|
+
});
|
|
166
|
+
}
|
|
167
|
+
const parser = new import_core3.SkillParser().use((0, import_plugin_metadata3.metadataPlugin)());
|
|
168
|
+
spinner.text = "Loading skills...";
|
|
169
|
+
const result = await skillSource.load();
|
|
170
|
+
if (result.errors.length > 0) {
|
|
171
|
+
for (const error of result.errors) {
|
|
172
|
+
spinner.fail(import_chalk3.default.red(`Error loading from ${error.path}: ${error.error.message}`));
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
if (result.skills.length === 0) {
|
|
176
|
+
spinner.fail(import_chalk3.default.red("No skills found"));
|
|
177
|
+
await skillSource.cleanup();
|
|
178
|
+
process.exit(1);
|
|
179
|
+
}
|
|
180
|
+
spinner.text = "Installing skills...";
|
|
181
|
+
await import_fs_extra3.default.ensureDir(options.dir);
|
|
182
|
+
const installedSkills = [];
|
|
183
|
+
for (const skillData of result.skills) {
|
|
184
|
+
const skill = await parser.parse(skillData.content);
|
|
185
|
+
const targetDir = import_path2.default.join(options.dir, skillData.baseName);
|
|
186
|
+
await import_fs_extra3.default.copy(skillData.directory, targetDir, { overwrite: true });
|
|
187
|
+
installedSkills.push({
|
|
188
|
+
name: skillData.baseName,
|
|
189
|
+
version: skill.metadata.version,
|
|
190
|
+
description: skill.metadata.description
|
|
191
|
+
});
|
|
192
|
+
}
|
|
193
|
+
await skillSource.cleanup();
|
|
194
|
+
spinner.succeed(import_chalk3.default.green(`\u2713 ${installedSkills.length} skill(s) installed successfully!`));
|
|
195
|
+
console.log("\nInstalled Skills:");
|
|
196
|
+
for (const skill of installedSkills) {
|
|
197
|
+
console.log(import_chalk3.default.gray(" \u2022"), import_chalk3.default.cyan(skill.name), skill.version ? import_chalk3.default.gray(`v${skill.version}`) : "");
|
|
198
|
+
if (skill.description) {
|
|
199
|
+
console.log(import_chalk3.default.gray(" "), skill.description);
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
} catch (error) {
|
|
203
|
+
spinner.fail(import_chalk3.default.red(`Failed to install skill: ${error instanceof Error ? error.message : "Unknown error"}`));
|
|
204
|
+
process.exit(1);
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
// src/index.ts
|
|
209
|
+
var program = new import_commander.Command();
|
|
210
|
+
program.name("skill-toolbox").description("CLI tool for discovering and managing Claude Code skills").version("1.0.0");
|
|
211
|
+
program.command("install <source>").description("Install a skill from git repository or local path").option("-d, --dir <directory>", "Installation directory", "./skills").action(async (source, options) => {
|
|
212
|
+
await installCommand(source, options);
|
|
213
|
+
});
|
|
214
|
+
program.command("list").description("List installed skills").option("-d, --dir <directory>", "Skills directory", "./skills").action(async (options) => {
|
|
215
|
+
await listCommand(options.dir);
|
|
216
|
+
});
|
|
217
|
+
program.command("validate <path>").description("Validate skill format").action(async (skillPath) => {
|
|
218
|
+
await validateCommand(skillPath);
|
|
219
|
+
});
|
|
220
|
+
program.parse();
|
package/package.json
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@skill-toolbox/cli",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"description": "Command-line interface for skill-toolbox",
|
|
5
|
+
"bin": {
|
|
6
|
+
"skill-toolbox": "./dist/index.js"
|
|
7
|
+
},
|
|
8
|
+
"main": "./dist/index.js",
|
|
9
|
+
"types": "./dist/index.d.ts",
|
|
10
|
+
"files": [
|
|
11
|
+
"dist"
|
|
12
|
+
],
|
|
13
|
+
"scripts": {
|
|
14
|
+
"dev": "tsup src/index.ts --format cjs --watch",
|
|
15
|
+
"build": "tsup src/index.ts --format cjs",
|
|
16
|
+
"clean": "rm -rf dist *.tsbuildinfo"
|
|
17
|
+
},
|
|
18
|
+
"dependencies": {
|
|
19
|
+
"@skill-toolbox/core": "workspace:*",
|
|
20
|
+
"@skill-toolbox/utils": "workspace:*",
|
|
21
|
+
"@skill-toolbox/git-source": "workspace:*",
|
|
22
|
+
"@skill-toolbox/filesystem-source": "workspace:*",
|
|
23
|
+
"@skill-toolbox/plugin-metadata": "workspace:*",
|
|
24
|
+
"commander": "^12.0.0",
|
|
25
|
+
"chalk": "^5.3.0",
|
|
26
|
+
"ora": "^8.0.0",
|
|
27
|
+
"fs-extra": "^11.2.0"
|
|
28
|
+
},
|
|
29
|
+
"devDependencies": {
|
|
30
|
+
"@types/fs-extra": "^11.0.4",
|
|
31
|
+
"tsup": "^8.0.0",
|
|
32
|
+
"vitest": "^1.2.0"
|
|
33
|
+
},
|
|
34
|
+
"publishConfig": {
|
|
35
|
+
"access": "public",
|
|
36
|
+
"registry": "https://registry.npmjs.org/"
|
|
37
|
+
},
|
|
38
|
+
"repository": {
|
|
39
|
+
"type": "git",
|
|
40
|
+
"url": "git+https://github.com/Link-Reverie/skill-toolbox.git",
|
|
41
|
+
"directory": "packages/cli"
|
|
42
|
+
},
|
|
43
|
+
"bugs": {
|
|
44
|
+
"url": "https://github.com/Link-Reverie/skill-toolbox/issues"
|
|
45
|
+
},
|
|
46
|
+
"homepage": "https://github.com/Link-Reverie/skill-toolbox#readme",
|
|
47
|
+
"license": "MIT",
|
|
48
|
+
"keywords": [
|
|
49
|
+
"skill",
|
|
50
|
+
"ai-agent",
|
|
51
|
+
"claude",
|
|
52
|
+
"llm",
|
|
53
|
+
"typescript",
|
|
54
|
+
"cli"
|
|
55
|
+
]
|
|
56
|
+
}
|