skild 0.1.3 → 0.1.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 +391 -29
  2. package/package.json +3 -2
package/dist/index.js CHANGED
@@ -2,12 +2,12 @@
2
2
 
3
3
  // src/index.ts
4
4
  import { Command } from "commander";
5
- import chalk9 from "chalk";
5
+ import chalk15 from "chalk";
6
6
  import { createRequire } from "module";
7
7
 
8
8
  // src/commands/install.ts
9
9
  import chalk2 from "chalk";
10
- import { installSkill, SkildError } from "@skild/core";
10
+ import { installRegistrySkill, installSkill, 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, path, hasSkillMd) => {
58
+ skillEntry: (name, path2, 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 ${path}`));
61
+ console.log(chalk.dim(` \u2514\u2500 ${path2}`));
62
62
  },
63
63
  /**
64
64
  * Log installation result details.
@@ -75,15 +75,12 @@ async function install(source, options = {}) {
75
75
  const scope = options.local ? "project" : "global";
76
76
  const spinner = createSpinner(`Installing ${chalk2.cyan(source)} to ${chalk2.dim(platform)} (${scope})...`);
77
77
  try {
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)}`);
78
+ const record = source.trim().startsWith("@") && source.includes("/") ? await installRegistrySkill(
79
+ { spec: source, registryUrl: options.registry },
80
+ { platform, scope, force: Boolean(options.force) }
81
+ ) : await installSkill({ source }, { platform, scope, force: Boolean(options.force) });
82
+ const displayName = record.canonicalName || record.name;
83
+ spinner.succeed(`Installed ${chalk2.green(displayName)} to ${chalk2.dim(record.installDir)}`);
87
84
  if (options.json) {
88
85
  console.log(JSON.stringify(record, null, 2));
89
86
  return;
@@ -128,7 +125,8 @@ async function list(options = {}) {
128
125
  `));
129
126
  for (const s of skills) {
130
127
  const status = s.hasSkillMd ? chalk3.green("\u2713") : chalk3.yellow("\u26A0");
131
- console.log(` ${status} ${chalk3.cyan(s.name)}`);
128
+ const displayName = s.record?.canonicalName || s.name;
129
+ console.log(` ${status} ${chalk3.cyan(displayName)}`);
132
130
  console.log(chalk3.dim(` \u2514\u2500 ${s.installDir}`));
133
131
  }
134
132
  console.log("");
@@ -157,7 +155,8 @@ async function list(options = {}) {
157
155
  }
158
156
  for (const s of platformSkills) {
159
157
  const status = s.hasSkillMd ? chalk3.green("\u2713") : chalk3.yellow("\u26A0");
160
- console.log(` ${status} ${chalk3.cyan(s.name)}`);
158
+ const displayName = s.record?.canonicalName || s.name;
159
+ console.log(` ${status} ${chalk3.cyan(displayName)}`);
161
160
  console.log(chalk3.dim(` \u2514\u2500 ${s.installDir}`));
162
161
  }
163
162
  }
@@ -166,18 +165,20 @@ async function list(options = {}) {
166
165
 
167
166
  // src/commands/info.ts
168
167
  import chalk4 from "chalk";
169
- import { getSkillInfo, SkildError as SkildError2 } from "@skild/core";
168
+ import { canonicalNameToInstallDirName, getSkillInfo, SkildError as SkildError2 } from "@skild/core";
170
169
  async function info(skill, options = {}) {
171
170
  const platform = options.target || "claude";
172
171
  const scope = options.local ? "project" : "global";
173
172
  try {
174
- const record = getSkillInfo(skill, { platform, scope });
173
+ const resolvedName = skill.trim().startsWith("@") && skill.includes("/") ? canonicalNameToInstallDirName(skill.trim()) : skill;
174
+ const record = getSkillInfo(resolvedName, { platform, scope });
175
175
  if (options.json) {
176
176
  console.log(JSON.stringify(record, null, 2));
177
177
  return;
178
178
  }
179
+ const displayName = record.canonicalName || record.name;
179
180
  console.log(chalk4.bold(`
180
- ${chalk4.cyan(record.name)}
181
+ ${chalk4.cyan(displayName)}
181
182
  `));
182
183
  console.log(` ${chalk4.dim("Path:")} ${record.installDir}`);
183
184
  console.log(` ${chalk4.dim("Source:")} ${record.source}`);
@@ -206,16 +207,18 @@ ${chalk4.cyan(record.name)}
206
207
 
207
208
  // src/commands/uninstall.ts
208
209
  import chalk5 from "chalk";
209
- import { uninstallSkill, SkildError as SkildError3 } from "@skild/core";
210
+ import { canonicalNameToInstallDirName as canonicalNameToInstallDirName2, uninstallSkill, SkildError as SkildError3 } from "@skild/core";
210
211
  async function uninstall(skill, options = {}) {
211
212
  const platform = options.target || "claude";
212
213
  const scope = options.local ? "project" : "global";
213
- const spinner = createSpinner(`Uninstalling ${chalk5.cyan(skill)} from ${chalk5.dim(platform)} (${scope})...`);
214
+ const canonical = skill.trim();
215
+ const resolvedName = canonical.startsWith("@") && canonical.includes("/") ? canonicalNameToInstallDirName2(canonical) : canonical;
216
+ const spinner = createSpinner(`Uninstalling ${chalk5.cyan(canonical)} from ${chalk5.dim(platform)} (${scope})...`);
214
217
  try {
215
- uninstallSkill(skill, { platform, scope, allowMissingMetadata: Boolean(options.force) });
216
- spinner.succeed(`Uninstalled ${chalk5.green(skill)}`);
218
+ uninstallSkill(resolvedName, { platform, scope, allowMissingMetadata: Boolean(options.force) });
219
+ spinner.succeed(`Uninstalled ${chalk5.green(canonical)}`);
217
220
  } catch (error) {
218
- spinner.fail(`Failed to uninstall ${chalk5.red(skill)}`);
221
+ spinner.fail(`Failed to uninstall ${chalk5.red(canonical)}`);
219
222
  const message = error instanceof SkildError3 ? error.message : error instanceof Error ? error.message : String(error);
220
223
  console.error(chalk5.red(message));
221
224
  process.exitCode = 1;
@@ -224,14 +227,15 @@ async function uninstall(skill, options = {}) {
224
227
 
225
228
  // src/commands/update.ts
226
229
  import chalk6 from "chalk";
227
- import { updateSkill, SkildError as SkildError4 } from "@skild/core";
230
+ import { canonicalNameToInstallDirName as canonicalNameToInstallDirName3, updateSkill, SkildError as SkildError4 } from "@skild/core";
228
231
  async function update(skill, options = {}) {
229
232
  const platform = options.target || "claude";
230
233
  const scope = options.local ? "project" : "global";
231
234
  const label = skill ? skill : "all skills";
235
+ const resolvedName = skill && skill.trim().startsWith("@") && skill.includes("/") ? canonicalNameToInstallDirName3(skill.trim()) : skill;
232
236
  const spinner = createSpinner(`Updating ${chalk6.cyan(label)} on ${chalk6.dim(platform)} (${scope})...`);
233
237
  try {
234
- const results = await updateSkill(skill, { platform, scope });
238
+ const results = await updateSkill(resolvedName, { platform, scope });
235
239
  spinner.succeed(`Updated ${chalk6.green(results.length.toString())} skill(s).`);
236
240
  if (options.json) {
237
241
  console.log(JSON.stringify(results, null, 2));
@@ -246,12 +250,13 @@ async function update(skill, options = {}) {
246
250
 
247
251
  // src/commands/validate.ts
248
252
  import chalk7 from "chalk";
249
- import { validateSkill } from "@skild/core";
253
+ import { canonicalNameToInstallDirName as canonicalNameToInstallDirName4, validateSkill } from "@skild/core";
250
254
  async function validate(target, options = {}) {
251
255
  const platform = options.target || "claude";
252
256
  const scope = options.local ? "project" : "global";
253
257
  const value = target || ".";
254
- const result = validateSkill(value, { platform, scope });
258
+ const resolvedValue = value.trim().startsWith("@") && value.includes("/") ? canonicalNameToInstallDirName4(value.trim()) : value;
259
+ const result = validateSkill(resolvedValue, { platform, scope });
255
260
  if (options.json) {
256
261
  console.log(JSON.stringify(result, null, 2));
257
262
  process.exitCode = result.ok ? 0 : 1;
@@ -291,13 +296,364 @@ async function init(name, options = {}) {
291
296
  }
292
297
  }
293
298
 
299
+ // src/commands/signup.ts
300
+ import chalk9 from "chalk";
301
+ import { fetchWithTimeout, resolveRegistryUrl, SkildError as SkildError6 } from "@skild/core";
302
+
303
+ // src/utils/prompt.ts
304
+ import readline from "readline";
305
+ async function promptLine(question, defaultValue) {
306
+ const rl = readline.createInterface({ input: process.stdin, output: process.stdout, terminal: true });
307
+ try {
308
+ const suffix = defaultValue ? ` (${defaultValue})` : "";
309
+ const answer = await new Promise((resolve) => rl.question(`${question}${suffix}: `, resolve));
310
+ const trimmed = answer.trim();
311
+ return trimmed || defaultValue || "";
312
+ } finally {
313
+ rl.close();
314
+ }
315
+ }
316
+ async function promptPassword(question) {
317
+ const rl = readline.createInterface({ input: process.stdin, output: process.stdout, terminal: true });
318
+ rl.stdoutMuted = true;
319
+ rl._writeToOutput = function _writeToOutput(stringToWrite) {
320
+ if (this.stdoutMuted) return;
321
+ this.output.write(stringToWrite);
322
+ };
323
+ try {
324
+ const answer = await new Promise((resolve) => rl.question(`${question}: `, resolve));
325
+ return String(answer || "");
326
+ } finally {
327
+ rl.stdoutMuted = false;
328
+ rl.close();
329
+ process.stdout.write("\n");
330
+ }
331
+ }
332
+
333
+ // src/commands/signup.ts
334
+ async function signup(options) {
335
+ const registry = resolveRegistryUrl(options.registry);
336
+ const interactive = Boolean(process.stdin.isTTY && process.stdout.isTTY);
337
+ const email = options.email?.trim() || "";
338
+ const handle = options.handle?.trim() || "";
339
+ const password = options.password || "";
340
+ if ((!email || !handle || !password) && (!interactive || options.json)) {
341
+ console.error(chalk9.red("Missing signup fields. Use --email/--handle/--password, or run `skild signup` interactively."));
342
+ process.exitCode = 1;
343
+ return;
344
+ }
345
+ const finalEmail = email || await promptLine("Email");
346
+ const finalHandle = handle || (await promptLine("Handle (publisher scope)", void 0)).toLowerCase();
347
+ const finalPassword = password || await promptPassword("Password");
348
+ let text = "";
349
+ try {
350
+ const res = await fetchWithTimeout(
351
+ `${registry}/auth/signup`,
352
+ {
353
+ method: "POST",
354
+ headers: { "content-type": "application/json" },
355
+ body: JSON.stringify({
356
+ email: finalEmail,
357
+ handle: finalHandle,
358
+ password: finalPassword
359
+ })
360
+ },
361
+ 1e4
362
+ );
363
+ text = await res.text();
364
+ if (!res.ok) {
365
+ console.error(chalk9.red(`Signup failed (${res.status}): ${text}`));
366
+ process.exitCode = 1;
367
+ return;
368
+ }
369
+ } catch (error) {
370
+ const message = error instanceof SkildError6 ? error.message : error instanceof Error ? error.message : String(error);
371
+ console.error(chalk9.red(`Signup failed: ${message}`));
372
+ process.exitCode = 1;
373
+ return;
374
+ }
375
+ if (options.json) {
376
+ console.log(text || JSON.stringify({ ok: true }, null, 2));
377
+ return;
378
+ }
379
+ console.log(chalk9.green("Signup successful."));
380
+ console.log(chalk9.dim("Next: run `skild login`"));
381
+ }
382
+
383
+ // src/commands/login.ts
384
+ import chalk10 from "chalk";
385
+ import { fetchWithTimeout as fetchWithTimeout2, resolveRegistryUrl as resolveRegistryUrl2, saveRegistryAuth, SkildError as SkildError7 } from "@skild/core";
386
+ async function login(options) {
387
+ const registry = resolveRegistryUrl2(options.registry);
388
+ const interactive = Boolean(process.stdin.isTTY && process.stdout.isTTY);
389
+ const handleOrEmail = options.handleOrEmail?.trim() || "";
390
+ const password = options.password || "";
391
+ if ((!handleOrEmail || !password) && (!interactive || options.json)) {
392
+ console.error(chalk10.red("Missing credentials. Use --handle-or-email and --password, or run `skild login` interactively."));
393
+ process.exitCode = 1;
394
+ return;
395
+ }
396
+ const finalHandleOrEmail = handleOrEmail || await promptLine("Handle or email");
397
+ const finalPassword = password || await promptPassword("Password");
398
+ const finalTokenName = options.tokenName?.trim() || void 0;
399
+ let text = "";
400
+ try {
401
+ const res = await fetchWithTimeout2(
402
+ `${registry}/auth/login`,
403
+ {
404
+ method: "POST",
405
+ headers: { "content-type": "application/json" },
406
+ body: JSON.stringify({
407
+ handleOrEmail: finalHandleOrEmail,
408
+ password: finalPassword,
409
+ tokenName: finalTokenName
410
+ })
411
+ },
412
+ 1e4
413
+ );
414
+ text = await res.text();
415
+ if (!res.ok) {
416
+ console.error(chalk10.red(`Login failed (${res.status}): ${text}`));
417
+ process.exitCode = 1;
418
+ return;
419
+ }
420
+ } catch (error) {
421
+ const message = error instanceof SkildError7 ? error.message : error instanceof Error ? error.message : String(error);
422
+ console.error(chalk10.red(`Login failed: ${message}`));
423
+ process.exitCode = 1;
424
+ return;
425
+ }
426
+ const json = JSON.parse(text);
427
+ saveRegistryAuth({
428
+ schemaVersion: 1,
429
+ registryUrl: registry,
430
+ token: json.token,
431
+ publisher: json.publisher,
432
+ updatedAt: (/* @__PURE__ */ new Date()).toISOString()
433
+ });
434
+ if (options.json) {
435
+ console.log(JSON.stringify({ ok: true, publisher: json.publisher }, null, 2));
436
+ return;
437
+ }
438
+ console.log(chalk10.green(`Logged in as ${chalk10.cyan(json.publisher.handle)}.`));
439
+ }
440
+
441
+ // src/commands/logout.ts
442
+ import chalk11 from "chalk";
443
+ import { clearRegistryAuth } from "@skild/core";
444
+ async function logout() {
445
+ clearRegistryAuth();
446
+ console.log(chalk11.green("Logged out."));
447
+ }
448
+
449
+ // src/commands/whoami.ts
450
+ import chalk12 from "chalk";
451
+ import { fetchWithTimeout as fetchWithTimeout3, loadRegistryAuth, resolveRegistryUrl as resolveRegistryUrl3, SkildError as SkildError8 } from "@skild/core";
452
+ async function whoami() {
453
+ const auth = loadRegistryAuth();
454
+ if (!auth) {
455
+ console.error(chalk12.red("Not logged in. Run `skild login` first."));
456
+ process.exitCode = 1;
457
+ return;
458
+ }
459
+ const registryUrl = resolveRegistryUrl3(auth.registryUrl);
460
+ try {
461
+ const res = await fetchWithTimeout3(
462
+ `${registryUrl}/auth/me`,
463
+ { headers: { authorization: `Bearer ${auth.token}`, accept: "application/json" } },
464
+ 5e3
465
+ );
466
+ const text = await res.text();
467
+ if (!res.ok) {
468
+ console.error(chalk12.red(`whoami failed (${res.status}): ${text}`));
469
+ process.exitCode = 1;
470
+ return;
471
+ }
472
+ const json = JSON.parse(text);
473
+ console.log(chalk12.cyan(json.publisher.handle));
474
+ } catch (error) {
475
+ const message = error instanceof SkildError8 ? error.message : error instanceof Error ? error.message : String(error);
476
+ console.error(chalk12.red(`whoami failed: ${message}`));
477
+ console.error(chalk12.dim("Tip: if you previously logged into a local registry, run `skild logout` then `skild login`."));
478
+ process.exitCode = 1;
479
+ }
480
+ }
481
+
482
+ // src/commands/publish.ts
483
+ import fs from "fs";
484
+ import os from "os";
485
+ import path from "path";
486
+ import crypto from "crypto";
487
+ import * as tar from "tar";
488
+ import chalk13 from "chalk";
489
+ import { fetchWithTimeout as fetchWithTimeout4, loadRegistryAuth as loadRegistryAuth2, resolveRegistryUrl as resolveRegistryUrl4, SkildError as SkildError9, splitCanonicalName, validateSkillDir } from "@skild/core";
490
+ function sha256Hex(buf) {
491
+ const h = crypto.createHash("sha256");
492
+ h.update(buf);
493
+ return h.digest("hex");
494
+ }
495
+ function parseTargets(raw) {
496
+ if (!raw?.trim()) return [];
497
+ return raw.split(",").map((s) => s.trim()).filter(Boolean);
498
+ }
499
+ async function publish(options = {}) {
500
+ const auth = loadRegistryAuth2();
501
+ const registry = resolveRegistryUrl4(options.registry || auth?.registryUrl);
502
+ const token = auth?.token;
503
+ if (!token) {
504
+ console.error(chalk13.red("Not logged in. Run `skild login` first."));
505
+ process.exitCode = 1;
506
+ return;
507
+ }
508
+ const dir = path.resolve(options.dir || process.cwd());
509
+ const validation = validateSkillDir(dir);
510
+ if (!validation.ok) {
511
+ console.error(chalk13.red("Skill validation failed:"));
512
+ for (const issue of validation.issues) console.error(chalk13.red(`- ${issue.message}`));
513
+ process.exitCode = 1;
514
+ return;
515
+ }
516
+ const fm = validation.frontmatter;
517
+ let name = (options.name || fm.name || "").trim();
518
+ const version2 = (options.skillVersion || fm.version || "").trim();
519
+ const description = (options.description || fm.description || "").trim();
520
+ const tag = (options.tag || "latest").trim() || "latest";
521
+ const targets = parseTargets(options.targets);
522
+ if (!name) {
523
+ console.error(chalk13.red("Missing name. Provide SKILL.md frontmatter.name or --name."));
524
+ process.exitCode = 1;
525
+ return;
526
+ }
527
+ if (!name.startsWith("@")) {
528
+ const seg = name.trim();
529
+ if (!/^[a-z0-9][a-z0-9-]{1,63}$/.test(seg)) {
530
+ console.error(chalk13.red("Invalid name. Use @publisher/skill or a simple skill name (lowercase letters/digits/dashes)."));
531
+ process.exitCode = 1;
532
+ return;
533
+ }
534
+ const meRes = await fetchWithTimeout4(
535
+ `${registry}/auth/me`,
536
+ { headers: { authorization: `Bearer ${token}` } },
537
+ 1e4
538
+ );
539
+ const meText = await meRes.text();
540
+ if (!meRes.ok) {
541
+ console.error(chalk13.red(`Failed to infer publisher scope (${meRes.status}): ${meText}`));
542
+ process.exitCode = 1;
543
+ return;
544
+ }
545
+ const meJson = JSON.parse(meText);
546
+ const handle = String(meJson?.publisher?.handle || "").trim().toLowerCase();
547
+ if (!handle) {
548
+ console.error(chalk13.red("Failed to infer publisher scope from registry response."));
549
+ process.exitCode = 1;
550
+ return;
551
+ }
552
+ name = `@${handle}/${seg}`;
553
+ }
554
+ if (!/^@[a-z0-9][a-z0-9-]{1,31}\/[a-z0-9][a-z0-9-]{1,63}$/.test(name)) {
555
+ console.error(chalk13.red("Invalid publish name. Expected @publisher/skill (lowercase letters/digits/dashes)."));
556
+ process.exitCode = 1;
557
+ return;
558
+ }
559
+ if (!version2) {
560
+ console.error(chalk13.red("Missing version. Provide semver like 1.2.3 via SKILL.md frontmatter or --skill-version."));
561
+ process.exitCode = 1;
562
+ return;
563
+ }
564
+ const spinner = createSpinner(`Publishing ${chalk13.cyan(`${name}@${version2}`)} to ${chalk13.dim(registry)}...`);
565
+ const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), "skild-publish-"));
566
+ const tarballPath = path.join(tempDir, "skill.tgz");
567
+ try {
568
+ await tar.c(
569
+ {
570
+ gzip: true,
571
+ file: tarballPath,
572
+ cwd: dir,
573
+ portable: true,
574
+ filter: (p) => !p.startsWith(".skild") && !p.startsWith(".git")
575
+ },
576
+ ["."]
577
+ );
578
+ const buf = fs.readFileSync(tarballPath);
579
+ const integrity = sha256Hex(buf);
580
+ const form = new FormData();
581
+ form.set("version", version2);
582
+ form.set("description", description);
583
+ form.set("targets", JSON.stringify(targets));
584
+ form.set("tag", tag);
585
+ form.append("tarball", new Blob([buf], { type: "application/gzip" }), "skill.tgz");
586
+ const { scope, name: skillName } = splitCanonicalName(name);
587
+ const res = await fetchWithTimeout4(
588
+ `${registry}/skills/${encodeURIComponent(scope)}/${encodeURIComponent(skillName)}/publish`,
589
+ {
590
+ method: "POST",
591
+ headers: { authorization: `Bearer ${token}` },
592
+ body: form
593
+ },
594
+ 3e4
595
+ );
596
+ const text = await res.text();
597
+ if (!res.ok) {
598
+ spinner.fail(`Publish failed (${res.status})`);
599
+ console.error(chalk13.red(text));
600
+ process.exitCode = 1;
601
+ return;
602
+ }
603
+ if (options.json) {
604
+ console.log(text);
605
+ return;
606
+ }
607
+ spinner.succeed(`Published ${chalk13.green(`${name}@${version2}`)} (sha256:${integrity.slice(0, 12)}\u2026)`);
608
+ } catch (error) {
609
+ spinner.fail("Publish failed");
610
+ const message = error instanceof SkildError9 ? error.message : error instanceof Error ? error.message : String(error);
611
+ console.error(chalk13.red(message));
612
+ process.exitCode = 1;
613
+ } finally {
614
+ fs.rmSync(tempDir, { recursive: true, force: true });
615
+ }
616
+ }
617
+
618
+ // src/commands/search.ts
619
+ import chalk14 from "chalk";
620
+ import { resolveRegistryUrl as resolveRegistryUrl5, searchRegistrySkills, SkildError as SkildError10 } from "@skild/core";
621
+ async function search(query, options = {}) {
622
+ const registryUrl = resolveRegistryUrl5(options.registry);
623
+ const limit = Math.min(Math.max(Number.parseInt(options.limit || "50", 10) || 50, 1), 100);
624
+ try {
625
+ const skills = await searchRegistrySkills(registryUrl, query, limit);
626
+ if (options.json) {
627
+ console.log(JSON.stringify({ ok: true, registryUrl, skills }, null, 2));
628
+ return;
629
+ }
630
+ if (!skills.length) {
631
+ console.log(chalk14.dim("No results."));
632
+ return;
633
+ }
634
+ console.log(chalk14.bold(`
635
+ \u{1F50E} Results (${skills.length}) \u2014 ${chalk14.dim(registryUrl)}
636
+ `));
637
+ for (const s of skills) {
638
+ const name = String(s.name || "").trim();
639
+ const desc = String(s.description || "").trim();
640
+ if (!name) continue;
641
+ console.log(` ${chalk14.cyan(name)}${desc ? chalk14.dim(` \u2014 ${desc}`) : ""}`);
642
+ }
643
+ } catch (error) {
644
+ const message = error instanceof SkildError10 ? error.message : error instanceof Error ? error.message : String(error);
645
+ console.error(chalk14.red(message));
646
+ process.exitCode = 1;
647
+ }
648
+ }
649
+
294
650
  // src/index.ts
295
651
  import { PLATFORMS as PLATFORMS2 } from "@skild/core";
296
652
  var require2 = createRequire(import.meta.url);
297
653
  var { version } = require2("../package.json");
298
654
  var program = new Command();
299
655
  program.name("skild").description("The npm for Agent Skills \u2014 Discover, install, manage, and publish AI Agent Skills with ease.").version(version);
300
- 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("--json", "Output JSON").action(async (source, options) => {
656
+ 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) => {
301
657
  await install(source, options);
302
658
  });
303
659
  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));
@@ -306,8 +662,14 @@ program.command("uninstall <skill>").alias("rm").description("Uninstall a Skill"
306
662
  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));
307
663
  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));
308
664
  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));
665
+ program.command("signup").description("Create a publisher account in the registry (no GitHub required)").option("--registry <url>", "Registry base URL (default: https://registry.skild.sh)").option("--email <email>", "Email (optional; will prompt)").option("--handle <handle>", "Publisher handle (owns @handle/* scope) (optional; will prompt)").option("--password <password>", "Password (optional; will prompt)").option("--json", "Output JSON").action(async (options) => signup(options));
666
+ program.command("login").description("Login to a registry and store an access token locally").option("--registry <url>", "Registry base URL (default: https://registry.skild.sh)").option("--handle-or-email <value>", "Handle or email (optional; will prompt)").option("--password <password>", "Password (optional; will prompt)").option("--token-name <name>", "Token label").option("--json", "Output JSON").action(async (options) => login(options));
667
+ program.command("logout").description("Remove stored registry credentials").action(async () => logout());
668
+ program.command("whoami").description("Show current registry identity").action(async () => whoami());
669
+ program.command("publish").description("Publish a Skill directory to the registry (hosted tarball)").option("--dir <path>", "Skill directory (defaults to cwd)").option("--name <@publisher/skill>", "Override skill name (defaults to SKILL.md frontmatter)").option("--skill-version <semver>", "Override version (defaults to SKILL.md frontmatter)").option("--description <text>", "Override description (defaults to SKILL.md frontmatter)").option("--targets <list>", "Comma-separated target platforms metadata (optional)").option("--tag <tag>", "Dist-tag (default: latest)", "latest").option("--registry <url>", "Registry base URL (defaults to saved login)").option("--json", "Output JSON").action(async (options) => publish(options));
670
+ program.command("search <query>").description("Search Skills in the registry").option("--registry <url>", "Registry base URL (default: https://registry.skild.sh)").option("--limit <n>", "Max results (default: 50)", "50").option("--json", "Output JSON").action(async (query, options) => search(query, options));
309
671
  program.action(() => {
310
- console.log(chalk9.bold("\n\u{1F6E1}\uFE0F skild \u2014 Get your agents skilled.\n"));
672
+ console.log(chalk15.bold("\n\u{1F6E1}\uFE0F skild \u2014 Get your agents skilled.\n"));
311
673
  program.outputHelp();
312
674
  });
313
675
  var argv = process.argv.slice();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "skild",
3
- "version": "0.1.3",
3
+ "version": "0.1.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",
@@ -36,7 +36,8 @@
36
36
  "chalk": "^5.3.0",
37
37
  "commander": "^12.1.0",
38
38
  "ora": "^8.0.1",
39
- "@skild/core": "^0.1.3"
39
+ "tar": "^7.4.3",
40
+ "@skild/core": "^0.1.4"
40
41
  },
41
42
  "devDependencies": {
42
43
  "@types/node": "^20.10.0",