skild 0.2.6 → 0.2.8

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 (2) hide show
  1. package/dist/index.js +144 -78
  2. package/package.json +2 -2
package/dist/index.js CHANGED
@@ -6,8 +6,10 @@ import chalk15 from "chalk";
6
6
  import { createRequire } from "module";
7
7
 
8
8
  // src/commands/install.ts
9
+ import fs from "fs";
10
+ import path from "path";
9
11
  import chalk2 from "chalk";
10
- import { fetchWithTimeout, installRegistrySkill, installSkill, loadRegistryAuth, resolveRegistryUrl, SkildError } from "@skild/core";
12
+ import { fetchWithTimeout, installRegistrySkill, installSkill, loadRegistryAuth, resolveRegistryAlias, resolveRegistryUrl, SkildError } from "@skild/core";
11
13
 
12
14
  // src/utils/logger.ts
13
15
  import chalk from "chalk";
@@ -70,17 +72,43 @@ var logger = {
70
72
  };
71
73
 
72
74
  // src/commands/install.ts
75
+ function looksLikeAlias(input) {
76
+ const s = input.trim();
77
+ if (!s) return false;
78
+ if (s.startsWith("@")) return false;
79
+ if (s.includes("/") || s.includes("\\")) return false;
80
+ if (/^https?:\/\//i.test(s) || s.includes("github.com")) return false;
81
+ if (fs.existsSync(path.resolve(s))) return false;
82
+ if (s.length < 3 || s.length > 64) return false;
83
+ if (!/^[a-z0-9][a-z0-9-]*[a-z0-9]$/.test(s)) return false;
84
+ if (s.includes("--")) return false;
85
+ return true;
86
+ }
73
87
  async function install(source, options = {}) {
74
88
  const platform = options.target || "claude";
75
89
  const scope = options.local ? "project" : "global";
76
90
  const auth = loadRegistryAuth();
77
91
  const registryUrlForDeps = options.registry || auth?.registryUrl;
92
+ let resolvedSource = source.trim();
93
+ try {
94
+ if (looksLikeAlias(resolvedSource)) {
95
+ const registryUrl = resolveRegistryUrl(registryUrlForDeps);
96
+ const resolved = await resolveRegistryAlias(registryUrl, resolvedSource);
97
+ if (!options.json) logger.info(`Resolved ${chalk2.cyan(resolvedSource)} \u2192 ${chalk2.cyan(resolved.spec)} (${resolved.type})`);
98
+ resolvedSource = resolved.spec;
99
+ }
100
+ } catch (error) {
101
+ const message = error instanceof SkildError ? error.message : error instanceof Error ? error.message : String(error);
102
+ console.error(chalk2.red(message));
103
+ process.exitCode = 1;
104
+ return;
105
+ }
78
106
  const spinner = createSpinner(`Installing ${chalk2.cyan(source)} to ${chalk2.dim(platform)} (${scope})...`);
79
107
  try {
80
- const record = source.trim().startsWith("@") && source.includes("/") ? await installRegistrySkill(
81
- { spec: source, registryUrl: registryUrlForDeps },
108
+ const record = resolvedSource.startsWith("@") && resolvedSource.includes("/") ? await installRegistrySkill(
109
+ { spec: resolvedSource, registryUrl: registryUrlForDeps },
82
110
  { platform, scope, force: Boolean(options.force) }
83
- ) : await installSkill({ source }, { platform, scope, force: Boolean(options.force), registryUrl: registryUrlForDeps });
111
+ ) : await installSkill({ source: resolvedSource }, { platform, scope, force: Boolean(options.force), registryUrl: registryUrlForDeps });
84
112
  const displayName = record.canonicalName || record.name;
85
113
  spinner.succeed(`Installed ${chalk2.green(displayName)} to ${chalk2.dim(record.installDir)}`);
86
114
  if (options.json) {
@@ -138,54 +166,122 @@ async function reportDownload(record, registryOverride) {
138
166
 
139
167
  // src/commands/list.ts
140
168
  import chalk3 from "chalk";
141
- import fs from "fs";
142
- import path from "path";
143
169
  import { PLATFORMS, listAllSkills, listSkills } from "@skild/core";
144
- function toDisplayName(name, mapping) {
145
- return mapping.get(name) || name;
170
+ function isSkillset(skill) {
171
+ return Boolean(skill.record?.skillset || skill.record?.skill?.frontmatter?.skillset);
146
172
  }
147
- function buildDisplayEntries(skills) {
148
- const nameToDisplay = /* @__PURE__ */ new Map();
149
- for (const skill of skills) {
150
- const displayName = skill.record?.canonicalName || skill.name;
151
- nameToDisplay.set(skill.name, displayName);
152
- }
153
- const entries = skills.map((skill) => {
154
- const displayName = toDisplayName(skill.name, nameToDisplay);
155
- const flags = [];
156
- if (skill.record?.skillset || skill.record?.skill?.frontmatter?.skillset) {
157
- flags.push("skillset");
158
- }
159
- if (skill.record?.dependedBy?.length) {
160
- const dependedBy = skill.record.dependedBy.map((name) => toDisplayName(name, nameToDisplay));
161
- flags.push(`dep of: ${dependedBy.join(", ")}`);
162
- }
163
- return {
164
- name: displayName,
165
- installDir: skill.installDir,
166
- status: skill.hasSkillMd ? "ok" : "warn",
167
- flags
168
- };
169
- });
173
+ function getDisplayName(skill) {
174
+ return skill.record?.canonicalName || skill.record?.skill?.frontmatter?.name || skill.name;
175
+ }
176
+ function buildNameToDisplay(skills) {
177
+ const mapping = /* @__PURE__ */ new Map();
170
178
  for (const skill of skills) {
171
- const inlineDeps = skill.record?.installedDependencies?.filter((dep) => dep.sourceType === "inline") || [];
172
- if (!inlineDeps.length) continue;
173
- const ownerName = toDisplayName(skill.name, nameToDisplay);
174
- for (const dep of inlineDeps) {
175
- const inlineDir = dep.inlinePath ? path.join(skill.installDir, dep.inlinePath) : path.join(skill.installDir, dep.name);
176
- const hasSkillMd = fs.existsSync(path.join(inlineDir, "SKILL.md"));
177
- entries.push({
178
- name: dep.name,
179
- installDir: inlineDir,
180
- status: hasSkillMd ? "ok" : "warn",
181
- flags: [`dep of: ${ownerName}`]
182
- });
179
+ mapping.set(skill.name, getDisplayName(skill));
180
+ }
181
+ return mapping;
182
+ }
183
+ function statusIcon(skill) {
184
+ return skill.hasSkillMd ? chalk3.green("\u2713") : chalk3.yellow("\u26A0");
185
+ }
186
+ function missingSkillMdLabel(skill) {
187
+ return skill.hasSkillMd ? "" : chalk3.yellow(" (missing SKILL.md)");
188
+ }
189
+ function formatDepName(dep, nameToDisplay) {
190
+ return dep.canonicalName || nameToDisplay.get(dep.name) || dep.name;
191
+ }
192
+ function summarizeDeps(record) {
193
+ const deps = record?.installedDependencies || [];
194
+ if (deps.length === 0) return null;
195
+ const byType = deps.reduce(
196
+ (acc, d) => {
197
+ acc.total += 1;
198
+ if (d.sourceType === "inline") acc.inline += 1;
199
+ else acc.external += 1;
200
+ acc.bySourceType[d.sourceType] = (acc.bySourceType[d.sourceType] || 0) + 1;
201
+ return acc;
202
+ },
203
+ { total: 0, inline: 0, external: 0, bySourceType: {} }
204
+ );
205
+ const parts = [];
206
+ if (byType.inline) parts.push(`${byType.inline} inline`);
207
+ const externalParts = Object.entries(byType.bySourceType).filter(([t]) => t !== "inline").sort(([a], [b]) => a.localeCompare(b)).map(([t, c2]) => `${c2} ${t}`);
208
+ if (externalParts.length) parts.push(...externalParts);
209
+ return `deps: ${byType.total}${parts.length ? ` (${parts.join(", ")})` : ""}`;
210
+ }
211
+ function printSkillsetSection(skills, nameToDisplay, options) {
212
+ console.log(chalk3.bold(` Skillsets (${skills.length})`));
213
+ if (skills.length === 0) {
214
+ console.log(chalk3.dim(" (none)"));
215
+ return;
216
+ }
217
+ for (const s of skills) {
218
+ const label = `${chalk3.cyan(getDisplayName(s))}${chalk3.dim(" (skillset)")}${missingSkillMdLabel(s)}`;
219
+ console.log(` ${statusIcon(s)} ${label}`);
220
+ const summary = summarizeDeps(s.record);
221
+ if (summary) console.log(chalk3.dim(` ${summary}`));
222
+ if (options.verbose) {
223
+ const deps = (s.record?.installedDependencies || []).slice().sort((a, b) => a.name.localeCompare(b.name));
224
+ if (deps.length) {
225
+ console.log(chalk3.dim(` includes (${deps.length}):`));
226
+ for (const dep of deps) {
227
+ const depName = formatDepName(dep, nameToDisplay);
228
+ console.log(chalk3.dim(` - ${depName} [${dep.sourceType}]`));
229
+ }
230
+ }
183
231
  }
232
+ if (options.paths || !s.hasSkillMd) console.log(chalk3.dim(` path: ${s.installDir}`));
233
+ }
234
+ }
235
+ function printSkillsSection(skills, options) {
236
+ console.log(chalk3.bold(` Skills (${skills.length})`));
237
+ if (skills.length === 0) {
238
+ console.log(chalk3.dim(" (none)"));
239
+ return;
240
+ }
241
+ for (const s of skills) {
242
+ const label = `${chalk3.cyan(getDisplayName(s))}${missingSkillMdLabel(s)}`;
243
+ console.log(` ${statusIcon(s)} ${label}`);
244
+ if (options.paths || !s.hasSkillMd) console.log(chalk3.dim(` path: ${s.installDir}`));
245
+ }
246
+ }
247
+ function printDependenciesSection(skills, nameToDisplay, options) {
248
+ console.log(chalk3.bold(` Dependencies (${skills.length})`));
249
+ if (skills.length === 0) {
250
+ console.log(chalk3.dim(" (none)"));
251
+ return;
252
+ }
253
+ for (const s of skills) {
254
+ const dependedBy = (s.record?.dependedBy || []).map((name) => nameToDisplay.get(name) || name).sort((a, b) => a.localeCompare(b));
255
+ const requiredBy = dependedBy.length ? chalk3.dim(` \u2190 required by: ${dependedBy.join(", ")}`) : "";
256
+ const label = `${chalk3.cyan(getDisplayName(s))}${missingSkillMdLabel(s)}${requiredBy}`;
257
+ console.log(` ${statusIcon(s)} ${label}`);
258
+ if (options.paths || !s.hasSkillMd) console.log(chalk3.dim(` path: ${s.installDir}`));
184
259
  }
185
- return entries;
260
+ }
261
+ function printPlatform(skills, platform, scope, options) {
262
+ console.log(chalk3.bold(`
263
+ \u{1F4E6} Installed Skills \u2014 ${platform} (${scope})
264
+ `));
265
+ if (skills.length === 0) {
266
+ console.log(chalk3.dim(" No skills installed."));
267
+ console.log(chalk3.dim(` Use ${chalk3.cyan("skild install <source>")} to install a skill.`));
268
+ return;
269
+ }
270
+ const nameToDisplay = buildNameToDisplay(skills);
271
+ const skillsets = skills.filter(isSkillset).sort((a, b) => getDisplayName(a).localeCompare(getDisplayName(b)));
272
+ const dependencies = skills.filter((s) => !isSkillset(s) && Boolean(s.record?.dependedBy?.length)).sort((a, b) => getDisplayName(a).localeCompare(getDisplayName(b)));
273
+ const regular = skills.filter((s) => !isSkillset(s) && !Boolean(s.record?.dependedBy?.length)).sort((a, b) => getDisplayName(a).localeCompare(getDisplayName(b)));
274
+ printSkillsetSection(skillsets, nameToDisplay, options);
275
+ console.log("");
276
+ printSkillsSection(regular, options);
277
+ console.log("");
278
+ printDependenciesSection(dependencies, nameToDisplay, options);
279
+ console.log("");
186
280
  }
187
281
  async function list(options = {}) {
188
282
  const scope = options.local ? "project" : "global";
283
+ const paths = Boolean(options.paths);
284
+ const verbose = Boolean(options.verbose);
189
285
  const platform = options.target;
190
286
  if (platform) {
191
287
  const skills = listSkills({ platform, scope });
@@ -193,22 +289,7 @@ async function list(options = {}) {
193
289
  console.log(JSON.stringify(skills, null, 2));
194
290
  return;
195
291
  }
196
- if (skills.length === 0) {
197
- console.log(chalk3.dim("No skills installed."));
198
- console.log(chalk3.dim(`Use ${chalk3.cyan("skild install <source>")} to install a skill.`));
199
- return;
200
- }
201
- const entries = buildDisplayEntries(skills);
202
- console.log(chalk3.bold(`
203
- \u{1F4E6} Installed Skills (${entries.length}) \u2014 ${platform} (${scope}):
204
- `));
205
- for (const entry of entries) {
206
- const status = entry.status === "ok" ? chalk3.green("\u2713") : chalk3.yellow("\u26A0");
207
- const label = entry.flags.length ? `${entry.name} (${entry.flags.join("; ")})` : entry.name;
208
- console.log(` ${status} ${chalk3.cyan(label)}`);
209
- console.log(chalk3.dim(` \u2514\u2500 ${entry.installDir}`));
210
- }
211
- console.log("");
292
+ printPlatform(skills, platform, scope, { paths, verbose });
212
293
  return;
213
294
  }
214
295
  const allSkills = listAllSkills({ scope });
@@ -221,26 +302,11 @@ async function list(options = {}) {
221
302
  console.log(chalk3.dim(`Use ${chalk3.cyan("skild install <source>")} to install a skill.`));
222
303
  return;
223
304
  }
224
- console.log(chalk3.bold(`
225
- \u{1F4E6} Installed Skills \u2014 all platforms (${scope}):
226
- `));
227
305
  for (const p of PLATFORMS) {
228
306
  const platformSkills = allSkills.filter((s) => s.platform === p).sort((a, b) => a.name.localeCompare(b.name));
229
- const entries = buildDisplayEntries(platformSkills);
230
- const header = `${p} (${entries.length})`;
231
- console.log(chalk3.bold(` ${header}`));
232
- if (entries.length === 0) {
233
- console.log(chalk3.dim(" (none)"));
234
- continue;
235
- }
236
- for (const entry of entries) {
237
- const status = entry.status === "ok" ? chalk3.green("\u2713") : chalk3.yellow("\u26A0");
238
- const label = entry.flags.length ? `${entry.name} (${entry.flags.join("; ")})` : entry.name;
239
- console.log(` ${status} ${chalk3.cyan(label)}`);
240
- console.log(chalk3.dim(` \u2514\u2500 ${entry.installDir}`));
241
- }
307
+ if (platformSkills.length === 0) continue;
308
+ printPlatform(platformSkills, p, scope, { paths, verbose });
242
309
  }
243
- console.log("");
244
310
  }
245
311
 
246
312
  // src/commands/info.ts
@@ -822,7 +888,7 @@ program.name("skild").description("The npm for Agent Skills \u2014 Discover, ins
822
888
  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: ${PLATFORMS2.join(", ")}`, "claude").option("-l, --local", "Install to project-level directory instead of global").option("-f, --force", "Overwrite existing installation").option("--registry <url>", "Registry base URL (default: https://registry.skild.sh)").option("--json", "Output JSON").action(async (source, options) => {
823
889
  await install(source, options);
824
890
  });
825
- program.command("list").alias("ls").description("List installed Skills").option("-t, --target <platform>", `Target platform: ${PLATFORMS2.join(", ")} (optional; omit to list all)`).option("-l, --local", "List project-level directory instead of global").option("--json", "Output JSON").action(async (options) => list(options));
891
+ program.command("list").alias("ls").description("List installed Skills").option("-t, --target <platform>", `Target platform: ${PLATFORMS2.join(", ")} (optional; omit to list all)`).option("-l, --local", "List project-level directory instead of global").option("--paths", "Show install paths").option("--verbose", "Show skillset dependency details").option("--json", "Output JSON").action(async (options) => list(options));
826
892
  program.command("info <skill>").description("Show installed Skill details").option("-t, --target <platform>", `Target platform: ${PLATFORMS2.join(", ")}`, "claude").option("-l, --local", "Use project-level directory instead of global").option("--json", "Output JSON").action(async (skill, options) => info(skill, options));
827
893
  program.command("uninstall <skill>").alias("rm").description("Uninstall a Skill").option("-t, --target <platform>", `Target platform: ${PLATFORMS2.join(", ")}`, "claude").option("-l, --local", "Use project-level directory instead of global").option("-f, --force", "Uninstall even if metadata is missing").option("--with-deps", "Uninstall dependencies that are only required by this skill").action(async (skill, options) => uninstall(skill, options));
828
894
  program.command("update [skill]").alias("up").description("Update one or all installed Skills").option("-t, --target <platform>", `Target platform: ${PLATFORMS2.join(", ")}`, "claude").option("-l, --local", "Use project-level directory instead of global").option("--json", "Output JSON").action(async (skill, options) => update(skill, options));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "skild",
3
- "version": "0.2.6",
3
+ "version": "0.2.8",
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",
@@ -37,7 +37,7 @@
37
37
  "commander": "^12.1.0",
38
38
  "ora": "^8.0.1",
39
39
  "tar": "^7.4.3",
40
- "@skild/core": "^0.2.6"
40
+ "@skild/core": "^0.2.8"
41
41
  },
42
42
  "devDependencies": {
43
43
  "@types/node": "^20.10.0",