ht-skills 0.1.1 → 0.1.3

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 CHANGED
@@ -5,7 +5,7 @@ CLI for installing and submitting skills from HT Skills Marketplace.
5
5
  ## Usage
6
6
 
7
7
  ```powershell
8
- npx ht-skills install repo-bug-analyze --registry http://skills.ic.aeroht.local
8
+ npx ht-skills add http://skills.ic.aeroht.local --skill repo-bug-analyze
9
9
  ```
10
10
 
11
11
  ## Commands
@@ -14,4 +14,5 @@ npx ht-skills install repo-bug-analyze --registry http://skills.ic.aeroht.local
14
14
  ht-skills search <query> [--registry <url>] [--limit <n>]
15
15
  ht-skills submit <skillDir> [--registry <url>] [--submitter <name>] [--visibility public|private|shared] [--shared-with a@b.com,c@d.com] [--publish-now]
16
16
  ht-skills install <slug[@version]> [--registry <url>] [--target <dir>] [--tool codex|claude|vscode]
17
+ ht-skills add <registry> --skill <slug[@version]> [--tool codex|claude|vscode]
17
18
  ```
package/bin/ht-skills.js CHANGED
@@ -3,6 +3,10 @@
3
3
  const cli = require("../lib/cli");
4
4
 
5
5
  cli.main().catch((error) => {
6
+ if (error && error.reported) {
7
+ process.exitCode = 1;
8
+ return;
9
+ }
6
10
  // eslint-disable-next-line no-console
7
11
  console.error(`error: ${error.message}`);
8
12
  process.exitCode = 1;
package/lib/cli.js CHANGED
@@ -41,13 +41,15 @@ function printHelp() {
41
41
  ht-skills search <query> [--registry <url>] [--limit <n>]
42
42
  ht-skills submit <skillDir> [--registry <url>] [--submitter <name>] [--visibility public|private|shared] [--shared-with a@b.com,c@d.com] [--publish-now]
43
43
  ht-skills install <slug[@version]> [--registry <url>] [--target <dir>] [--tool codex|claude|vscode]
44
+ ht-skills add <registry> --skill <slug[@version]> [--tool codex|claude|vscode]
44
45
 
45
46
  Examples:
46
47
  ht-skills search openai --registry http://localhost:8787
47
48
  ht-skills submit ./examples/hello-skill --registry http://localhost:8787
48
49
  ht-skills install hello-skill@1.0.0 --registry http://localhost:8787 --tool codex
49
50
  ht-skills install hello-skill@1.0.0 --registry http://localhost:8787 --tool codex,claude,vscode
50
- ht-skills install hello-skill --registry http://localhost:8787`);
51
+ ht-skills install hello-skill --registry http://localhost:8787
52
+ ht-skills add http://localhost:8787 --skill hello-skill`);
51
53
  }
52
54
 
53
55
  function parseArgs(argv) {
@@ -91,11 +93,37 @@ async function requestJson(url, options = {}) {
91
93
  }
92
94
  if (!res.ok) {
93
95
  const message = payload.error || text || `HTTP ${res.status}`;
94
- throw new Error(message);
96
+ const error = new Error(message);
97
+ error.status = res.status;
98
+ error.url = url;
99
+ throw error;
95
100
  }
96
101
  return payload;
97
102
  }
98
103
 
