skild 0.2.2 → 0.2.4

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 +90 -32
  2. package/package.json +2 -2
package/dist/index.js CHANGED
@@ -7,7 +7,7 @@ import { createRequire } from "module";
7
7
 
8
8
  // src/commands/install.ts
9
9
  import chalk2 from "chalk";
10
- import { fetchWithTimeout, installRegistrySkill, installSkill, resolveRegistryUrl, SkildError } from "@skild/core";
10
+ import { fetchWithTimeout, installRegistrySkill, installSkill, loadRegistryAuth, resolveRegistryUrl, SkildError } from "@skild/core";
11
11
 
12
12
  // src/utils/logger.ts
13
13
  import chalk from "chalk";
@@ -55,10 +55,10 @@ var logger = {
55
55
  /**
56
56
  * Log a skill entry with status indicator.
57
57
  */
58
- skillEntry: (name, path2, hasSkillMd) => {
58
+ skillEntry: (name, path3, hasSkillMd) => {
59
59
  const status = hasSkillMd ? chalk.green("\u2713") : chalk.yellow("\u26A0");
60
60
  console.log(` ${status} ${chalk.cyan(name)}`);
61
- console.log(chalk.dim(` \u2514\u2500 ${path2}`));
61
+ console.log(chalk.dim(` \u2514\u2500 ${path3}`));
62
62
  },
63
63
  /**
64
64
  * Log installation result details.
@@ -73,12 +73,14 @@ var logger = {
73
73
  async function install(source, options = {}) {
74
74
  const platform = options.target || "claude";
75
75
  const scope = options.local ? "project" : "global";
76
+ const auth = loadRegistryAuth();
77
+ const registryUrlForDeps = options.registry || auth?.registryUrl;
76
78
  const spinner = createSpinner(`Installing ${chalk2.cyan(source)} to ${chalk2.dim(platform)} (${scope})...`);
77
79
  try {
78
80
  const record = source.trim().startsWith("@") && source.includes("/") ? await installRegistrySkill(
79
- { spec: source, registryUrl: options.registry },
81
+ { spec: source, registryUrl: registryUrlForDeps },
80
82
  { platform, scope, force: Boolean(options.force) }
81
- ) : await installSkill({ source }, { platform, scope, force: Boolean(options.force) });
83
+ ) : await installSkill({ source }, { platform, scope, force: Boolean(options.force), registryUrl: registryUrlForDeps });
82
84
  const displayName = record.canonicalName || record.name;
83
85
  spinner.succeed(`Installed ${chalk2.green(displayName)} to ${chalk2.dim(record.installDir)}`);
84
86
  if (options.json) {
@@ -95,7 +97,7 @@ async function install(source, options = {}) {
95
97
  } else if (record.skill?.validation?.ok) {
96
98
  logger.installDetail(`Validation: ${chalk2.green("ok")}`);
97
99
  }
98
- void reportDownload(record, options.registry);
100
+ void reportDownload(record, registryUrlForDeps);
99
101
  } catch (error) {
100
102
  spinner.fail(`Failed to install ${chalk2.red(source)}`);
101
103
  const message = error instanceof SkildError ? error.message : error instanceof Error ? error.message : String(error);
@@ -136,7 +138,52 @@ async function reportDownload(record, registryOverride) {
136
138
 
137
139
  // src/commands/list.ts
138
140
  import chalk3 from "chalk";
141
+ import fs from "fs";
142
+ import path from "path";
139
143
  import { PLATFORMS, listAllSkills, listSkills } from "@skild/core";
144
+ function toDisplayName(name, mapping) {
145
+ return mapping.get(name) || name;
146
+ }
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
+ });
170
+ 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
+ });
183
+ }
184
+ }
185
+ return entries;
186
+ }
140
187
  async function list(options = {}) {
141
188
  const scope = options.local ? "project" : "global";
142
189
  const platform = options.target;
@@ -151,14 +198,15 @@ async function list(options = {}) {
151
198
  console.log(chalk3.dim(`Use ${chalk3.cyan("skild install <source>")} to install a skill.`));
152
199
  return;
153
200
  }
201
+ const entries = buildDisplayEntries(skills);
154
202
  console.log(chalk3.bold(`
155
- \u{1F4E6} Installed Skills (${skills.length}) \u2014 ${platform} (${scope}):
203
+ \u{1F4E6} Installed Skills (${entries.length}) \u2014 ${platform} (${scope}):
156
204
  `));
157
- for (const s of skills) {
158
- const status = s.hasSkillMd ? chalk3.green("\u2713") : chalk3.yellow("\u26A0");
159
- const displayName = s.record?.canonicalName || s.name;
160
- console.log(` ${status} ${chalk3.cyan(displayName)}`);
161
- console.log(chalk3.dim(` \u2514\u2500 ${s.installDir}`));
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}`));
162
210
  }
163
211
  console.log("");
164
212
  return;
@@ -178,17 +226,18 @@ async function list(options = {}) {
178
226
  `));
179
227
  for (const p of PLATFORMS) {
180
228
  const platformSkills = allSkills.filter((s) => s.platform === p).sort((a, b) => a.name.localeCompare(b.name));
181
- const header = `${p} (${platformSkills.length})`;
229
+ const entries = buildDisplayEntries(platformSkills);
230
+ const header = `${p} (${entries.length})`;
182
231
  console.log(chalk3.bold(` ${header}`));
183
- if (platformSkills.length === 0) {
232
+ if (entries.length === 0) {
184
233
  console.log(chalk3.dim(" (none)"));
185
234
  continue;
186
235
  }
187
- for (const s of platformSkills) {
188
- const status = s.hasSkillMd ? chalk3.green("\u2713") : chalk3.yellow("\u26A0");
189
- const displayName = s.record?.canonicalName || s.name;
190
- console.log(` ${status} ${chalk3.cyan(displayName)}`);
191
- console.log(chalk3.dim(` \u2514\u2500 ${s.installDir}`));
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}`));
192
241
  }
193
242
  }
194
243
  console.log("");
@@ -246,7 +295,12 @@ async function uninstall(skill, options = {}) {
246
295
  const resolvedName = canonical.startsWith("@") && canonical.includes("/") ? canonicalNameToInstallDirName2(canonical) : canonical;
247
296
  const spinner = createSpinner(`Uninstalling ${chalk5.cyan(canonical)} from ${chalk5.dim(platform)} (${scope})...`);
248
297
  try {
249
- uninstallSkill(resolvedName, { platform, scope, allowMissingMetadata: Boolean(options.force) });
298
+ uninstallSkill(resolvedName, {
299
+ platform,
300
+ scope,
301
+ allowMissingMetadata: Boolean(options.force),
302
+ withDeps: Boolean(options.withDeps)
303
+ });
250
304
  spinner.succeed(`Uninstalled ${chalk5.green(canonical)}`);
251
305
  } catch (error) {
252
306
  spinner.fail(`Failed to uninstall ${chalk5.red(canonical)}`);
@@ -500,9 +554,9 @@ async function logout() {
500
554
 
501
555
  // src/commands/whoami.ts
502
556
  import chalk12 from "chalk";
503
- import { fetchWithTimeout as fetchWithTimeout4, loadRegistryAuth, resolveRegistryUrl as resolveRegistryUrl4, SkildError as SkildError8 } from "@skild/core";
557
+ import { fetchWithTimeout as fetchWithTimeout4, loadRegistryAuth as loadRegistryAuth2, resolveRegistryUrl as resolveRegistryUrl4, SkildError as SkildError8 } from "@skild/core";
504
558
  async function whoami() {
505
- const auth = loadRegistryAuth();
559
+ const auth = loadRegistryAuth2();
506
560
  if (!auth) {
507
561
  console.error(chalk12.red("Not logged in. Run `skild login` first."));
508
562
  process.exitCode = 1;
@@ -532,13 +586,13 @@ async function whoami() {
532
586
  }
533
587
 
534
588
  // src/commands/publish.ts
535
- import fs from "fs";
589
+ import fs2 from "fs";
536
590
  import os from "os";
537
- import path from "path";
591
+ import path2 from "path";
538
592
  import crypto from "crypto";
539
593
  import * as tar from "tar";
540
594
  import chalk13 from "chalk";
541
- import { fetchWithTimeout as fetchWithTimeout5, loadRegistryAuth as loadRegistryAuth2, resolveRegistryUrl as resolveRegistryUrl5, SkildError as SkildError9, splitCanonicalName, validateSkillDir } from "@skild/core";
595
+ import { fetchWithTimeout as fetchWithTimeout5, loadRegistryAuth as loadRegistryAuth3, resolveRegistryUrl as resolveRegistryUrl5, SkildError as SkildError9, splitCanonicalName, validateSkillDir } from "@skild/core";
542
596
  function sha256Hex(buf) {
543
597
  const h = crypto.createHash("sha256");
544
598
  h.update(buf);
@@ -549,7 +603,7 @@ function parseTargets(raw) {
549
603
  return raw.split(",").map((s) => s.trim()).filter(Boolean);
550
604
  }
551
605
  async function publish(options = {}) {
552
- const auth = loadRegistryAuth2();
606
+ const auth = loadRegistryAuth3();
553
607
  const registry = resolveRegistryUrl5(options.registry || auth?.registryUrl);
554
608
  const token = auth?.token;
555
609
  if (!token) {
@@ -557,7 +611,7 @@ async function publish(options = {}) {
557
611
  process.exitCode = 1;
558
612
  return;
559
613
  }
560
- const dir = path.resolve(options.dir || process.cwd());
614
+ const dir = path2.resolve(options.dir || process.cwd());
561
615
  const validation = validateSkillDir(dir);
562
616
  if (!validation.ok) {
563
617
  console.error(chalk13.red("Skill validation failed:"));
@@ -571,6 +625,8 @@ async function publish(options = {}) {
571
625
  const description = (options.description || fm.description || "").trim();
572
626
  const tag = (options.tag || "latest").trim() || "latest";
573
627
  const targets = parseTargets(options.targets);
628
+ const skillset = fm.skillset === true;
629
+ const dependencies = Array.isArray(fm.dependencies) ? fm.dependencies : [];
574
630
  if (!name) {
575
631
  console.error(chalk13.red("Missing name. Provide SKILL.md frontmatter.name or --name."));
576
632
  process.exitCode = 1;
@@ -614,8 +670,8 @@ async function publish(options = {}) {
614
670
  return;
615
671
  }
616
672
  const spinner = createSpinner(`Publishing ${chalk13.cyan(`${name}@${version2}`)} to ${chalk13.dim(registry)}...`);
617
- const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), "skild-publish-"));
618
- const tarballPath = path.join(tempDir, "skill.tgz");
673
+ const tempDir = fs2.mkdtempSync(path2.join(os.tmpdir(), "skild-publish-"));
674
+ const tarballPath = path2.join(tempDir, "skill.tgz");
619
675
  try {
620
676
  await tar.c(
621
677
  {
@@ -627,13 +683,15 @@ async function publish(options = {}) {
627
683
  },
628
684
  ["."]
629
685
  );
630
- const buf = fs.readFileSync(tarballPath);
686
+ const buf = fs2.readFileSync(tarballPath);
631
687
  const integrity = sha256Hex(buf);
632
688
  const form = new FormData();
633
689
  form.set("version", version2);
634
690
  form.set("description", description);
635
691
  form.set("targets", JSON.stringify(targets));
636
692
  form.set("tag", tag);
693
+ form.set("skillset", skillset ? "true" : "false");
694
+ form.set("dependencies", JSON.stringify(dependencies));
637
695
  form.append("tarball", new Blob([buf], { type: "application/gzip" }), "skill.tgz");
638
696
  const { scope, name: skillName } = splitCanonicalName(name);
639
697
  const res = await fetchWithTimeout5(
@@ -669,7 +727,7 @@ async function publish(options = {}) {
669
727
  console.error(chalk13.red(message));
670
728
  process.exitCode = 1;
671
729
  } finally {
672
- fs.rmSync(tempDir, { recursive: true, force: true });
730
+ fs2.rmSync(tempDir, { recursive: true, force: true });
673
731
  }
674
732
  }
675
733
 
@@ -716,7 +774,7 @@ program.command("install <source>").alias("i").description("Install a Skill from
716
774
  });
717
775
  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));
718
776
  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));
719
- 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").action(async (skill, options) => uninstall(skill, options));
777
+ 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));
720
778
  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));
721
779
  program.command("validate [target]").alias("v").description("Validate a Skill folder (path) or an installed Skill name").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 (target, options) => validate(target, options));
722
780
  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));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "skild",
3
- "version": "0.2.2",
3
+ "version": "0.2.4",
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.1"
40
+ "@skild/core": "^0.2.4"
41
41
  },
42
42
  "devDependencies": {
43
43
  "@types/node": "^20.10.0",