skilld 1.6.2 → 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 (73) hide show
  1. package/README.md +29 -20
  2. package/dist/_chunks/agent.mjs +2 -1
  3. package/dist/_chunks/agent.mjs.map +1 -1
  4. package/dist/_chunks/assemble.mjs +1 -1
  5. package/dist/_chunks/author-group.mjs +17 -0
  6. package/dist/_chunks/author-group.mjs.map +1 -0
  7. package/dist/_chunks/author.mjs +8 -6
  8. package/dist/_chunks/author.mjs.map +1 -1
  9. package/dist/_chunks/cache.mjs +1 -1
  10. package/dist/_chunks/cache2.mjs +1 -1
  11. package/dist/_chunks/cli-helpers.mjs +3 -119
  12. package/dist/_chunks/cli-helpers.mjs.map +1 -1
  13. package/dist/_chunks/config.mjs +119 -27
  14. package/dist/_chunks/config.mjs.map +1 -1
  15. package/dist/_chunks/core.mjs +1 -1
  16. package/dist/_chunks/embedding-cache2.mjs +1 -1
  17. package/dist/_chunks/index.d.mts.map +1 -1
  18. package/dist/_chunks/index3.d.mts +79 -78
  19. package/dist/_chunks/index3.d.mts.map +1 -1
  20. package/dist/_chunks/install.mjs +85 -535
  21. package/dist/_chunks/install.mjs.map +1 -1
  22. package/dist/_chunks/install2.mjs +554 -0
  23. package/dist/_chunks/install2.mjs.map +1 -0
  24. package/dist/_chunks/lockfile.mjs +1 -0
  25. package/dist/_chunks/lockfile.mjs.map +1 -1
  26. package/dist/_chunks/package-registry.mjs +465 -0
  27. package/dist/_chunks/package-registry.mjs.map +1 -0
  28. package/dist/_chunks/prefix.mjs +108 -0
  29. package/dist/_chunks/prefix.mjs.map +1 -0
  30. package/dist/_chunks/prepare.mjs +6 -2
  31. package/dist/_chunks/prepare.mjs.map +1 -1
  32. package/dist/_chunks/prepare2.mjs +1 -1
  33. package/dist/_chunks/prompts.mjs +5 -99
  34. package/dist/_chunks/prompts.mjs.map +1 -1
  35. package/dist/_chunks/search-helpers.mjs +99 -0
  36. package/dist/_chunks/search-helpers.mjs.map +1 -0
  37. package/dist/_chunks/search-interactive.mjs +1 -1
  38. package/dist/_chunks/search-interactive.mjs.map +1 -1
  39. package/dist/_chunks/search.mjs +219 -1
  40. package/dist/_chunks/search.mjs.map +1 -0
  41. package/dist/_chunks/shared.mjs +1 -463
  42. package/dist/_chunks/shared.mjs.map +1 -1
  43. package/dist/_chunks/skills.mjs +1 -1
  44. package/dist/_chunks/sources.mjs +1177 -988
  45. package/dist/_chunks/sources.mjs.map +1 -1
  46. package/dist/_chunks/sync-registry.mjs +59 -0
  47. package/dist/_chunks/sync-registry.mjs.map +1 -0
  48. package/dist/_chunks/sync-shared2.mjs +10 -7
  49. package/dist/_chunks/sync-shared2.mjs.map +1 -1
  50. package/dist/_chunks/sync.mjs +208 -99
  51. package/dist/_chunks/sync.mjs.map +1 -1
  52. package/dist/_chunks/sync2.mjs +1 -1
  53. package/dist/_chunks/uninstall.mjs +3 -2
  54. package/dist/_chunks/uninstall.mjs.map +1 -1
  55. package/dist/_chunks/upload.mjs +152 -0
  56. package/dist/_chunks/upload.mjs.map +1 -0
  57. package/dist/_chunks/validate.mjs +1 -1
  58. package/dist/_chunks/version.mjs +30 -0
  59. package/dist/_chunks/version.mjs.map +1 -0
  60. package/dist/_chunks/wizard.mjs +2 -1
  61. package/dist/_chunks/wizard.mjs.map +1 -1
  62. package/dist/agent/index.mjs +2 -1
  63. package/dist/cache/index.mjs +1 -1
  64. package/dist/cli.mjs +48 -20
  65. package/dist/cli.mjs.map +1 -1
  66. package/dist/index.d.mts +1 -1
  67. package/dist/index.mjs +2 -2
  68. package/dist/sources/index.d.mts +2 -2
  69. package/dist/sources/index.mjs +3 -3
  70. package/dist/types.d.mts +1 -1
  71. package/package.json +11 -12
  72. package/dist/_chunks/search2.mjs +0 -310
  73. package/dist/_chunks/search2.mjs.map +0 -1