104
+ function formatInstallError(error, { slug, version = null, registry, stage = "resolve" }) {
105
+ const rawMessage = String(error?.message || "Install failed").trim();
106
+ const status = Number(error?.status || 0);
107
+ const lowerMessage = rawMessage.toLowerCase();
108
+ const isNotFound = status === 404 || lowerMessage === "not found";
109
+
110
+ if (isNotFound && stage === "resolve") {
111
+ return `Skill "${slug}" was not found in registry ${registry}.`;
112
+ }
113
+ if (isNotFound && stage === "metadata") {
114
+ return version
115
+ ? `Skill "${slug}@${version}" metadata was not found in registry ${registry}.`
116
+ : `Skill "${slug}" metadata was not found in registry ${registry}.`;
117
+ }
118
+ if (isNotFound && stage === "bundle") {
119
+ return version
120
+ ? `Skill bundle "${slug}@${version}" was not found in registry ${registry}.`
121
+ : `Skill bundle for "${slug}" was not found in registry ${registry}.`;
122
+ }
123
+
124
+ return rawMessage;
125
+ }
126
+
99
127
  async function walkFiles(baseDir) {
100
128
  const results = [];
101
129
  const ignored = new Set([".git", "node_modules", ".DS_Store"]);
@@ -448,15 +476,31 @@ async function cmdInstall(flags, deps = {}) {
448
476
  const parsed = parseSpec(spec);
449
477
 
450
478
  const resolveSpinner = ui ? ui.spinner() : null;
451
- if (resolveSpinner) {
452
- // eslint-disable-next-line no-console
453
- console.log(`\n${renderGradientBanner()}\n`);
454
- ui.intro(ui.pc.bgCyan(ui.pc.black(" ht-skills ")));
455
- resolveSpinner.start(`Resolving ${parsed.slug}`);
456
- }
457
- const version = await fetchResolvedVersion(registry, parsed, requestJsonImpl);
458
- if (resolveSpinner) {
459
- resolveSpinner.stop(`Resolved ${parsed.slug}@${version}`);
479
+ let version;
480
+ try {
481
+ if (resolveSpinner) {
482
+ // eslint-disable-next-line no-console
483
+ console.log(`\n${renderGradientBanner()}\n`);
484
+ ui.intro(ui.pc.bgCyan(ui.pc.black(" ht-skills ")));
485
+ resolveSpinner.start(`Resolving ${parsed.slug}`);
486
+ }
487
+ version = await fetchResolvedVersion(registry, parsed, requestJsonImpl);
488
+ if (resolveSpinner) {
489
+ resolveSpinner.stop(`Resolved ${parsed.slug}@${version}`);
490
+ }
491
+ } catch (error) {
492
+ const friendlyMessage = formatInstallError(error, {
493
+ slug: parsed.slug,
494
+ registry,
495
+ stage: "resolve",
496
+ });
497
+ if (resolveSpinner) {
498
+ resolveSpinner.stop(ui.pc.red(`Unable to resolve ${parsed.slug}`));
499
+ ui.outro(ui.pc.red(friendlyMessage));
500
+ error.reported = true;
501
+ }
502
+ error.message = friendlyMessage;
503
+ throw error;
460
504
  }
461
505
 
462
506
  let toolIds = normalizeToolIds(flags.tool);
@@ -467,7 +511,15 @@ async function cmdInstall(flags, deps = {}) {
467
511
  metadata = await requestJsonImpl(
468
512
  `${registry}/api/skills/${encodeURIComponent(parsed.slug)}/${encodeURIComponent(version)}`,
469
513
  );
470
- } catch {
514
+ } catch (error) {
515
+ if (Number(error?.status || 0) !== 404 && String(error?.message || "").toLowerCase() !== "not found") {
516
+ throw new Error(formatInstallError(error, {
517
+ slug: parsed.slug,
518
+ version,
519
+ registry,
520
+ stage: "metadata",
521
+ }));
522
+ }
471
523
  metadata = null;
472
524
  }
473
525
 
@@ -540,7 +592,16 @@ async function cmdInstall(flags, deps = {}) {
540
592
  }
541
593
  const bundle = await requestJsonImpl(
542
594
  `${registry}/api/skills/${encodeURIComponent(parsed.slug)}/${encodeURIComponent(version)}/bundle`,
543
- );
595
+ ).catch((error) => {
596
+ const friendlyError = new Error(formatInstallError(error, {
597
+ slug: parsed.slug,
598
+ version,
599
+ registry,
600
+ stage: "bundle",
601
+ }));
602
+ friendlyError.status = error?.status;
603
+ throw friendlyError;
604
+ });
544
605
  if (bundleSpinner) {
545
606
  bundleSpinner.stop(`Downloaded ${parsed.slug}@${version}`);
546
607
  }
@@ -644,6 +705,26 @@ async function cmdSubmit(flags, deps = {}) {
644
705
  log(JSON.stringify(result, null, 2));
645
706
  }
646
707
 
708
+ async function cmdAdd(flags, deps = {}) {
709
+ const source = String(flags._[0] || "").trim();
710
+ const skill = String(flags.skill || "").trim();
711
+
712
+ if (!source) {
713
+ throw new Error("add requires a registry URL, for example ht-skills add http://localhost:8787 --skill hello-skill");
714
+ }
715
+ if (!skill) {
716
+ throw new Error("add requires --skill <slug> or --skill <slug@version>");
717
+ }
718
+
719
+ const installFlags = {
720
+ ...flags,
721
+ _: [skill],
722
+ registry: source,
723
+ };
724
+
725
+ return cmdInstall(installFlags, deps);
726
+ }
727
+
647
728
  async function main(argv = process.argv) {
648
729
  const [, , command, ...rest] = argv;
649
730
  const flags = parseArgs(rest);
@@ -660,6 +741,10 @@ async function main(argv = process.argv) {
660
741
  await cmdInstall(flags);
661
742
  return;
662
743
  }
744
+ if (command === "add") {
745
+ await cmdAdd(flags);
746
+ return;
747
+ }
663
748
  if (command === "submit") {
664
749
  await cmdSubmit(flags);
665
750
  return;
@@ -678,6 +763,7 @@ module.exports = {
678
763
  resolveInstallTargets,
679
764
  fetchResolvedVersion,
680
765
  cmdInstall,
766
+ cmdAdd,
681
767
  cmdSearch,
682
768
  cmdSubmit,
683
769
  main,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ht-skills",
3
- "version": "0.1.1",
3
+ "version": "0.1.3",
4
4
  "description": "CLI for installing and submitting skills from HT Skills Marketplace.",
5
5
  "type": "commonjs",
6
6
  "bin": {