skilld 1.5.5 → 1.7.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 (120) hide show
  1. package/README.md +32 -23
  2. package/dist/_chunks/agent.mjs +2 -78
  3. package/dist/_chunks/agent.mjs.map +1 -1
  4. package/dist/_chunks/assemble.mjs +1 -18
  5. package/dist/_chunks/assemble.mjs.map +1 -1
  6. package/dist/_chunks/author-group.mjs +17 -0
  7. package/dist/_chunks/author-group.mjs.map +1 -0
  8. package/dist/_chunks/author.mjs +8 -24
  9. package/dist/_chunks/author.mjs.map +1 -1
  10. package/dist/_chunks/cache.mjs +1 -73
  11. package/dist/_chunks/cache.mjs.map +1 -1
  12. package/dist/_chunks/cache2.mjs +84 -17
  13. package/dist/_chunks/cache2.mjs.map +1 -1
  14. package/dist/_chunks/cli-helpers.mjs +3 -166
  15. package/dist/_chunks/cli-helpers.mjs.map +1 -1
  16. package/dist/_chunks/cli-helpers2.mjs +0 -11
  17. package/dist/_chunks/config.mjs +119 -54
  18. package/dist/_chunks/config.mjs.map +1 -1
  19. package/dist/_chunks/core.mjs +9 -0
  20. package/dist/_chunks/detect.mjs +29 -226
  21. package/dist/_chunks/detect.mjs.map +1 -1
  22. package/dist/_chunks/embedding-cache.mjs +0 -5
  23. package/dist/_chunks/embedding-cache2.mjs +2 -3
  24. package/dist/_chunks/formatting.mjs +0 -6
  25. package/dist/_chunks/formatting.mjs.map +1 -1
  26. package/dist/_chunks/index.d.mts +0 -10
  27. package/dist/_chunks/index.d.mts.map +1 -1
  28. package/dist/_chunks/index2.d.mts +3 -6
  29. package/dist/_chunks/index2.d.mts.map +1 -1
  30. package/dist/_chunks/index3.d.mts +81 -109
  31. package/dist/_chunks/index3.d.mts.map +1 -1
  32. package/dist/_chunks/install.mjs +85 -550
  33. package/dist/_chunks/install.mjs.map +1 -1
  34. package/dist/_chunks/install2.mjs +554 -0
  35. package/dist/_chunks/install2.mjs.map +1 -0
  36. package/dist/_chunks/libs/@sinclair/typebox.mjs +0 -444
  37. package/dist/_chunks/libs/@sinclair/typebox.mjs.map +1 -1
  38. package/dist/_chunks/list.mjs +0 -16
  39. package/dist/_chunks/list.mjs.map +1 -1
  40. package/dist/_chunks/lockfile.mjs +2 -10
  41. package/dist/_chunks/lockfile.mjs.map +1 -1
  42. package/dist/_chunks/markdown.mjs +0 -9
  43. package/dist/_chunks/markdown.mjs.map +1 -1
  44. package/dist/_chunks/package-json.mjs +0 -25
  45. package/dist/_chunks/package-json.mjs.map +1 -1
  46. package/dist/_chunks/package-registry.mjs +465 -0
  47. package/dist/_chunks/package-registry.mjs.map +1 -0
  48. package/dist/_chunks/pool2.mjs +0 -2
  49. package/dist/_chunks/pool2.mjs.map +1 -1
  50. package/dist/_chunks/prefix.mjs +108 -0
  51. package/dist/_chunks/prefix.mjs.map +1 -0
  52. package/dist/_chunks/prepare.mjs +14 -9
  53. package/dist/_chunks/prepare.mjs.map +1 -1
  54. package/dist/_chunks/prepare2.mjs +1 -19
  55. package/dist/_chunks/prepare2.mjs.map +1 -1
  56. package/dist/_chunks/prompts.mjs +6 -201
  57. package/dist/_chunks/prompts.mjs.map +1 -1
  58. package/dist/_chunks/retriv.mjs +23 -24
  59. package/dist/_chunks/retriv.mjs.map +1 -1
  60. package/dist/_chunks/rolldown-runtime.mjs +0 -2
  61. package/dist/_chunks/sanitize.mjs +0 -78
  62. package/dist/_chunks/sanitize.mjs.map +1 -1
  63. package/dist/_chunks/search-helpers.mjs +99 -0
  64. package/dist/_chunks/search-helpers.mjs.map +1 -0
  65. package/dist/_chunks/search-interactive.mjs +1 -18
  66. package/dist/_chunks/search-interactive.mjs.map +1 -1
  67. package/dist/_chunks/search.mjs +218 -19
  68. package/dist/_chunks/search.mjs.map +1 -0
  69. package/dist/_chunks/setup.mjs +0 -13
  70. package/dist/_chunks/setup.mjs.map +1 -1
  71. package/dist/_chunks/shared.mjs +1 -473
  72. package/dist/_chunks/shared.mjs.map +1 -1
  73. package/dist/_chunks/skills.mjs +3 -3
  74. package/dist/_chunks/skills.mjs.map +1 -1
  75. package/dist/_chunks/sources.mjs +1179 -1440
  76. package/dist/_chunks/sources.mjs.map +1 -1
  77. package/dist/_chunks/sync-registry.mjs +59 -0
  78. package/dist/_chunks/sync-registry.mjs.map +1 -0
  79. package/dist/_chunks/sync-shared.mjs +0 -16
  80. package/dist/_chunks/sync-shared2.mjs +10 -49
  81. package/dist/_chunks/sync-shared2.mjs.map +1 -1
  82. package/dist/_chunks/sync.mjs +209 -120
  83. package/dist/_chunks/sync.mjs.map +1 -1
  84. package/dist/_chunks/sync2.mjs +1 -21
  85. package/dist/_chunks/types.d.mts +0 -2
  86. package/dist/_chunks/types.d.mts.map +1 -1
  87. package/dist/_chunks/uninstall.mjs +3 -27
  88. package/dist/_chunks/uninstall.mjs.map +1 -1
  89. package/dist/_chunks/upload.mjs +152 -0
  90. package/dist/_chunks/upload.mjs.map +1 -0
  91. package/dist/_chunks/validate.mjs +1 -8
  92. package/dist/_chunks/validate.mjs.map +1 -1
  93. package/dist/_chunks/version.mjs +30 -0
  94. package/dist/_chunks/version.mjs.map +1 -0
  95. package/dist/_chunks/wizard.mjs +2 -3
  96. package/dist/_chunks/yaml.mjs +0 -21
  97. package/dist/_chunks/yaml.mjs.map +1 -1
  98. package/dist/agent/index.d.mts +0 -24
  99. package/dist/agent/index.d.mts.map +1 -1
  100. package/dist/agent/index.mjs +2 -9
  101. package/dist/cache/index.mjs +1 -3
  102. package/dist/cli-entry.mjs +0 -6
  103. package/dist/cli-entry.mjs.map +1 -1
  104. package/dist/cli.mjs +48 -33
  105. package/dist/cli.mjs.map +1 -1
  106. package/dist/index.d.mts +1 -1
  107. package/dist/index.mjs +2 -8
  108. package/dist/prepare.mjs +0 -12
  109. package/dist/prepare.mjs.map +1 -1
  110. package/dist/retriv/index.mjs +0 -2
  111. package/dist/retriv/worker.d.mts +0 -3
  112. package/dist/retriv/worker.d.mts.map +1 -1
  113. package/dist/retriv/worker.mjs +0 -2
  114. package/dist/retriv/worker.mjs.map +1 -1
  115. package/dist/sources/index.d.mts +2 -2
  116. package/dist/sources/index.mjs +3 -7
  117. package/dist/types.d.mts +1 -1
  118. package/package.json +20 -21
  119. package/dist/_chunks/search2.mjs +0 -319
  120. package/dist/_chunks/search2.mjs.map +0 -1