@@ -1,16 +1,19 @@
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";
@@ -713,10 +716,18 @@ function showResolveAttempts(attempts) {
713
716
  p.log.message(` ${icon} ${source}${msg}`);
714
717
  }
715
718
  }
719
+ function isCrateSpec(spec) {
720
+ return spec.startsWith("crate:");
721
+ }
722
+ function toCrateIdentity(crateName) {
723
+ return `crate:${crateName}`;
724
+ }
716
725
  async function syncCommand(state, opts) {
717
726
  if (opts.packages && opts.packages.length > 0) {
718
- if (opts.packages.length > 1) return syncPackagesParallel({
719
- 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,
720
731
  global: opts.global,
721
732
  agent: opts.agent,
722
733
  model: opts.model,
@@ -725,7 +736,8 @@ async function syncCommand(state, opts) {
725
736
  debug: opts.debug,
726
737
  mode: opts.mode
727
738
  });
728
- 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);
729
741
  return;
730
742
  }
731
743
  const packages = await interactivePicker(state);
@@ -802,64 +814,79 @@ async function pickFromList(packages, state) {
802
814
  return selected;
803
815
  }
804
816
  async function syncSinglePackage(packageSpec, config) {
805
- 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);
806
827
  const spin = timedSpinner();
807
828
  spin.start(`Resolving ${packageSpec}`);
808
829
  const cwd = process.cwd();
809
- const localVersion = (await readLocalDependencies(cwd).catch(() => [])).find((d) => d.name === packageName)?.version;
810
- 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, {
811
836
  version: localVersion,
812
837
  cwd,
813
838
  onProgress: (step) => spin.message(`${packageName}: ${RESOLVE_STEP_LABELS[step]}`)
814
839
  });
815
840
  let resolved = resolveResult.package;
816
- if (!resolved) {
841
+ if (!resolved && !isCrate) {
817
842
  spin.message(`Resolving local package: ${packageName}`);
818
843
  resolved = await resolveLocalDep(packageName, cwd);
819
844
  }
820
845
  if (!resolved) {
821
- const earlyShipped = handleShippedSkills(packageName, localVersion || resolveResult.registryVersion || "latest", cwd, config.agent, config.global);
822
- if (earlyShipped) {
823
- const shared = !config.global && getSharedSkillsDir(cwd);
824
- for (const shipped of earlyShipped.shipped) {
825
- if (shared) linkSkillToAgents(shipped.skillName, shared, cwd, config.agent);
826
- 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;
827
875
  }
828
- spin.stop(`Using published SKILL.md(s) from ${packageName}`);
829
- return;
830
- }
831
- spin.message(`Searching npm for "${packageName}"...`);
832
- const suggestions = await searchNpmPackages(packageName);
833
- if (suggestions.length > 0) {
834
- spin.stop(`Package "${packageName}" not found on npm`);
835
- showResolveAttempts(resolveResult.attempts);
836
- const selected = await p.select({
837
- message: "Did you mean one of these?",
838
- options: [...suggestions.map((s) => ({
839
- label: s.name,
840
- value: s.name,
841
- hint: s.description
842
- })), {
843
- label: "None of these",
844
- value: "_none_"
845
- }]
846
- });
847
- if (!p.isCancel(selected) && selected !== "_none_") return syncSinglePackage(selected, config);
848
- return;
849
876
  }
850
- spin.stop(`Could not find docs for: ${packageName}`);
877
+ spin.stop(`Could not find docs for: ${identityPackageName}`);
851
878
  showResolveAttempts(resolveResult.attempts);
852
879
  return;
853
880
  }
854
- const version = localVersion || resolved.version || "latest";
881
+ const version = isCrate ? resolved.version || requestedTag || "latest" : localVersion || resolved.version || "latest";
855
882
  const versionKey = getVersionKey(version);
856
- if (config.force) forceClearCache(packageName, version);
857
- const useCache = isCached(packageName, version);
858
- 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))) {
859
886
  spin.message(`Downloading ${packageName}@${version} dist`);
860
887
  await fetchPkgDist(packageName, version);
861
888
  }
