skild 0.0.7 → 0.1.0

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.
Files changed (3) hide show
  1. package/README.md +20 -0
  2. package/dist/index.js +248 -102
  3. package/package.json +5 -7
package/README.md CHANGED
@@ -12,4 +12,24 @@ npm i -g skild
12
12
 
13
13
  ```bash
14
14
  skild --help
15
+
16
+ # Install a skill (Git URL / degit shorthand / local dir)
17
+ skild install https://github.com/anthropics/skills/tree/main/skills/pdf
18
+ skild install anthropics/skills/skills/pdf#main
19
+ skild install ./path/to/your-skill
20
+
21
+ # Target platform + project-level install
22
+ skild install https://github.com/anthropics/skills/tree/main/skills/pdf -t codex --local
23
+
24
+ # List installed skills
25
+ skild list -t codex --local
26
+
27
+ # Inspect / Validate / Update / Uninstall
28
+ skild info pdf -t codex --local
29
+ skild validate pdf -t codex --local
30
+ skild update pdf -t codex --local
31
+ skild uninstall pdf -t codex --local
32
+
33
+ # Create a new Skill
34
+ skild init my-skill
15
35
  ```
package/dist/index.js CHANGED
@@ -2,137 +2,283 @@
2
2
 
3
3
  // src/index.ts
4
4
  import { Command } from "commander";
5
- import chalk3 from "chalk";
5
+ import chalk9 from "chalk";
6
+ import { createRequire } from "module";
6
7
 
7
8
  // src/commands/install.ts
8
- import { execSync } from "child_process";
9
- import path2 from "path";
10
- import fs2 from "fs";
9
+ import chalk2 from "chalk";
10
+ import { installSkill, SkildError } from "@skild/core";
11
+
12
+ // src/utils/logger.ts
11
13
  import chalk from "chalk";
12
14
  import ora from "ora";