@@ -1,34 +1,30 @@
1
- import { c as getVersionKey, o as getCacheDir, t as CACHE_DIR } from "./config.mjs";
1
+ import { i as CACHE_DIR, r as getVersionKey, t as getCacheDir } from "./version.mjs";
2
2
  import { r as resolvePkgDir } from "./prepare.mjs";
3
3
  import { n as sanitizeMarkdown } from "./sanitize.mjs";
4
4
  import { a as hasShippedDocs, f as listReferenceFiles, i as getPkgKeyFiles, l as linkPkgNamed, m as readCachedSection, o as isCached, r as ensureCacheDir } from "./cache.mjs";
5
5
  import { i as parseFrontmatter } from "./markdown.mjs";
6
+ import { J as isPrerelease, M as resolveGitHubRepo, f as resolvePackageDocsWithAttempts, i as fetchPkgDist, m as fetchGitSkills, p as searchNpmPackages, rt as parsePackageSpec, s as readLocalDependencies, w as resolveCrateDocsWithAttempts } from "./sources.mjs";
6
7
  import { a as semverDiff, n as getSharedSkillsDir, t as SHARED_SKILLS_DIR } from "./shared.mjs";
7
- import { A as parseGitSkillInput, f as resolvePackageDocsWithAttempts, i as fetchPkgDist, k as fetchGitSkills, nt as parsePackageSpec, p as searchNpmPackages, q as isPrerelease, s as readLocalDependencies, x as resolveGitHubRepo } from "./sources.mjs";
8
8
  import { a as targets } from "./detect.mjs";
9
- import { a as sanitizeName, c as SECTION_OUTPUT_FILES, i as linkSkillToAgents, l as buildAllSectionPrompts, m as wrapSection, n as computeSkillDirName, p as portabilizePrompt, s as SECTION_MERGE_ORDER, t as generateSkillMd } from "./prompts.mjs";
9
+ import { c as portabilizePrompt, i as buildAllSectionPrompts, l as wrapSection, n as SECTION_MERGE_ORDER, r as SECTION_OUTPUT_FILES, t as generateSkillMd } from "./prompts.mjs";
10
+ import { i as sanitizeName, r as linkSkillToAgents, t as computeSkillDirName } from "./install.mjs";
10
11
  import { a as getModelLabel, i as getAvailableModels, s as optimizeDocs, t as detectImportedPackages } from "./agent.mjs";
11
- import { E as hasCompletedWizard, O as readConfig, S as suggestPrepareHook, _ as promptForAgent, b as resolveAgent, f as introLine, k as registerProject, o as getInstalledGenerators, p as isInteractive, w as defaultFeatures, x as sharedArgs } from "./cli-helpers.mjs";
12
+ import { a as readConfig, o as registerProject, r as hasCompletedWizard, t as defaultFeatures } from "./config.mjs";
13
+ import { S as suggestPrepareHook, _ as promptForAgent, b as resolveAgent, f as introLine, o as getInstalledGenerators, p as isInteractive, x as sharedArgs } from "./cli-helpers.mjs";
12
14
  import { a as removeLockEntry, i as readLock, n as parsePackages, s as writeLock } from "./lockfile.mjs";
13
15
  import { t as getProjectState } from "./skills.mjs";
16
+ import { n as resolveSkillName, r as toStoragePackageName, t as parseSkillInput } from "./prefix.mjs";
14
17
  import { l as timedSpinner, n as formatDuration } from "./formatting.mjs";
15
18
  import { t as runWizard } from "./wizard.mjs";
16
19
  import { S as writePromptFiles, _ as linkAllReferences, b as selectLlmConfig, c as ejectReferences, d as ensureGitignore, f as fetchAndCacheResources, g as indexResources, h as handleShippedSkills, l as enhanceSkillWithLLM, m as forceClearCache, n as RESOLVE_STEP_LABELS, o as detectChangelog, p as findRelatedSkills, t as DEFAULT_SECTIONS, u as ensureAgentInstructions, v as resolveBaseDir, y as resolveLocalDep } from "./sync-shared2.mjs";