862
- const shippedResult = handleShippedSkills(packageName, version, cwd, config.agent, config.global);
889
+ const shippedResult = isCrate ? null : handleShippedSkills(packageName, version, cwd, config.agent, config.global);
863
890
  if (shippedResult) {
864
891
  const shared = !config.global && getSharedSkillsDir(cwd);
865
892
  for (const shipped of shippedResult.shipped) {
@@ -869,18 +896,18 @@ async function syncSinglePackage(packageSpec, config) {
869
896
  spin.stop(`Using published SKILL.md(s) from ${packageName}`);
870
897
  return;
871
898
  }
872
- spin.stop(`Resolved ${packageName}@${useCache ? versionKey : version}${config.force ? " (force)" : useCache ? " (cached)" : ""}`);
873
- 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)) {
874
901
  const nextTag = resolved.distTags?.next ?? resolved.distTags?.beta ?? resolved.distTags?.alpha;
875
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`);
876
903
  }
877
904
  ensureCacheDir();
878
905
  const baseDir = resolveBaseDir(cwd, config.agent, config.global);
879
- let skillDirName = config.name ? sanitizeName(config.name) : computeSkillDirName(packageName);
906
+ let skillDirName = config.name ? sanitizeName(config.name) : computeSkillDirName(storagePackageName);
880
907
  if (config.mode === "update" && !config.name) {
881
908
  const lock = readLock(baseDir);
882
909
  if (lock) {
883
- 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)) {
884
911
  skillDirName = name;
885
912
  break;
886
913
  }
@@ -889,7 +916,7 @@ async function syncSinglePackage(packageSpec, config) {
889
916
  const skillDir = config.eject ? typeof config.eject === "string" ? join(resolve(cwd, config.eject), skillDirName) : join(cwd, "skills", skillDirName) : join(baseDir, skillDirName);
890
917
  mkdirSync(skillDir, { recursive: true });
891
918
  const existingLock = config.eject ? void 0 : readLock(baseDir)?.skills[skillDirName];
892
- const isMerge = existingLock && existingLock.packageName && existingLock.packageName !== packageName;
919
+ const isMerge = existingLock && existingLock.packageName && existingLock.packageName !== identityPackageName;
893
920
  const updateCtx = config.mode === "update" && existingLock ? {
894
921
  oldVersion: existingLock.version,
895
922
  newVersion: version,
@@ -901,11 +928,11 @@ async function syncSinglePackage(packageSpec, config) {
901
928
  })()
902
929
  } : void 0;
903
930
  if (isMerge) {
904
- spin.stop(`Merging ${packageName} into ${skillDirName}`);
905
- linkPkgNamed(skillDir, packageName, cwd, version);
931
+ spin.stop(`Merging ${identityPackageName} into ${skillDirName}`);
932
+ linkPkgNamed(skillDir, storagePackageName, cwd, version);
906
933
  const repoSlug = resolved.repoUrl?.match(/github\.com\/([^/]+\/[^/]+?)(?:\.git)?(?:[/#]|$)/)?.[1];
907
934
  writeLock(baseDir, skillDirName, {
908
- packageName,
935
+ packageName: identityPackageName,
909
936
  version,
910
937
  repo: repoSlug,
911
938
  source: existingLock.source,
@@ -914,9 +941,10 @@ async function syncSinglePackage(packageSpec, config) {
914
941
  });
915
942
  const updatedLock = readLock(baseDir)?.skills[skillDirName];
916
943
  const allPackages = parsePackages(updatedLock?.packages).map((p) => ({ name: p.name }));
917
- const relatedSkills = await findRelatedSkills(packageName, baseDir);
918
- const pkgFiles = getPkgKeyFiles(existingLock.packageName, cwd, existingLock.version);
919
- 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);
920
948
  const mergeFeatures = readConfig().features ?? defaultFeatures;
921
949
  const skillMd = generateSkillMd({
922
950
  name: existingLock.packageName,
@@ -936,7 +964,7 @@ async function syncSinglePackage(packageSpec, config) {
936
964
  const mergeShared = !config.global && getSharedSkillsDir(cwd);
937
965
  if (mergeShared) linkSkillToAgents(skillDirName, mergeShared, cwd, config.agent);
938
966
  if (!config.global) registerProject(cwd);
939
- p.outro(`Merged ${packageName} into ${skillDirName}`);
967
+ p.outro(`Merged ${identityPackageName} into ${skillDirName}`);
940
968
  return;
941
969
  }
942
970
  const features = { ...readConfig().features ?? defaultFeatures };
@@ -944,7 +972,7 @@ async function syncSinglePackage(packageSpec, config) {
944
972
  const resSpin = timedSpinner();
945
973
  resSpin.start("Finding resources");
946
974
  const resources = await fetchAndCacheResources({
947
- packageName,
975
+ packageName: storagePackageName,
948
976
  resolved,
949
977
  version,
950
978
  useCache,
@@ -962,12 +990,12 @@ async function syncSinglePackage(packageSpec, config) {
962
990
  if (resources.hasReleases) resParts.push("releases");
963
991
  resSpin.stop(resources.usedCache ? `Loaded ${resParts.length > 0 ? resParts.join(", ") : "resources"} (cached)` : `Fetched ${resParts.length > 0 ? resParts.join(", ") : "resources"}`);
964
992
  for (const w of resources.warnings) p.log.warn(`\x1B[33m${w}\x1B[0m`);
965
- 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);
966
994
  if (features.search) {
967
995
  const idxSpin = timedSpinner();
968
996
  idxSpin.start("Creating search index");
969
997
  await indexResources({
970
- packageName,
998
+ packageName: storagePackageName,
971
999
  version,
972
1000
  cwd,
973
1001
  docsToIndex: resources.docsToIndex,
@@ -976,15 +1004,15 @@ async function syncSinglePackage(packageSpec, config) {
976
1004
  });
977
1005
  idxSpin.stop("Search index ready");
978
1006
  }
979
- const hasChangelog = detectChangelog(resolvePkgDir(packageName, cwd, version), getCacheDir(packageName, version));
980
- const relatedSkills = await findRelatedSkills(packageName, baseDir);
981
- const shippedDocs = hasShippedDocs(packageName, cwd, version);
982
- 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);
983
1011
  const repoSlug = resolved.repoUrl?.match(/github\.com\/([^/]+\/[^/]+?)(?:\.git)?(?:[/#]|$)/)?.[1];
984
- if (!config.eject) linkPkgNamed(skillDir, packageName, cwd, version);
1012
+ if (!config.eject) linkPkgNamed(skillDir, storagePackageName, cwd, version);
985
1013
  if (!config.eject) {
986
1014
  writeLock(baseDir, skillDirName, {
987
- packageName,
1015
+ packageName: identityPackageName,
988
1016
  version,
989
1017
  repo: repoSlug,
990
1018
  source: resources.docSource,
@@ -994,7 +1022,7 @@ async function syncSinglePackage(packageSpec, config) {
994
1022
  const lock = readLock(baseDir);
995
1023
  if (lock) for (const [name, info] of Object.entries(lock.skills)) {
996
1024
  if (name === skillDirName) continue;
997
- 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)) {
998
1026
  removeLockEntry(baseDir, name);
999
1027
  const staleDir = join(baseDir, name);
1000
1028
  if (existsSync(staleDir)) rmSync(staleDir, { recursive: true });
@@ -1004,7 +1032,7 @@ async function syncSinglePackage(packageSpec, config) {
1004
1032
  const allPackages = parsePackages((config.eject ? void 0 : readLock(baseDir)?.skills[skillDirName])?.packages).map((p) => ({ name: p.name }));
1005
1033
  const isEject = !!config.eject;
1006
1034
  const baseSkillMd = generateSkillMd({
1007
- name: packageName,
1035
+ name: identityPackageName,
1008
1036
  version,
1009
1037
  releasedAt: resolved.releasedAt,
1010
1038
  description: resolved.description,
@@ -1028,19 +1056,19 @@ async function syncSinglePackage(packageSpec, config) {
1028
1056
  p.log.success(config.mode === "update" ? `Updated skill: ${relative(cwd, skillDir)}` : `Created base skill: ${relative(cwd, skillDir)}`);
1029
1057
  const allSectionsCached = !config.force && DEFAULT_SECTIONS.every((s) => {
1030
1058
  const outputFile = SECTION_OUTPUT_FILES[s];
1031
- return readCachedSection(packageName, version, outputFile) !== null;
1059
+ return readCachedSection(storagePackageName, version, outputFile) !== null;
1032
1060
  });
1033
1061
  if (allSectionsCached) {
1034
1062
  const cachedParts = [];
1035
1063
  for (const s of SECTION_MERGE_ORDER) {
1036
1064
  if (!DEFAULT_SECTIONS.includes(s)) continue;
1037
1065
  const outputFile = SECTION_OUTPUT_FILES[s];
1038
- const content = readCachedSection(packageName, version, outputFile);
1066
+ const content = readCachedSection(storagePackageName, version, outputFile);
1039
1067
  if (content) cachedParts.push(wrapSection(s, content));
1040
1068
  }
1041
1069
  const cachedBody = cachedParts.join("\n\n");
1042
1070
  const skillMd = generateSkillMd({
1043
- name: packageName,
1071
+ name: identityPackageName,
1044
1072
  version,
1045
1073
  releasedAt: resolved.releasedAt,
1046
1074
  description: resolved.description,
@@ -1074,7 +1102,7 @@ async function syncSinglePackage(packageSpec, config) {
1074
1102
  if (!allSectionsCached && !globalConfig.skipLlm && !(config.yes && !resolvedModel)) {
1075
1103
  const llmConfig = await selectLlmConfig(resolvedModel, void 0, updateCtx);
1076
1104
  if (llmConfig?.promptOnly) writePromptFiles({
1077
- packageName,
1105
+ packageName: storagePackageName,
1078
1106
  skillDir,
1079
1107
  version,
1080
1108
  hasIssues: resources.hasIssues,
@@ -1092,7 +1120,8 @@ async function syncSinglePackage(packageSpec, config) {
1092
1120
  else if (llmConfig) {
1093
1121
  p.log.step(getModelLabel(llmConfig.model));
1094
1122
  await enhanceSkillWithLLM({
1095
- packageName,
1123
+ packageName: identityPackageName,
1124
+ cachePackageName: storagePackageName,
1096
1125
  version,
1097
1126
  skillDir,
1098
1127
  dirName: skillDirName,
@@ -1123,7 +1152,7 @@ async function syncSinglePackage(packageSpec, config) {
1123
1152
  recursive: true,
1124
1153
  force: true
1125
1154
  });
1126
- ejectReferences(skillDir, packageName, cwd, version, resources.docsType, features, resources.repoInfo);
1155
+ ejectReferences(skillDir, storagePackageName, cwd, version, resources.docsType, features, resources.repoInfo);
1127
1156
  }
1128
1157
  if (!isEject) {
1129
1158
  const shared = !config.global && getSharedSkillsDir(cwd);
@@ -1135,7 +1164,7 @@ async function syncSinglePackage(packageSpec, config) {
1135
1164
  await shutdownWorker();
1136
1165
  const ejectMsg = isEject ? " (ejected)" : "";
1137
1166
  const relDir = relative(cwd, skillDir);
1138
- 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}`);
1139
1168
  try {
1140
1169
  await suggestPrepareHook(cwd);
1141
1170
  } catch (err) {
@@ -1145,12 +1174,12 @@ async function syncSinglePackage(packageSpec, config) {
1145
1174
  const addCommandDef = defineCommand({
1146
1175
  meta: {
1147
1176
  name: "add",
1148
- description: "Add skills for package(s)"
1177
+ description: "Install skills (npm:<pkg>, crate:<name>, gh:<owner/repo>, @<curator>)"
1149
1178
  },
1150
1179
  args: {
1151
1180
  package: {
1152
1181
  type: "positional",
1153
- 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)",
1154
1183
  required: true
1155
1184
  },
1156
1185
  skill: {
@@ -1178,12 +1207,43 @@ const addCommandDef = defineCommand({
1178
1207
  return;
1179
1208
  }
1180
1209
  if (!hasCompletedWizard()) await runWizard({ agent });
1210
+ const parsedSources = rawInputs.map(parseSkillInput);
1181
1211
  const gitSources = [];
1182
- const npmTokens = [];
1183
- for (const input of rawInputs) {
1184
- const git = parseGitSkillInput(input);
1185
- if (git) gitSources.push(git);
1186
- 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;
1187
1247
  }
1188
1248
  if (gitSources.length > 0) for (const source of gitSources) {
1189
1249
  const skillFilter = args.skill ? args.skill.split(/[,\s]+/).map((s) => s.trim()).filter(Boolean) : void 0;
@@ -1198,15 +1258,50 @@ const addCommandDef = defineCommand({
1198
1258
  skillFilter
1199
1259
  });
1200
1260
  }
1201
- if (npmTokens.length > 0) {
1202
- 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) {
1203
1298
  const state = await getProjectState(cwd);
1204
1299
  p.intro(introLine({
1205
1300
  state,
1206
1301
  agentId: agent || void 0
1207
1302
  }));
1208
- return syncCommand(state, {
1209
- packages,
1303
+ await syncCommand(state, {
1304
+ packages: crateSpecs,
1210
1305
  global: args.global,
1211
1306
  agent,
1212
1307
  model: args.model,
@@ -1318,7 +1413,7 @@ const updateCommandDef = defineCommand({
1318
1413
  }
1319
1414
  if (agent === "none") {
1320
1415
  const state = await getProjectState(cwd);
1321
- 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);
1322
1417
  if (packages.length === 0) {
1323
1418
  if (!silent) p.log.success("All skills up to date");
1324
1419
  return;
@@ -1340,22 +1435,36 @@ const updateCommandDef = defineCommand({
1340
1435
  agentId: config.agent || agent || void 0
1341
1436
  }));
1342
1437
  }
1343
- if (args.package) return syncCommand(state, {
1344
- packages: [...new Set([args.package, ...args._ || []].flatMap((s) => s.split(/[,\s]+/)).map((s) => s.trim()).filter(Boolean))],
1345
- global: args.global,
1346
- agent,
1347
- model: args.model || (silent ? config.model : void 0),
1348
- yes: args.yes || silent,
1349
- force: args.force,
1350
- debug: args.debug,
1351
- mode: "update"
1352
- });
1353
- 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) {
1354
1463
  p.log.success("All skills up to date");
1355
1464
  return;
1356
1465
  }
1357
1466
  return syncCommand(state, {
1358
- packages: state.outdated.map((s) => s.packageName || s.name),
1467
+ packages: [...state.outdated.map((s) => s.packageName || s.name), ...crateSpecs],
1359
1468
  global: args.global,
1360
1469
  agent,
1361
1470
  model: args.model || (silent ? config.model : void 0),
@@ -1490,6 +1599,6 @@ async function exportPortablePrompts(packageSpec, opts) {
1490
1599
  const outputFileList = sectionList.map((s) => SECTION_OUTPUT_FILES[s]).join(", ");
1491
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`);
1492
1601
  }
1493
- 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 };
1494
1603
 
1495
1604
  //# sourceMappingURL=sync.mjs.map