13
-
14
- // src/utils/config.ts
15
- import os from "os";
16
- import path from "path";
17
- import fs from "fs";
18
- function getSkillsDir(platform = "claude", projectLevel = false) {
19
- const base = projectLevel ? process.cwd() : os.homedir();
20
- switch (platform) {
21
- case "claude":
22
- return path.join(base, projectLevel ? ".claude" : ".claude", "skills");
23
- case "codex":
24
- return path.join(base, projectLevel ? ".codex" : ".codex", "skills");
25
- case "copilot":
26
- return path.join(base, ".github", "skills");
27
- default:
28
- return path.join(base, ".claude", "skills");
29
- }
15
+ function createSpinner(message) {
16
+ return ora(message).start();
30
17
  }
31
- var SKILLS_DIR = getSkillsDir("claude", false);
32
- function ensureSkillsDir(platform = "claude", projectLevel = false) {
33
- const dir = getSkillsDir(platform, projectLevel);
34
- if (!fs.existsSync(dir)) {
35
- fs.mkdirSync(dir, { recursive: true });
18
+ var logger = {
19
+ /**
20
+ * Log a success message with green checkmark.
21
+ */
22
+ success: (message) => {
23
+ console.log(chalk.green("\u2713"), message);
24
+ },
25
+ /**
26
+ * Log a warning message with yellow color.
27
+ */
28
+ warn: (message) => {
29
+ console.log(chalk.yellow("\u26A0"), message);
30
+ },
31
+ /**
32
+ * Log an error message with red color.
33
+ */
34
+ error: (message) => {
35
+ console.error(chalk.red("\u2717"), message);
36
+ },
37
+ /**
38
+ * Log an info message with cyan color.
39
+ */
40
+ info: (message) => {
41
+ console.log(chalk.cyan("\u2139"), message);
42
+ },
43
+ /**
44
+ * Log a dimmed/subtle message.
45
+ */
46
+ dim: (message) => {
47
+ console.log(chalk.dim(message));
48
+ },
49
+ /**
50
+ * Log a bold header.
51
+ */
52
+ header: (message) => {
53
+ console.log(chalk.bold(message));
54
+ },
55
+ /**
56
+ * Log a skill entry with status indicator.
57
+ */
58
+ skillEntry: (name, path, hasSkillMd) => {
59
+ const status = hasSkillMd ? chalk.green("\u2713") : chalk.yellow("\u26A0");
60
+ console.log(` ${status} ${chalk.cyan(name)}`);
61
+ console.log(chalk.dim(` \u2514\u2500 ${path}`));
62
+ },
63
+ /**
64
+ * Log installation result details.
65
+ */
66
+ installDetail: (message, isWarning = false) => {
67
+ const color = isWarning ? chalk.yellow : chalk.dim;
68
+ console.log(color(` \u2514\u2500 ${message}`));
36
69
  }
37
- return dir;
38
- }
39
- function getSkillPath(skillName, platform = "claude", projectLevel = false) {
40
- return path.join(getSkillsDir(platform, projectLevel), skillName);
41
- }
70
+ };
42
71
 
43
72
  // src/commands/install.ts
44
- function extractSkillName(url) {
45
- const treeMatch = url.match(/\/tree\/[^/]+\/(.+?)(?:\/)?$/);
46
- if (treeMatch) {
47
- return treeMatch[1].split("/").pop() || "unknown-skill";
48
- }
49
- const repoMatch = url.match(/github\.com\/[^/]+\/([^/]+)/);
50
- if (repoMatch) {
51
- return repoMatch[1].replace(/\.git$/, "");
52
- }
53
- return "unknown-skill";
54
- }
55
- function toDegitPath(url) {
56
- const treeMatch = url.match(/github\.com\/([^/]+)\/([^/]+)\/tree\/([^/]+)\/(.+?)(?:\/)?$/);
57
- if (treeMatch) {
58
- const [, owner, repo, branch, subpath] = treeMatch;
59
- return `${owner}/${repo}/${subpath}#${branch}`;
60
- }
61
- const repoMatch = url.match(/github\.com\/([^/]+\/[^/]+)/);
62
- if (repoMatch) {
63
- return repoMatch[1].replace(/\.git$/, "");
64
- }
65
- return url;
66
- }
67
73
  async function install(source, options = {}) {
68
74
  const platform = options.target || "claude";
69
- const projectLevel = options.local || false;
70
- ensureSkillsDir(platform, projectLevel);
71
- const skillName = extractSkillName(source);
72
- const targetPath = getSkillPath(skillName, platform, projectLevel);
73
- const degitPath = toDegitPath(source);
74
- const locationLabel = projectLevel ? "project" : "global";
75
- const spinner = ora(`Installing ${chalk.cyan(skillName)} to ${chalk.dim(platform)} (${locationLabel})...`).start();
75
+ const scope = options.local ? "project" : "global";
76
+ const spinner = createSpinner(`Installing ${chalk2.cyan(source)} to ${chalk2.dim(platform)} (${scope})...`);
76
77
  try {
77
- execSync(`npx degit ${degitPath} "${targetPath}" --force`, {
78
- stdio: "pipe"
79
- });
80
- spinner.succeed(`Installed ${chalk.green(skillName)} to ${chalk.dim(targetPath)}`);
81
- const skillMdPath = path2.join(targetPath, "SKILL.md");
82
- const hasSkillMd = fs2.existsSync(skillMdPath);
83
- if (hasSkillMd) {
84
- console.log(chalk.dim(` \u2514\u2500 SKILL.md found \u2713`));
78
+ const record = await installSkill(
79
+ { source },
80
+ {
81
+ platform,
82
+ scope,
83
+ force: Boolean(options.force)
84
+ }
85
+ );
86
+ spinner.succeed(`Installed ${chalk2.green(record.name)} to ${chalk2.dim(record.installDir)}`);
87
+ if (options.json) {
88
+ console.log(JSON.stringify(record, null, 2));
89
+ return;
90
+ }
91
+ if (record.hasSkillMd) {
92
+ logger.installDetail("SKILL.md found \u2713");
85
93
  } else {
86
- console.log(chalk.yellow(` \u2514\u2500 Warning: No SKILL.md found`));
94
+ logger.installDetail("Warning: No SKILL.md found", true);
95
+ }
96
+ if (record.skill?.validation && !record.skill.validation.ok) {
97
+ logger.installDetail(`Validation: ${chalk2.yellow("failed")} (${record.skill.validation.issues.length} issues)`, true);
98
+ } else if (record.skill?.validation?.ok) {
99
+ logger.installDetail(`Validation: ${chalk2.green("ok")}`);
87
100
  }
88
101
  } catch (error) {
89
- spinner.fail(`Failed to install ${chalk.red(skillName)}`);
90
- console.error(chalk.red(error.message || error));
91
- process.exit(1);
102
+ spinner.fail(`Failed to install ${chalk2.red(source)}`);
103
+ const message = error instanceof SkildError ? error.message : error instanceof Error ? error.message : String(error);
104
+ console.error(chalk2.red(message));
105
+ process.exitCode = 1;
92
106
  }
93
107
  }
94
108
 
95
109
  // src/commands/list.ts
96
- import fs3 from "fs";
97
- import path3 from "path";
98
- import chalk2 from "chalk";
99
- async function list() {
100
- ensureSkillsDir();
101
- const entries = fs3.readdirSync(SKILLS_DIR, { withFileTypes: true });
102
- const skills = entries.filter((e) => e.isDirectory());
110
+ import chalk3 from "chalk";
111
+ import { listSkills } from "@skild/core";
112
+ async function list(options = {}) {
113
+ const platform = options.target || "claude";
114
+ const scope = options.local ? "project" : "global";
115
+ const skills = listSkills({ platform, scope });
116
+ if (options.json) {
117
+ console.log(JSON.stringify(skills, null, 2));
118
+ return;
119
+ }
103
120
  if (skills.length === 0) {
104
- console.log(chalk2.dim("No skills installed."));
105
- console.log(chalk2.dim(`Use ${chalk2.cyan("skild install <url>")} to install a skill.`));
121
+ console.log(chalk3.dim("No skills installed."));
122
+ console.log(chalk3.dim(`Use ${chalk3.cyan("skild install <source>")} to install a skill.`));
106
123
  return;
107
124
  }
108
- console.log(chalk2.bold(`
109
- \u{1F4E6} Installed Skills (${skills.length}):
125
+ console.log(chalk3.bold(`
126
+ \u{1F4E6} Installed Skills (${skills.length}) \u2014 ${platform} (${scope}):
110
127
  `));
111
- for (const skill of skills) {
112
- const skillPath = path3.join(SKILLS_DIR, skill.name);
113
- const skillMdPath = path3.join(skillPath, "SKILL.md");
114
- const hasSkillMd = fs3.existsSync(skillMdPath);
115
- const status = hasSkillMd ? chalk2.green("\u2713") : chalk2.yellow("\u26A0");
116
- console.log(` ${status} ${chalk2.cyan(skill.name)}`);
117
- console.log(chalk2.dim(` \u2514\u2500 ${skillPath}`));
128
+ for (const s of skills) {
129
+ const status = s.hasSkillMd ? chalk3.green("\u2713") : chalk3.yellow("\u26A0");
130
+ console.log(` ${status} ${chalk3.cyan(s.name)}`);
131
+ console.log(chalk3.dim(` \u2514\u2500 ${s.installDir}`));
118
132
  }
119
133
  console.log("");
120
134
  }
121
135
 
136
+ // src/commands/info.ts
137
+ import chalk4 from "chalk";
138
+ import { getSkillInfo, SkildError as SkildError2 } from "@skild/core";
139
+ async function info(skill, options = {}) {
140
+ const platform = options.target || "claude";
141
+ const scope = options.local ? "project" : "global";
142
+ try {
143
+ const record = getSkillInfo(skill, { platform, scope });
144
+ if (options.json) {
145
+ console.log(JSON.stringify(record, null, 2));
146
+ return;
147
+ }
148
+ console.log(chalk4.bold(`
149
+ ${chalk4.cyan(record.name)}
150
+ `));
151
+ console.log(` ${chalk4.dim("Path:")} ${record.installDir}`);
152
+ console.log(` ${chalk4.dim("Source:")} ${record.source}`);
153
+ console.log(` ${chalk4.dim("Target:")} ${record.platform} (${record.scope})`);
154
+ console.log(` ${chalk4.dim("Installed:")} ${record.installedAt}`);
155
+ if (record.updatedAt) console.log(` ${chalk4.dim("Updated:")} ${record.updatedAt}`);
156
+ console.log(` ${chalk4.dim("Hash:")} ${record.contentHash}`);
157
+ console.log(` ${chalk4.dim("SKILL.md:")} ${record.hasSkillMd ? chalk4.green("yes") : chalk4.yellow("no")}`);
158
+ const validation = record.skill?.validation;
159
+ if (validation) {
160
+ console.log(` ${chalk4.dim("Validate:")} ${validation.ok ? chalk4.green("ok") : chalk4.red("failed")}`);
161
+ if (!validation.ok) {
162
+ for (const issue of validation.issues) {
163
+ const color = issue.level === "error" ? chalk4.red : chalk4.yellow;
164
+ console.log(` - ${color(issue.level)}: ${issue.message}`);
165
+ }
166
+ }
167
+ }
168
+ console.log("");
169
+ } catch (error) {
170
+ const message = error instanceof SkildError2 ? error.message : error instanceof Error ? error.message : String(error);
171
+ console.error(chalk4.red(message));
172
+ process.exitCode = 1;
173
+ }
174
+ }
175
+
176
+ // src/commands/uninstall.ts
177
+ import chalk5 from "chalk";
178
+ import { uninstallSkill, SkildError as SkildError3 } from "@skild/core";
179
+ async function uninstall(skill, options = {}) {
180
+ const platform = options.target || "claude";
181
+ const scope = options.local ? "project" : "global";
182
+ const spinner = createSpinner(`Uninstalling ${chalk5.cyan(skill)} from ${chalk5.dim(platform)} (${scope})...`);
183
+ try {
184
+ uninstallSkill(skill, { platform, scope, allowMissingMetadata: Boolean(options.force) });
185
+ spinner.succeed(`Uninstalled ${chalk5.green(skill)}`);
186
+ } catch (error) {
187
+ spinner.fail(`Failed to uninstall ${chalk5.red(skill)}`);
188
+ const message = error instanceof SkildError3 ? error.message : error instanceof Error ? error.message : String(error);
189
+ console.error(chalk5.red(message));
190
+ process.exitCode = 1;
191
+ }
192
+ }
193
+
194
+ // src/commands/update.ts
195
+ import chalk6 from "chalk";
196
+ import { updateSkill, SkildError as SkildError4 } from "@skild/core";
197
+ async function update(skill, options = {}) {
198
+ const platform = options.target || "claude";
199
+ const scope = options.local ? "project" : "global";
200
+ const label = skill ? skill : "all skills";
201
+ const spinner = createSpinner(`Updating ${chalk6.cyan(label)} on ${chalk6.dim(platform)} (${scope})...`);
202
+ try {
203
+ const results = await updateSkill(skill, { platform, scope });
204
+ spinner.succeed(`Updated ${chalk6.green(results.length.toString())} skill(s).`);
205
+ if (options.json) {
206
+ console.log(JSON.stringify(results, null, 2));
207
+ }
208
+ } catch (error) {
209
+ spinner.fail(`Failed to update ${chalk6.red(label)}`);
210
+ const message = error instanceof SkildError4 ? error.message : error instanceof Error ? error.message : String(error);
211
+ console.error(chalk6.red(message));
212
+ process.exitCode = 1;
213
+ }
214
+ }
215
+
216
+ // src/commands/validate.ts
217
+ import chalk7 from "chalk";
218
+ import { validateSkill } from "@skild/core";
219
+ async function validate(target, options = {}) {
220
+ const platform = options.target || "claude";
221
+ const scope = options.local ? "project" : "global";
222
+ const value = target || ".";
223
+ const result = validateSkill(value, { platform, scope });
224
+ if (options.json) {
225
+ console.log(JSON.stringify(result, null, 2));
226
+ process.exitCode = result.ok ? 0 : 1;
227
+ return;
228
+ }
229
+ if (result.ok) {
230
+ console.log(chalk7.green("\u2713"), "Valid skill");
231
+ if (result.frontmatter?.name) console.log(chalk7.dim(` name: ${result.frontmatter.name}`));
232
+ return;
233
+ }
234
+ console.error(chalk7.red("\u2717"), "Invalid skill");
235
+ for (const issue of result.issues) {
236
+ const color = issue.level === "error" ? chalk7.red : chalk7.yellow;
237
+ console.error(` - ${color(issue.level)}: ${issue.message}`);
238
+ }
239
+ process.exitCode = 1;
240
+ }
241
+
242
+ // src/commands/init.ts
243
+ import chalk8 from "chalk";
244
+ import { initSkill, SkildError as SkildError5 } from "@skild/core";
245
+ async function init(name, options = {}) {
246
+ const spinner = createSpinner(`Initializing ${chalk8.cyan(name)}...`);
247
+ try {
248
+ const createdDir = initSkill(name, {
249
+ dir: options.dir,
250
+ description: options.description,
251
+ force: Boolean(options.force)
252
+ });
253
+ spinner.succeed(`Created ${chalk8.green(name)} at ${chalk8.dim(createdDir)}`);
254
+ console.log(chalk8.dim(`Next: cd ${createdDir} && skild validate .`));
255
+ } catch (error) {
256
+ spinner.fail(`Failed to init ${chalk8.red(name)}`);
257
+ const message = error instanceof SkildError5 ? error.message : error instanceof Error ? error.message : String(error);
258
+ console.error(chalk8.red(message));
259
+ process.exitCode = 1;
260
+ }
261
+ }
262
+
122
263
  // src/index.ts
264
+ import { PLATFORMS } from "@skild/core";
265
+ var require2 = createRequire(import.meta.url);
266
+ var { version } = require2("../package.json");
123
267
  var program = new Command();
124
- program.name("skild").description("The npm for Agent Skills \u2014 Discover, install, manage, and publish AI Agent Skills with ease.").version("0.0.1");
125
- program.command("install <source>").alias("i").description("Install a Skill from a GitHub URL or registry name").option("-t, --target <platform>", "Target platform: claude, codex, copilot", "claude").option("-l, --local", "Install to project-level directory instead of global").action(async (source, options) => {
126
- await install(source, {
127
- target: options.target,
128
- local: options.local
129
- });
130
- });
131
- program.command("list").alias("ls").description("List installed Skills").action(async () => {
132
- await list();
268
+ program.name("skild").description("The npm for Agent Skills \u2014 Discover, install, manage, and publish AI Agent Skills with ease.").version(version);
269
+ program.command("install <source>").alias("i").description("Install a Skill from a Git URL, degit shorthand, or local directory").option("-t, --target <platform>", `Target platform: ${PLATFORMS.join(", ")}`, "claude").option("-l, --local", "Install to project-level directory instead of global").option("-f, --force", "Overwrite existing installation").option("--json", "Output JSON").action(async (source, options) => {
270
+ await install(source, options);
133
271
  });
272
+ program.command("list").alias("ls").description("List installed Skills").option("-t, --target <platform>", `Target platform: ${PLATFORMS.join(", ")}`, "claude").option("-l, --local", "List project-level directory instead of global").option("--json", "Output JSON").action(async (options) => list(options));
273
+ program.command("info <skill>").description("Show installed Skill details").option("-t, --target <platform>", `Target platform: ${PLATFORMS.join(", ")}`, "claude").option("-l, --local", "Use project-level directory instead of global").option("--json", "Output JSON").action(async (skill, options) => info(skill, options));
274
+ program.command("uninstall <skill>").alias("rm").description("Uninstall a Skill").option("-t, --target <platform>", `Target platform: ${PLATFORMS.join(", ")}`, "claude").option("-l, --local", "Use project-level directory instead of global").option("-f, --force", "Uninstall even if metadata is missing").action(async (skill, options) => uninstall(skill, options));
275
+ program.command("update [skill]").alias("up").description("Update one or all installed Skills").option("-t, --target <platform>", `Target platform: ${PLATFORMS.join(", ")}`, "claude").option("-l, --local", "Use project-level directory instead of global").option("--json", "Output JSON").action(async (skill, options) => update(skill, options));
276
+ program.command("validate [target]").alias("v").description("Validate a Skill folder (path) or an installed Skill name").option("-t, --target <platform>", `Target platform: ${PLATFORMS.join(", ")}`, "claude").option("-l, --local", "Use project-level directory instead of global").option("--json", "Output JSON").action(async (target, options) => validate(target, options));
277
+ program.command("init <name>").description("Create a new Skill project").option("--dir <path>", "Target directory (defaults to <name>)").option("--description <text>", "Skill description").option("-f, --force", "Overwrite target directory if it exists").action(async (name, options) => init(name, options));
134
278
  program.action(() => {
135
- console.log(chalk3.bold("\n\u{1F6E1}\uFE0F skild \u2014 Get your agents skilled.\n"));
279
+ console.log(chalk9.bold("\n\u{1F6E1}\uFE0F skild \u2014 Get your agents skilled.\n"));
136
280
  program.outputHelp();
137
281
  });
138
- program.parse();
282
+ var argv = process.argv.slice();
283
+ if (argv[2] === "--") argv.splice(2, 1);
284
+ program.parse(argv);
package/package.json CHANGED
@@ -1,11 +1,11 @@
1
1
  {
2
2
  "name": "skild",
3
- "version": "0.0.7",
3
+ "version": "0.1.0",
4
4
  "description": "The npm for Agent Skills — Discover, install, manage, and publish AI Agent Skills with ease.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
7
7
  "bin": {
8
- "skild": "./dist/index.js"
8
+ "skild": "dist/index.js"
9
9
  },
10
10
  "files": [
11
11
  "dist",
@@ -35,12 +35,11 @@
35
35
  "dependencies": {
36
36
  "chalk": "^5.3.0",
37
37
  "commander": "^12.1.0",
38
- "degit": "^2.8.4",
39
- "ora": "^8.0.1"
38
+ "ora": "^8.0.1",
39
+ "@skild/core": "^0.1.0"
40
40
  },
41
41
  "devDependencies": {
42
42
  "@types/node": "^20.10.0",
43
- "bumpp": "^10.3.2",
44
43
  "tsup": "^8.0.0",
45
44
  "typescript": "^5.3.0"
46
45
  },
@@ -51,7 +50,6 @@
51
50
  "build": "tsup src/index.ts --format esm --dts --clean",
52
51
  "dev": "tsup src/index.ts --format esm --watch",
53
52
  "start": "node dist/index.js",
54
- "typecheck": "tsc -p tsconfig.json --noEmit",
55
- "release": "pnpm build && bumpp && pnpm publish --no-git-checks"
53
+ "typecheck": "pnpm -C ../core build && tsc -p tsconfig.json --noEmit"
56
54
  }
57
55
  }