17
20
  import { n as shutdownWorker } from "./pool2.mjs";
18
21
  import { dirname, join, relative, resolve } from "pathe";
19
22
  import { existsSync, mkdirSync, readFileSync, rmSync, writeFileSync } from "node:fs";
20
- import { isCI } from "std-env";
21
23
  import pLimit from "p-limit";
24
+ import { isCI } from "std-env";
22
25
  import * as p from "@clack/prompts";
23
26
  import { defineCommand } from "citty";
24
27
  import logUpdate from "log-update";
25
- //#region src/telemetry.ts
26
- /**
27
- * Anonymous telemetry — fire-and-forget GET to add-skill.vercel.sh/t
28
- *
29
- * Opt-out: set DISABLE_TELEMETRY=1 or DO_NOT_TRACK=1
30
- * Auto-disabled in CI environments.
31
- */
32
28
  const TELEMETRY_URL = "https://add-skill.vercel.sh/t";
33
29
  const SKILLS_VERSION = "1.3.9";
34
30
  function isEnabled() {
@@ -44,8 +40,6 @@ function track(data) {
44
40
  fetch(`${TELEMETRY_URL}?${params.toString()}`).catch(() => {});
45
41
  } catch {}
46
42
  }
47
- //#endregion
48
- //#region src/commands/sync-git.ts
49
43
  async function syncGitSkills(opts) {
50
44
  const { source, agent, global: isGlobal, yes } = opts;
51
45
  const cwd = process.cwd();
@@ -121,10 +115,6 @@ async function syncGitSkills(opts) {
121
115
  const names = selected.map((s) => `\x1B[36m${s.name}\x1B[0m`).join(", ");
122
116
  p.log.success(`Installed ${names}`);
123
117
  }
124
- /**
125
- * Generate a skill from a GitHub repo's docs (no npm package required).
126
- * Uses the same pipeline as npm packages: resolve → fetch → cache → generate → LLM enhance.
127
- */
128
118
  async function syncGitHubRepo(opts) {
129
119
  const { source, agent, global: isGlobal, yes } = opts;
130
120
  const owner = source.owner;
@@ -274,8 +264,6 @@ async function syncGitHubRepo(opts) {
274
264
  });
275
265
  p.outro(`Synced ${owner}/${repo} to ${relative(cwd, skillDir)}`);
276
266
  }
277
- //#endregion
278
- //#region src/commands/sync-parallel.ts
279
267
  const STATUS_ICONS = {
280
268
  pending: "○",
281
269
  resolving: "◐",
@@ -496,7 +484,6 @@ async function syncPackagesParallel(config) {
496
484
  p.log.warn(`Failed to suggest prepare hook: ${err instanceof Error ? err.message : String(err)}`);
497
485
  }
498
486
  }
499
- /** Phase 1: Generate base skill (no LLM). Returns 'shipped' if shipped skill was linked, or BaseSkillData. */
500
487
  async function syncBaseSkill(packageSpec, config, cwd, update) {
501
488
  const { name: packageName, tag: requestedTag } = parsePackageSpec(packageSpec);
502
489
  const localVersion = (await readLocalDependencies(cwd).catch(() => [])).find((d) => d.name === packageName)?.version;
@@ -651,7 +638,6 @@ async function syncBaseSkill(packageSpec, config, cwd, update) {
651
638
  overheadLines
652
639
  };
653
640
  }
654
- /** Phase 2: Enhance skill with LLM */
655
641
  async function enhanceWithLLM(packageName, data, config, cwd, update, sections, customPrompt) {
656
642
  const versionKey = getVersionKey(data.version);
657
643
  const skillDir = join(resolveBaseDir(cwd, config.agent, config.global), data.skillDirName);
@@ -710,8 +696,6 @@ async function enhanceWithLLM(packageName, data, config, cwd, update, sections,
710
696
  }
711
697
  update(packageName, "done", "Skill optimized", versionKey);
712
698
  }
713
- //#endregion
714
- //#region src/commands/sync.ts
715
699
  const RESOLVE_SOURCE_LABELS = {
716
700
  "npm": "npm registry",
717
701
  "github-docs": "GitHub versioned docs",
@@ -732,10 +716,18 @@ function showResolveAttempts(attempts) {
732
716
  p.log.message(` ${icon} ${source}${msg}`);
733
717
  }
734
718
  }
719
+ function isCrateSpec(spec) {
720
+ return spec.startsWith("crate:");
721
+ }
722
+ function toCrateIdentity(crateName) {
723
+ return `crate:${crateName}`;
724
+ }
735
725
  async function syncCommand(state, opts) {
736
726
  if (opts.packages && opts.packages.length > 0) {
737
- if (opts.packages.length > 1) return syncPackagesParallel({
738
- packages: opts.packages,
727
+ const crateSpecs = opts.packages.filter(isCrateSpec);
728
+ const npmSpecs = opts.packages.filter((p) => !isCrateSpec(p));
729
+ if (npmSpecs.length > 1) await syncPackagesParallel({
730
+ packages: npmSpecs,
739
731
  global: opts.global,
740
732
  agent: opts.agent,
741
733
  model: opts.model,
@@ -744,7 +736,8 @@ async function syncCommand(state, opts) {
744
736
  debug: opts.debug,
745
737
  mode: opts.mode
746
738
  });
747
- await syncSinglePackage(opts.packages[0], opts);
739
+ else if (npmSpecs.length === 1) await syncSinglePackage(npmSpecs[0], opts);
740
+ for (const spec of crateSpecs) await syncSinglePackage(spec, opts);
748
741
  return;
749
742
  }
750
743
  const packages = await interactivePicker(state);
@@ -821,64 +814,79 @@ async function pickFromList(packages, state) {
821
814
  return selected;
822
815
  }
823
816
  async function syncSinglePackage(packageSpec, config) {
824
- const { name: packageName, tag: requestedTag } = parsePackageSpec(packageSpec);
817
+ const isCrate = isCrateSpec(packageSpec);
818
+ const normalizedSpec = isCrate ? packageSpec.slice(6).trim() : packageSpec;
819
+ if (isCrate && !normalizedSpec) {
820
+ p.log.error("Invalid crate spec. Use format: crate:<name>");
821
+ return;
822
+ }
823
+ const { name: parsedName, tag: requestedTag } = parsePackageSpec(normalizedSpec);
824
+ const packageName = isCrate ? parsedName.toLowerCase() : parsedName;
825
+ const identityPackageName = isCrate ? toCrateIdentity(packageName) : packageName;
826
+ const storagePackageName = toStoragePackageName(identityPackageName);
825
827
  const spin = timedSpinner();
826
828
  spin.start(`Resolving ${packageSpec}`);
827
829
  const cwd = process.cwd();
828
- const localVersion = (await readLocalDependencies(cwd).catch(() => [])).find((d) => d.name === packageName)?.version;
829
- const resolveResult = await resolvePackageDocsWithAttempts(requestedTag ? packageSpec : packageName, {
830
+ const localDeps = isCrate ? [] : await readLocalDependencies(cwd).catch(() => []);
831
+ const localVersion = isCrate ? void 0 : localDeps.find((d) => d.name === packageName)?.version;
832
+ const resolveResult = isCrate ? await resolveCrateDocsWithAttempts(packageName, {
833
+ version: requestedTag,
834
+ onProgress: (step) => spin.message(`${identityPackageName}: ${step}`)
835
+ }) : await resolvePackageDocsWithAttempts(requestedTag ? normalizedSpec : packageName, {
830
836
  version: localVersion,
831
837
  cwd,
832
838
  onProgress: (step) => spin.message(`${packageName}: ${RESOLVE_STEP_LABELS[step]}`)
833
839
  });
834
840
  let resolved = resolveResult.package;
835
- if (!resolved) {
841
+ if (!resolved && !isCrate) {
836
842
  spin.message(`Resolving local package: ${packageName}`);
837
843
  resolved = await resolveLocalDep(packageName, cwd);
838
844
  }
839
845
  if (!resolved) {
840
- const earlyShipped = handleShippedSkills(packageName, localVersion || resolveResult.registryVersion || "latest", cwd, config.agent, config.global);
841
- if (earlyShipped) {
842
- const shared = !config.global && getSharedSkillsDir(cwd);
843
- for (const shipped of earlyShipped.shipped) {
844
- if (shared) linkSkillToAgents(shipped.skillName, shared, cwd, config.agent);
845
- p.log.success(`Using published SKILL.md: ${shipped.skillName} ${relative(cwd, shipped.skillDir)}`);
846
+ if (!isCrate) {
847
+ const earlyShipped = handleShippedSkills(packageName, localVersion || resolveResult.registryVersion || "latest", cwd, config.agent, config.global);
848
+ if (earlyShipped) {
849
+ const shared = !config.global && getSharedSkillsDir(cwd);
850
+ for (const shipped of earlyShipped.shipped) {
851
+ if (shared) linkSkillToAgents(shipped.skillName, shared, cwd, config.agent);
852
+ p.log.success(`Using published SKILL.md: ${shipped.skillName} → ${relative(cwd, shipped.skillDir)}`);
853
+ }
854
+ spin.stop(`Using published SKILL.md(s) from ${packageName}`);
855
+ return;
856
+ }
857
+ spin.message(`Searching npm for "${packageName}"...`);
858
+ const suggestions = await searchNpmPackages(packageName);
859
+ if (suggestions.length > 0) {
860
+ spin.stop(`Package "${packageName}" not found on npm`);
861
+ showResolveAttempts(resolveResult.attempts);
862
+ const selected = await p.select({
863
+ message: "Did you mean one of these?",
864
+ options: [...suggestions.map((s) => ({
865
+ label: s.name,
866
+ value: s.name,
867
+ hint: s.description
868
+ })), {
869
+ label: "None of these",
870
+ value: "_none_"
871
+ }]
872
+ });
873
+ if (!p.isCancel(selected) && selected !== "_none_") return syncSinglePackage(selected, config);
874
+ return;
846
875
  }
847
- spin.stop(`Using published SKILL.md(s) from ${packageName}`);
848
- return;
849
- }
850
- spin.message(`Searching npm for "${packageName}"...`);
851
- const suggestions = await searchNpmPackages(packageName);
852
- if (suggestions.length > 0) {
853
- spin.stop(`Package "${packageName}" not found on npm`);
854
- showResolveAttempts(resolveResult.attempts);
855
- const selected = await p.select({
856
- message: "Did you mean one of these?",
857
- options: [...suggestions.map((s) => ({
858
- label: s.name,
859
- value: s.name,
860
- hint: s.description
861
- })), {
862
- label: "None of these",
863
- value: "_none_"
864
- }]
865
- });
866
- if (!p.isCancel(selected) && selected !== "_none_") return syncSinglePackage(selected, config);
867
- return;
868
876
  }
869
- spin.stop(`Could not find docs for: ${packageName}`);
877
+ spin.stop(`Could not find docs for: ${identityPackageName}`);
870
878
  showResolveAttempts(resolveResult.attempts);
871
879
  return;
872
880
  }
873
- const version = localVersion || resolved.version || "latest";
881
+ const version = isCrate ? resolved.version || requestedTag || "latest" : localVersion || resolved.version || "latest";
874
882
  const versionKey = getVersionKey(version);
875
- if (config.force) forceClearCache(packageName, version);
876
- const useCache = isCached(packageName, version);
877
- if (!existsSync(join(cwd, "node_modules", packageName))) {
883
+ if (config.force) forceClearCache(storagePackageName, version);
884
+ const useCache = isCached(storagePackageName, version);
885
+ if (!isCrate && !existsSync(join(cwd, "node_modules", packageName))) {
878
886
  spin.message(`Downloading ${packageName}@${version} dist`);
879
887
  await fetchPkgDist(packageName, version);
880
888
  }
881
- const shippedResult = handleShippedSkills(packageName, version, cwd, config.agent, config.global);
889
+ const shippedResult = isCrate ? null : handleShippedSkills(packageName, version, cwd, config.agent, config.global);
882
890
  if (shippedResult) {
883
891
  const shared = !config.global && getSharedSkillsDir(cwd);
884
892
  for (const shipped of shippedResult.shipped) {
@@ -888,18 +896,18 @@ async function syncSinglePackage(packageSpec, config) {
888
896
  spin.stop(`Using published SKILL.md(s) from ${packageName}`);
889
897
  return;
890
898
  }
891
- spin.stop(`Resolved ${packageName}@${useCache ? versionKey : version}${config.force ? " (force)" : useCache ? " (cached)" : ""}`);
892
- if (!localVersion && !requestedTag && !isPrerelease(version)) {
899
+ spin.stop(`Resolved ${identityPackageName}@${useCache ? versionKey : version}${config.force ? " (force)" : useCache ? " (cached)" : ""}`);
900
+ if (!isCrate && !localVersion && !requestedTag && !isPrerelease(version)) {
893
901
  const nextTag = resolved.distTags?.next ?? resolved.distTags?.beta ?? resolved.distTags?.alpha;
894
902
  if (nextTag && (!resolved.releasedAt || !nextTag.releasedAt || nextTag.releasedAt > resolved.releasedAt)) p.log.warn(`\x1B[33mNo local dependency found — using latest stable (${version}). Prerelease ${nextTag.version} available: skilld add ${packageName}@beta\x1B[0m`);
895
903
  }
896
904
  ensureCacheDir();
897
905
  const baseDir = resolveBaseDir(cwd, config.agent, config.global);
898
- let skillDirName = config.name ? sanitizeName(config.name) : computeSkillDirName(packageName);
906
+ let skillDirName = config.name ? sanitizeName(config.name) : computeSkillDirName(storagePackageName);
899
907
  if (config.mode === "update" && !config.name) {
900
908
  const lock = readLock(baseDir);
901
909
  if (lock) {
902
- for (const [name, info] of Object.entries(lock.skills)) if (info.packageName === packageName || parsePackages(info.packages).some((p) => p.name === packageName)) {
910
+ for (const [name, info] of Object.entries(lock.skills)) if (info.packageName === identityPackageName || parsePackages(info.packages).some((p) => p.name === identityPackageName)) {
903
911
  skillDirName = name;
904
912
  break;
905
913
  }
@@ -908,7 +916,7 @@ async function syncSinglePackage(packageSpec, config) {
908
916
  const skillDir = config.eject ? typeof config.eject === "string" ? join(resolve(cwd, config.eject), skillDirName) : join(cwd, "skills", skillDirName) : join(baseDir, skillDirName);
909
917
  mkdirSync(skillDir, { recursive: true });
910
918
  const existingLock = config.eject ? void 0 : readLock(baseDir)?.skills[skillDirName];
911
- const isMerge = existingLock && existingLock.packageName && existingLock.packageName !== packageName;
919
+ const isMerge = existingLock && existingLock.packageName && existingLock.packageName !== identityPackageName;
912
920
  const updateCtx = config.mode === "update" && existingLock ? {
913
921
  oldVersion: existingLock.version,
914
922
  newVersion: version,
@@ -920,11 +928,11 @@ async function syncSinglePackage(packageSpec, config) {
920
928
  })()
921
929
  } : void 0;
922
930
  if (isMerge) {
923
- spin.stop(`Merging ${packageName} into ${skillDirName}`);
924
- linkPkgNamed(skillDir, packageName, cwd, version);
931
+ spin.stop(`Merging ${identityPackageName} into ${skillDirName}`);
932
+ linkPkgNamed(skillDir, storagePackageName, cwd, version);
925
933
  const repoSlug = resolved.repoUrl?.match(/github\.com\/([^/]+\/[^/]+?)(?:\.git)?(?:[/#]|$)/)?.[1];
926
934
  writeLock(baseDir, skillDirName, {
927
- packageName,
935
+ packageName: identityPackageName,
928
936
  version,
929
937
  repo: repoSlug,
930
938
  source: existingLock.source,
@@ -933,9 +941,10 @@ async function syncSinglePackage(packageSpec, config) {
933
941
  });
934
942
  const updatedLock = readLock(baseDir)?.skills[skillDirName];
935
943
  const allPackages = parsePackages(updatedLock?.packages).map((p) => ({ name: p.name }));
936
- const relatedSkills = await findRelatedSkills(packageName, baseDir);
937
- const pkgFiles = getPkgKeyFiles(existingLock.packageName, cwd, existingLock.version);
938
- const shippedDocs = hasShippedDocs(existingLock.packageName, cwd, existingLock.version);
944
+ const relatedSkills = await findRelatedSkills(storagePackageName, baseDir);
945
+ const existingStorageName = toStoragePackageName(existingLock.packageName);
946
+ const pkgFiles = getPkgKeyFiles(existingStorageName, cwd, existingLock.version);
947
+ const shippedDocs = hasShippedDocs(existingStorageName, cwd, existingLock.version);
939
948
  const mergeFeatures = readConfig().features ?? defaultFeatures;
940
949
  const skillMd = generateSkillMd({
941
950
  name: existingLock.packageName,
@@ -955,7 +964,7 @@ async function syncSinglePackage(packageSpec, config) {
955
964
  const mergeShared = !config.global && getSharedSkillsDir(cwd);
956
965
  if (mergeShared) linkSkillToAgents(skillDirName, mergeShared, cwd, config.agent);
957
966
  if (!config.global) registerProject(cwd);
958
- p.outro(`Merged ${packageName} into ${skillDirName}`);
967
+ p.outro(`Merged ${identityPackageName} into ${skillDirName}`);
959
968
  return;
960
969
  }
961
970
  const features = { ...readConfig().features ?? defaultFeatures };
@@ -963,7 +972,7 @@ async function syncSinglePackage(packageSpec, config) {
963
972
  const resSpin = timedSpinner();
964
973
  resSpin.start("Finding resources");
965
974
  const resources = await fetchAndCacheResources({
966
- packageName,
975
+ packageName: storagePackageName,
967
976
  resolved,
968
977
  version,
969
978
  useCache,
@@ -981,12 +990,12 @@ async function syncSinglePackage(packageSpec, config) {
981
990
  if (resources.hasReleases) resParts.push("releases");
982
991
  resSpin.stop(resources.usedCache ? `Loaded ${resParts.length > 0 ? resParts.join(", ") : "resources"} (cached)` : `Fetched ${resParts.length > 0 ? resParts.join(", ") : "resources"}`);
983
992
  for (const w of resources.warnings) p.log.warn(`\x1B[33m${w}\x1B[0m`);
984
- linkAllReferences(skillDir, packageName, cwd, version, resources.docsType, void 0, features, resources.repoInfo);
993
+ linkAllReferences(skillDir, storagePackageName, cwd, version, resources.docsType, void 0, features, resources.repoInfo);
985
994
  if (features.search) {
986
995
  const idxSpin = timedSpinner();
987
996
  idxSpin.start("Creating search index");
988
997
  await indexResources({
989
- packageName,
998
+ packageName: storagePackageName,
990
999
  version,
991
1000
  cwd,
992
1001
  docsToIndex: resources.docsToIndex,
@@ -995,15 +1004,15 @@ async function syncSinglePackage(packageSpec, config) {
995
1004
  });
996
1005
  idxSpin.stop("Search index ready");
997
1006
  }
998
- const hasChangelog = detectChangelog(resolvePkgDir(packageName, cwd, version), getCacheDir(packageName, version));
999
- const relatedSkills = await findRelatedSkills(packageName, baseDir);
1000
- const shippedDocs = hasShippedDocs(packageName, cwd, version);
1001
- const pkgFiles = getPkgKeyFiles(packageName, cwd, version);
1007
+ const hasChangelog = detectChangelog(resolvePkgDir(storagePackageName, cwd, version), getCacheDir(storagePackageName, version));
1008
+ const relatedSkills = await findRelatedSkills(storagePackageName, baseDir);
1009
+ const shippedDocs = hasShippedDocs(storagePackageName, cwd, version);
1010
+ const pkgFiles = getPkgKeyFiles(storagePackageName, cwd, version);
1002
1011
  const repoSlug = resolved.repoUrl?.match(/github\.com\/([^/]+\/[^/]+?)(?:\.git)?(?:[/#]|$)/)?.[1];
1003
- if (!config.eject) linkPkgNamed(skillDir, packageName, cwd, version);
1012
+ if (!config.eject) linkPkgNamed(skillDir, storagePackageName, cwd, version);
1004
1013
  if (!config.eject) {
1005
1014
  writeLock(baseDir, skillDirName, {
1006
- packageName,
1015
+ packageName: identityPackageName,
1007
1016
  version,
1008
1017
  repo: repoSlug,
1009
1018
  source: resources.docSource,
@@ -1013,7 +1022,7 @@ async function syncSinglePackage(packageSpec, config) {
1013
1022
  const lock = readLock(baseDir);
1014
1023
  if (lock) for (const [name, info] of Object.entries(lock.skills)) {
1015
1024
  if (name === skillDirName) continue;
1016
- if (info.packageName === packageName || parsePackages(info.packages).some((p) => p.name === packageName)) {
1025
+ if (info.packageName === identityPackageName || parsePackages(info.packages).some((p) => p.name === identityPackageName)) {
1017
1026
  removeLockEntry(baseDir, name);
1018
1027
  const staleDir = join(baseDir, name);
1019
1028
  if (existsSync(staleDir)) rmSync(staleDir, { recursive: true });
@@ -1023,7 +1032,7 @@ async function syncSinglePackage(packageSpec, config) {
1023
1032
  const allPackages = parsePackages((config.eject ? void 0 : readLock(baseDir)?.skills[skillDirName])?.packages).map((p) => ({ name: p.name }));
1024
1033
  const isEject = !!config.eject;
1025
1034
  const baseSkillMd = generateSkillMd({
1026
- name: packageName,
1035
+ name: identityPackageName,
1027
1036
  version,
1028
1037
  releasedAt: resolved.releasedAt,
1029
1038
  description: resolved.description,
@@ -1047,19 +1056,19 @@ async function syncSinglePackage(packageSpec, config) {
1047
1056
  p.log.success(config.mode === "update" ? `Updated skill: ${relative(cwd, skillDir)}` : `Created base skill: ${relative(cwd, skillDir)}`);
1048
1057
  const allSectionsCached = !config.force && DEFAULT_SECTIONS.every((s) => {
1049
1058
  const outputFile = SECTION_OUTPUT_FILES[s];
1050
- return readCachedSection(packageName, version, outputFile) !== null;
1059
+ return readCachedSection(storagePackageName, version, outputFile) !== null;
1051
1060
  });
1052
1061
  if (allSectionsCached) {
1053
1062
  const cachedParts = [];
1054
1063
  for (const s of SECTION_MERGE_ORDER) {
1055
1064
  if (!DEFAULT_SECTIONS.includes(s)) continue;
1056
1065
  const outputFile = SECTION_OUTPUT_FILES[s];
1057
- const content = readCachedSection(packageName, version, outputFile);
1066
+ const content = readCachedSection(storagePackageName, version, outputFile);
1058
1067
  if (content) cachedParts.push(wrapSection(s, content));
1059
1068
  }
1060
1069
  const cachedBody = cachedParts.join("\n\n");
1061
1070
  const skillMd = generateSkillMd({
1062
- name: packageName,
1071
+ name: identityPackageName,
1063
1072
  version,
1064
1073
  releasedAt: resolved.releasedAt,
1065
1074
  description: resolved.description,
@@ -1093,7 +1102,7 @@ async function syncSinglePackage(packageSpec, config) {
1093
1102
  if (!allSectionsCached && !globalConfig.skipLlm && !(config.yes && !resolvedModel)) {
1094
1103
  const llmConfig = await selectLlmConfig(resolvedModel, void 0, updateCtx);
1095
1104
  if (llmConfig?.promptOnly) writePromptFiles({
1096
- packageName,
1105
+ packageName: storagePackageName,
1097
1106
  skillDir,
1098
1107
  version,
1099
1108
  hasIssues: resources.hasIssues,
@@ -1111,7 +1120,8 @@ async function syncSinglePackage(packageSpec, config) {
1111
1120
  else if (llmConfig) {
1112
1121
  p.log.step(getModelLabel(llmConfig.model));
1113
1122
  await enhanceSkillWithLLM({
1114
- packageName,
1123
+ packageName: identityPackageName,
1124
+ cachePackageName: storagePackageName,
1115
1125
  version,
1116
1126
  skillDir,
1117
1127
  dirName: skillDirName,
@@ -1142,7 +1152,7 @@ async function syncSinglePackage(packageSpec, config) {
1142
1152
  recursive: true,
1143
1153
  force: true
1144
1154
  });
1145
- ejectReferences(skillDir, packageName, cwd, version, resources.docsType, features, resources.repoInfo);
1155
+ ejectReferences(skillDir, storagePackageName, cwd, version, resources.docsType, features, resources.repoInfo);
1146
1156
  }
1147
1157
  if (!isEject) {
1148
1158
  const shared = !config.global && getSharedSkillsDir(cwd);
@@ -1154,7 +1164,7 @@ async function syncSinglePackage(packageSpec, config) {
1154
1164
  await shutdownWorker();
1155
1165
  const ejectMsg = isEject ? " (ejected)" : "";
1156
1166
  const relDir = relative(cwd, skillDir);
1157
- p.outro(config.mode === "update" ? `Updated ${packageName}${ejectMsg}` : `Synced ${packageName} → ${relDir}${ejectMsg}`);
1167
+ p.outro(config.mode === "update" ? `Updated ${identityPackageName}${ejectMsg}` : `Synced ${identityPackageName} → ${relDir}${ejectMsg}`);
1158
1168
  try {
1159
1169
  await suggestPrepareHook(cwd);
1160
1170
  } catch (err) {
@@ -1164,12 +1174,12 @@ async function syncSinglePackage(packageSpec, config) {
1164
1174
  const addCommandDef = defineCommand({
1165
1175
  meta: {
1166
1176
  name: "add",
1167
- description: "Add skills for package(s)"
1177
+ description: "Install skills (npm:<pkg>, crate:<name>, gh:<owner/repo>, @<curator>)"
1168
1178
  },
1169
1179
  args: {
1170
1180
  package: {
1171
1181
  type: "positional",
1172
- description: "Package(s) to sync (space or comma-separated, e.g., vue nuxt pinia)",
1182
+ description: "Package(s) to sync (space/comma-separated; npm:<pkg>, crate:<name>, or owner/repo)",
1173
1183
  required: true
1174
1184
  },
1175
1185
  skill: {
@@ -1197,12 +1207,43 @@ const addCommandDef = defineCommand({
1197
1207
  return;
1198
1208
  }
1199
1209
  if (!hasCompletedWizard()) await runWizard({ agent });
1210
+ const parsedSources = rawInputs.map(parseSkillInput);
1200
1211
  const gitSources = [];
1201
- const npmTokens = [];
1202
- for (const input of rawInputs) {
1203
- const git = parseGitSkillInput(input);
1204
- if (git) gitSources.push(git);
1205
- else npmTokens.push(input);
1212
+ const npmEntries = [];
1213
+ const crateSpecs = [];
1214
+ const unsupported = [];
1215
+ for (const source of parsedSources) switch (source.type) {
1216
+ case "git":
1217
+ gitSources.push(source.source);
1218
+ break;
1219
+ case "npm":
1220
+ npmEntries.push({
1221
+ name: source.package,
1222
+ spec: source.tag ? `${source.package}@${source.tag}` : source.package
1223
+ });
1224
+ break;
1225
+ case "crate":
1226
+ crateSpecs.push(source.version ? `crate:${source.package}@${source.version}` : `crate:${source.package}`);
1227
+ break;
1228
+ case "bare":
1229
+ p.log.warn(`Bare names are deprecated. Use \x1B[36mnpm:${source.package}\x1B[0m instead.`);
1230
+ npmEntries.push({
1231
+ name: source.package,
1232
+ spec: source.tag ? `${source.package}@${source.tag}` : source.package
1233
+ });
1234
+ break;
1235
+ case "curator":
1236
+ unsupported.push(`@${source.handle} (curator)`);
1237
+ break;
1238
+ case "collection":
1239
+ unsupported.push(`@${source.handle}/${source.name} (collection)`);
1240
+ break;
1241
+ default: throw new Error(`Unhandled SkillSource type: ${JSON.stringify(source)}`);
1242
+ }
1243
+ if (unsupported.length > 0) {
1244
+ p.log.error(`Curator and collection installs are not yet available:\n ${unsupported.join("\n ")}\n\nFollow https://skilld.dev for launch updates.`);
1245
+ process.exitCode = 1;
1246
+ if (gitSources.length === 0 && npmEntries.length === 0 && crateSpecs.length === 0) return;
1206
1247
  }
1207
1248
  if (gitSources.length > 0) for (const source of gitSources) {
1208
1249
  const skillFilter = args.skill ? args.skill.split(/[,\s]+/).map((s) => s.trim()).filter(Boolean) : void 0;
@@ -1217,15 +1258,50 @@ const addCommandDef = defineCommand({
1217
1258
  skillFilter
1218
1259
  });
1219
1260
  }
1220
- if (npmTokens.length > 0) {
1221
- const packages = [...new Set(npmTokens.flatMap((s) => s.split(/[,\s]+/)).map((s) => s.trim()).filter(Boolean))];
1261
+ if (npmEntries.length > 0) {
1262
+ const { syncRegistrySkill } = await import("./sync-registry.mjs");
1263
+ const seen = /* @__PURE__ */ new Set();
1264
+ const dedupedEntries = npmEntries.filter((e) => {
1265
+ if (seen.has(e.name)) return false;
1266
+ seen.add(e.name);
1267
+ return true;
1268
+ });
1269
+ const fallbackPackages = [];
1270
+ for (const entry of dedupedEntries) {
1271
+ const result = await syncRegistrySkill({
1272
+ packageName: entry.name,
1273
+ agent,
1274
+ cwd
1275
+ });
1276
+ if (result) p.log.success(`Installed \x1B[36m${result.name}\x1B[0m from registry`);
1277
+ else fallbackPackages.push(entry.spec);
1278
+ }
1279
+ if (fallbackPackages.length > 0) {
1280
+ const state = await getProjectState(cwd);
1281
+ p.intro(introLine({
1282
+ state,
1283
+ agentId: agent || void 0
1284
+ }));
1285
+ await syncCommand(state, {
1286
+ packages: [...fallbackPackages, ...crateSpecs],
1287
+ global: args.global,
1288
+ agent,
1289
+ model: args.model,
1290
+ yes: args.yes,
1291
+ force: args.force,
1292
+ debug: args.debug
1293
+ });
1294
+ return;
1295
+ }
1296
+ }
1297
+ if (crateSpecs.length > 0) {
1222
1298
  const state = await getProjectState(cwd);
1223
1299
  p.intro(introLine({
1224
1300
  state,
1225
1301
  agentId: agent || void 0
1226
1302
  }));
1227
- return syncCommand(state, {
1228
- packages,
1303
+ await syncCommand(state, {
1304
+ packages: crateSpecs,
1229
1305
  global: args.global,
1230
1306
  agent,
1231
1307
  model: args.model,
@@ -1337,7 +1413,7 @@ const updateCommandDef = defineCommand({
1337
1413
  }
1338
1414
  if (agent === "none") {
1339
1415
  const state = await getProjectState(cwd);
1340
- const packages = args.package ? [...new Set([args.package, ...args._ || []].flatMap((s) => s.split(/[,\s]+/)).map((s) => s.trim()).filter(Boolean))] : state.outdated.map((s) => s.packageName || s.name);
1416
+ const packages = args.package ? Array.from(new Set([args.package, ...args._ || []].flatMap((s) => s.split(/[,\s]+/)).map((s) => s.trim()).filter(Boolean)), (s) => resolveSkillName(s)).filter((s) => s !== null) : state.outdated.map((s) => s.packageName || s.name);
1341
1417
  if (packages.length === 0) {
1342
1418
  if (!silent) p.log.success("All skills up to date");
1343
1419
  return;
@@ -1359,22 +1435,36 @@ const updateCommandDef = defineCommand({
1359
1435
  agentId: config.agent || agent || void 0
1360
1436
  }));
1361
1437
  }
1362
- if (args.package) return syncCommand(state, {
1363
- packages: [...new Set([args.package, ...args._ || []].flatMap((s) => s.split(/[,\s]+/)).map((s) => s.trim()).filter(Boolean))],
1364
- global: args.global,
1365
- agent,
1366
- model: args.model || (silent ? config.model : void 0),
1367
- yes: args.yes || silent,
1368
- force: args.force,
1369
- debug: args.debug,
1370
- mode: "update"
1371
- });
1372
- if (state.outdated.length === 0) {
1438
+ if (args.package) {
1439
+ const raw = [...new Set([args.package, ...args._ || []].flatMap((s) => s.split(/[,\s]+/)).map((s) => s.trim()).filter(Boolean))];
1440
+ const packages = [];
1441
+ for (const r of raw) {
1442
+ const name = resolveSkillName(r);
1443
+ if (!name) {
1444
+ p.log.warn(`Cannot update \x1B[36m${r}\x1B[0m: curator/collection inputs are not addressable here.`);
1445
+ continue;
1446
+ }
1447
+ packages.push(name);
1448
+ }
1449
+ if (packages.length === 0) return;
1450
+ return syncCommand(state, {
1451
+ packages,
1452
+ global: args.global,
1453
+ agent,
1454
+ model: args.model || (silent ? config.model : void 0),
1455
+ yes: args.yes || silent,
1456
+ force: args.force,
1457
+ debug: args.debug,
1458
+ mode: "update"
1459
+ });
1460
+ }
1461
+ const crateSpecs = state.skills.map((s) => s.info?.packageName).filter((name) => !!name && name.startsWith("crate:"));
1462
+ if (state.outdated.length === 0 && crateSpecs.length === 0) {
1373
1463
  p.log.success("All skills up to date");
1374
1464
  return;
1375
1465
  }
1376
1466
  return syncCommand(state, {
1377
- packages: state.outdated.map((s) => s.packageName || s.name),
1467
+ packages: [...state.outdated.map((s) => s.packageName || s.name), ...crateSpecs],
1378
1468
  global: args.global,
1379
1469
  agent,
1380
1470
  model: args.model || (silent ? config.model : void 0),
@@ -1509,7 +1599,6 @@ async function exportPortablePrompts(packageSpec, opts) {
1509
1599
  const outputFileList = sectionList.map((s) => SECTION_OUTPUT_FILES[s]).join(", ");
1510
1600
  p.log.info(`Have your agent enhance the skill. Give it this prompt:\n\x1B[2m\x1B[3m Read each prompt file (${promptFiles}) in ${relDir}/, read the\n referenced files, then write your output to the matching file (${outputFileList}).\n When done, run: skilld assemble\x1B[0m`);
1511
1601
  }
1512
- //#endregion
1513
- export { updateCommandDef as a, syncCommand as i, ejectCommandDef as n, exportPortablePrompts as r, addCommandDef as t };
1602
+ export { syncCommand as a, isCrateSpec as i, ejectCommandDef as n, updateCommandDef as o, exportPortablePrompts as r, addCommandDef as t };
1514
1603
 
1515
1604
  //# sourceMappingURL=sync.mjs.map