skilld 1.7.3 → 1.7.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 (96) hide show
  1. package/dist/_chunks/agent.mjs +693 -599
  2. package/dist/_chunks/agent.mjs.map +1 -1
  3. package/dist/_chunks/assemble.mjs +3 -3
  4. package/dist/_chunks/author.mjs +51 -121
  5. package/dist/_chunks/author.mjs.map +1 -1
  6. package/dist/_chunks/cache.mjs +315 -9
  7. package/dist/_chunks/cache.mjs.map +1 -1
  8. package/dist/_chunks/cache2.mjs +2 -2
  9. package/dist/_chunks/cli-helpers.mjs +3 -3
  10. package/dist/_chunks/core.mjs +7 -4
  11. package/dist/_chunks/detect.mjs +1 -1
  12. package/dist/_chunks/embedding-cache2.mjs +2 -2
  13. package/dist/_chunks/index.d.mts +305 -112
  14. package/dist/_chunks/index.d.mts.map +1 -1
  15. package/dist/_chunks/index2.d.mts +267 -32
  16. package/dist/_chunks/index2.d.mts.map +1 -1
  17. package/dist/_chunks/index3.d.mts +32 -577
  18. package/dist/_chunks/index3.d.mts.map +1 -1
  19. package/dist/_chunks/index4.d.mts +553 -0
  20. package/dist/_chunks/index4.d.mts.map +1 -0
  21. package/dist/_chunks/install.mjs +48 -88
  22. package/dist/_chunks/install.mjs.map +1 -1
  23. package/dist/_chunks/list.mjs +1 -1
  24. package/dist/_chunks/lockfile.mjs +29 -6
  25. package/dist/_chunks/lockfile.mjs.map +1 -1
  26. package/dist/_chunks/monorepo.mjs +71 -0
  27. package/dist/_chunks/monorepo.mjs.map +1 -0
  28. package/dist/_chunks/{shared.mjs → package-registry.mjs} +2 -40
  29. package/dist/_chunks/package-registry.mjs.map +1 -0
  30. package/dist/_chunks/paths.mjs +49 -0
  31. package/dist/_chunks/paths.mjs.map +1 -0
  32. package/dist/_chunks/pool2.mjs +1 -1
  33. package/dist/_chunks/prepare.mjs +1 -1
  34. package/dist/_chunks/prepare2.mjs +5 -5
  35. package/dist/_chunks/prepare2.mjs.map +1 -1
  36. package/dist/_chunks/prompts.mjs +366 -18
  37. package/dist/_chunks/prompts.mjs.map +1 -1
  38. package/dist/_chunks/search-helpers.mjs +5 -6
  39. package/dist/_chunks/search-helpers.mjs.map +1 -1
  40. package/dist/_chunks/search-interactive.mjs +1 -1
  41. package/dist/_chunks/search.mjs +1 -2
  42. package/dist/_chunks/search.mjs.map +1 -1
  43. package/dist/_chunks/semver.mjs +13 -0
  44. package/dist/_chunks/semver.mjs.map +1 -0
  45. package/dist/_chunks/skill-installer.mjs +2 -0
  46. package/dist/_chunks/skill-installer2.mjs +155 -0
  47. package/dist/_chunks/skill-installer2.mjs.map +1 -0
  48. package/dist/_chunks/skills.mjs +10 -9
  49. package/dist/_chunks/skills.mjs.map +1 -1
  50. package/dist/_chunks/sources.mjs +549 -372
  51. package/dist/_chunks/sources.mjs.map +1 -1
  52. package/dist/_chunks/sync-pipeline.mjs +952 -0
  53. package/dist/_chunks/sync-pipeline.mjs.map +1 -0
  54. package/dist/_chunks/sync-registry.mjs +19 -13
  55. package/dist/_chunks/sync-registry.mjs.map +1 -1
  56. package/dist/_chunks/sync.mjs +797 -886
  57. package/dist/_chunks/sync.mjs.map +1 -1
  58. package/dist/_chunks/sync2.mjs +4 -2
  59. package/dist/_chunks/types.d.mts +65 -77
  60. package/dist/_chunks/types.d.mts.map +1 -1
  61. package/dist/_chunks/types2.d.mts +88 -0
  62. package/dist/_chunks/types2.d.mts.map +1 -0
  63. package/dist/_chunks/uninstall.mjs +7 -8
  64. package/dist/_chunks/uninstall.mjs.map +1 -1
  65. package/dist/_chunks/upload.mjs +2 -2
  66. package/dist/_chunks/validate.mjs +1 -1
  67. package/dist/_chunks/version.mjs +3 -13
  68. package/dist/_chunks/version.mjs.map +1 -1
  69. package/dist/_chunks/wizard.mjs +2 -2
  70. package/dist/agent/index.d.mts +2 -346
  71. package/dist/agent/index.mjs +2 -3
  72. package/dist/cache/index.d.mts +2 -2
  73. package/dist/cache/index.mjs +4 -3
  74. package/dist/cli.mjs +12 -13
  75. package/dist/cli.mjs.map +1 -1
  76. package/dist/index.d.mts +5 -4
  77. package/dist/index.mjs +4 -3
  78. package/dist/prepare.mjs +2 -2
  79. package/dist/prepare.mjs.map +1 -1
  80. package/dist/retriv/index.d.mts +2 -2
  81. package/dist/retriv/worker.d.mts +1 -1
  82. package/dist/sources/index.d.mts +3 -2
  83. package/dist/sources/index.mjs +3 -3
  84. package/dist/types.d.mts +3 -3
  85. package/package.json +2 -2
  86. package/dist/_chunks/config.mjs +0 -122
  87. package/dist/_chunks/config.mjs.map +0 -1
  88. package/dist/_chunks/prefix.mjs +0 -108
  89. package/dist/_chunks/prefix.mjs.map +0 -1
  90. package/dist/_chunks/shared.mjs.map +0 -1
  91. package/dist/_chunks/skill.mjs +0 -329
  92. package/dist/_chunks/skill.mjs.map +0 -1
  93. package/dist/_chunks/sync-shared.mjs +0 -2
  94. package/dist/_chunks/sync-shared2.mjs +0 -1020
  95. package/dist/_chunks/sync-shared2.mjs.map +0 -1
  96. package/dist/agent/index.d.mts.map +0 -1
@@ -1,11 +1,11 @@
1
- import { t as getCacheDir } from "./version.mjs";
2
- import { i as readPackageJsonSafe } from "./package-json.mjs";
3
1
  import { t as yamlEscape } from "./yaml.mjs";
2
+ import { i as readPackageJsonSafe } from "./package-json.mjs";
3
+ import { t as getCacheDir } from "./version.mjs";
4
4
  import { i as parseFrontmatter, n as extractLinks, r as extractTitle, t as extractDescription } from "./markdown.mjs";
5
- import { c as getBlogPreset, l as getCrawlUrl, r as mapInsert, u as getDocOverride } from "./shared.mjs";
5
+ import { n as getCrawlUrl, r as getDocOverride, t as getBlogPreset } from "./package-registry.mjs";
6
+ import { createWriteStream, existsSync, mkdirSync, readFileSync, readdirSync, rmSync } from "node:fs";
6
7
  import { tmpdir } from "node:os";
7
8
  import { basename, dirname, join, resolve } from "pathe";
8
- import { createWriteStream, existsSync, mkdirSync, readFileSync, readdirSync, rmSync } from "node:fs";
9
9
  import { htmlToMarkdown } from "mdream";
10
10
  import pLimit from "p-limit";
11
11
  import { spawnSync } from "node:child_process";
@@ -79,6 +79,15 @@ function markRepoPrivate(owner, repo) {
79
79
  function isKnownPrivateRepo(owner, repo) {
80
80
  return _needsAuth.has(`${owner}/${repo}`);
81
81
  }
82
+ async function fetchUnghOrApi(owner, repo, ungh, api) {
83
+ if (!isKnownPrivateRepo(owner, repo)) {
84
+ const r = await ungh().catch(() => null);
85
+ if (r) return r;
86
+ }
87
+ const r = await api();
88
+ if (r) markRepoPrivate(owner, repo);
89
+ return r;
90
+ }
82
91
  const GH_API = "https://api.github.com";
83
92
  const ghApiFetch = ofetch.create({
84
93
  retry: 2,
@@ -499,6 +508,261 @@ async function fetchBlogReleases(packageName, installedVersion) {
499
508
  content: formatBlogRelease(r)
500
509
  }));
501
510
  }
511
+ function mapInsert(map, key, create) {
512
+ let val = map.get(key);
513
+ if (val === void 0) {
514
+ val = create();
515
+ map.set(key, val);
516
+ }
517
+ return val;
518
+ }
519
+ async function listFilesAtRef(owner, repo, ref) {
520
+ return await fetchUnghOrApi(owner, repo, async () => {
521
+ const data = await $fetch(`https://ungh.cc/repos/${owner}/${repo}/files/${ref}`);
522
+ return data.files?.length ? data.files.map((f) => f.path) : null;
523
+ }, async () => {
524
+ const tree = await ghApi(`repos/${owner}/${repo}/git/trees/${ref}?recursive=1`);
525
+ return tree?.tree?.length ? tree.tree.map((f) => f.path) : null;
526
+ }) ?? [];
527
+ }
528
+ async function findGitTag(owner, repo, version, packageName, branchHint) {
529
+ const candidates = [`v${version}`, version];
530
+ if (packageName) candidates.push(`${packageName}@${version}`);
531
+ for (const tag of candidates) {
532
+ const files = await listFilesAtRef(owner, repo, tag);
533
+ if (files.length > 0) return {
534
+ ref: tag,
535
+ files
536
+ };
537
+ }
538
+ if (packageName) {
539
+ const latestTag = await findLatestReleaseTag(owner, repo, packageName);
540
+ if (latestTag) {
541
+ const files = await listFilesAtRef(owner, repo, latestTag);
542
+ if (files.length > 0) return {
543
+ ref: latestTag,
544
+ files
545
+ };
546
+ }
547
+ }
548
+ const branches = branchHint ? [branchHint, ...["main", "master"].filter((b) => b !== branchHint)] : ["main", "master"];
549
+ for (const branch of branches) {
550
+ const files = await listFilesAtRef(owner, repo, branch);
551
+ if (files.length > 0) return {
552
+ ref: branch,
553
+ files,
554
+ fallback: true
555
+ };
556
+ }
557
+ return null;
558
+ }
559
+ async function fetchUnghReleases(owner, repo) {
560
+ return await fetchUnghOrApi(owner, repo, async () => {
561
+ const data = await $fetch(`https://ungh.cc/repos/${owner}/${repo}/releases`);
562
+ return data.releases?.length ? data.releases : null;
563
+ }, async () => {
564
+ const raw = await ghApiPaginated(`repos/${owner}/${repo}/releases`);
565
+ return raw.length > 0 ? raw.map((r) => ({
566
+ tag: r.tag_name,
567
+ publishedAt: r.published_at
568
+ })) : null;
569
+ }) ?? [];
570
+ }
571
+ async function findLatestReleaseTag(owner, repo, packageName) {
572
+ const prefix = `${packageName}@`;
573
+ return (await fetchUnghReleases(owner, repo)).find((r) => r.tag.startsWith(prefix))?.tag ?? null;
574
+ }
575
+ const MIN_GIT_DOCS = 5;
576
+ const isShallowGitDocs = (n) => n > 0 && n < 5;
577
+ function filterDocFiles(files, pathPrefix) {
578
+ return files.filter((f) => f.startsWith(pathPrefix) && /\.(?:md|mdx)$/.test(f));
579
+ }
580
+ const FRAMEWORK_NAMES = new Set([
581
+ "vue",
582
+ "react",
583
+ "solid",
584
+ "angular",
585
+ "svelte",
586
+ "preact",
587
+ "lit",
588
+ "qwik"
589
+ ]);
590
+ function filterFrameworkDocs(files, packageName) {
591
+ if (!packageName) return files;
592
+ const shortName = packageName.replace(/^@.*\//, "");
593
+ const targetFramework = [...FRAMEWORK_NAMES].find((fw) => shortName.includes(fw));
594
+ if (!targetFramework) return files;
595
+ const otherFrameworks = [...FRAMEWORK_NAMES].filter((fw) => fw !== targetFramework);
596
+ const excludePattern = new RegExp(`\\b(?:${otherFrameworks.join("|")})\\b`);
597
+ return files.filter((f) => !excludePattern.test(f));
598
+ }
599
+ const NOISE_PATTERNS = [
600
+ /^\.changeset\//,
601
+ /CHANGELOG\.md$/i,
602
+ /CONTRIBUTING\.md$/i,
603
+ /^\.github\//
604
+ ];
605
+ const EXCLUDE_DIRS = new Set([
606
+ "test",
607
+ "tests",
608
+ "__tests__",
609
+ "fixtures",
610
+ "fixture",
611
+ "examples",
612
+ "example",
613
+ "node_modules",
614
+ ".git",
615
+ "dist",
616
+ "build",
617
+ "coverage",
618
+ "e2e",
619
+ "spec",
620
+ "mocks",
621
+ "__mocks__"
622
+ ]);
623
+ const DOC_DIR_BONUS = new Set([
624
+ "docs",
625
+ "documentation",
626
+ "pages",
627
+ "content",
628
+ "website",
629
+ "guide",
630
+ "guides",
631
+ "wiki",
632
+ "manual",
633
+ "api"
634
+ ]);
635
+ function hasExcludedDir(path) {
636
+ return path.split("/").some((p) => EXCLUDE_DIRS.has(p.toLowerCase()));
637
+ }
638
+ function getPathDepth(path) {
639
+ return path.split("/").filter(Boolean).length;
640
+ }
641
+ function hasDocDirBonus(path) {
642
+ return path.split("/").some((p) => DOC_DIR_BONUS.has(p.toLowerCase()));
643
+ }
644
+ function scoreDocDir(dir, fileCount) {
645
+ const depth = getPathDepth(dir) || 1;
646
+ return fileCount * (hasDocDirBonus(dir) ? 1.5 : 1) / depth;
647
+ }
648
+ function discoverDocFiles(allFiles, packageName) {
649
+ const mdFiles = allFiles.filter((f) => /\.(?:md|mdx)$/.test(f)).filter((f) => !NOISE_PATTERNS.some((p) => p.test(f))).filter((f) => f.includes("/"));
650
+ if (packageName?.includes("/")) {
651
+ const subPkgPrefix = `packages/${packageName.split("/").pop().toLowerCase()}/`;
652
+ const subPkgFiles = mdFiles.filter((f) => f.startsWith(subPkgPrefix));
653
+ if (subPkgFiles.length >= 3) return {
654
+ files: subPkgFiles,
655
+ prefix: subPkgPrefix
656
+ };
657
+ }
658
+ const docsGroups = /* @__PURE__ */ new Map();
659
+ for (const file of mdFiles) {
660
+ const docsIdx = file.lastIndexOf("/docs/");
661
+ if (docsIdx === -1) continue;
662
+ mapInsert(docsGroups, file.slice(0, docsIdx + 6), () => []).push(file);
663
+ }
664
+ if (docsGroups.size > 0) {
665
+ const largest = [...docsGroups.entries()].sort((a, b) => b[1].length - a[1].length)[0];
666
+ if (largest[1].length >= 3) {
667
+ const fullPrefix = largest[0];
668
+ const docsIdx = fullPrefix.lastIndexOf("docs/");
669
+ const stripPrefix = docsIdx > 0 ? fullPrefix.slice(0, docsIdx) : "";
670
+ return {
671
+ files: largest[1],
672
+ prefix: stripPrefix
673
+ };
674
+ }
675
+ }
676
+ const dirGroups = /* @__PURE__ */ new Map();
677
+ for (const file of mdFiles) {
678
+ if (hasExcludedDir(file)) continue;
679
+ const lastSlash = file.lastIndexOf("/");
680
+ if (lastSlash === -1) continue;
681
+ mapInsert(dirGroups, file.slice(0, lastSlash + 1), () => []).push(file);
682
+ }
683
+ if (dirGroups.size === 0) return null;
684
+ const scored = Array.from(dirGroups.entries(), ([dir, files]) => ({
685
+ dir,
686
+ files,
687
+ score: scoreDocDir(dir, files.length)
688
+ })).filter((d) => d.files.length >= 5).sort((a, b) => b.score - a.score);
689
+ if (scored.length === 0) return null;
690
+ const best = scored[0];
691
+ return {
692
+ files: best.files,
693
+ prefix: best.dir
694
+ };
695
+ }
696
+ async function listDocsAtRef(owner, repo, ref, pathPrefix = "docs/") {
697
+ return filterDocFiles(await listFilesAtRef(owner, repo, ref), pathPrefix);
698
+ }
699
+ async function fetchGitDocs(owner, repo, version, packageName, repoUrl) {
700
+ const override = packageName ? getDocOverride(packageName) : void 0;
701
+ if (override) {
702
+ const ref = override.ref || "main";
703
+ const fallback = !override.ref;
704
+ const files = await listDocsAtRef(override.owner, override.repo, ref, `${override.path}/`);
705
+ if (files.length === 0) return null;
706
+ return {
707
+ baseUrl: `https://raw.githubusercontent.com/${override.owner}/${override.repo}/${ref}`,
708
+ ref,
709
+ files,
710
+ fallback,
711
+ docsPrefix: `${override.path}/` !== "docs/" ? `${override.path}/` : void 0
712
+ };
713
+ }
714
+ const tag = await findGitTag(owner, repo, version, packageName, repoUrl ? extractBranchHint(repoUrl) : void 0);
715
+ if (!tag) return null;
716
+ let docs = filterDocFiles(tag.files, "docs/");
717
+ let docsPrefix;
718
+ let allFiles;
719
+ if (docs.length === 0) {
720
+ const discovered = discoverDocFiles(tag.files, packageName);
721
+ if (discovered) {
722
+ docs = discovered.files;
723
+ docsPrefix = discovered.prefix || void 0;
724
+ allFiles = tag.files;
725
+ }
726
+ }
727
+ docs = filterFrameworkDocs(docs, packageName);
728
+ if (docs.length === 0) return null;
729
+ return {
730
+ baseUrl: `https://raw.githubusercontent.com/${owner}/${repo}/${tag.ref}`,
731
+ ref: tag.ref,
732
+ files: docs,
733
+ docsPrefix,
734
+ allFiles,
735
+ fallback: tag.fallback
736
+ };
737
+ }
738
+ function normalizePath(p) {
739
+ return p.replace(/^\//, "").replace(/\.(?:md|mdx)$/, "");
740
+ }
741
+ function validateGitDocsWithLlms(llmsLinks, repoFiles) {
742
+ if (llmsLinks.length === 0) return {
743
+ isValid: true,
744
+ matchRatio: 1
745
+ };
746
+ const sample = llmsLinks.slice(0, 10);
747
+ const normalizedLinks = sample.map((link) => {
748
+ let path = link.url;
749
+ if (path.startsWith("http")) try {
750
+ path = new URL(path).pathname;
751
+ } catch {}
752
+ return normalizePath(path);
753
+ });
754
+ const repoNormalized = new Set(repoFiles.map(normalizePath));
755
+ let matches = 0;
756
+ for (const linkPath of normalizedLinks) for (const repoPath of repoNormalized) if (repoPath === linkPath || repoPath.endsWith(`/${linkPath}`)) {
757
+ matches++;
758
+ break;
759
+ }
760
+ const matchRatio = matches / sample.length;
761
+ return {
762
+ isValid: matchRatio >= .3,
763
+ matchRatio
764
+ };
765
+ }
502
766
  let _ghAvailable;
503
767
  function isGhAvailable() {
504
768
  if (_ghAvailable !== void 0) return _ghAvailable;
@@ -762,385 +1026,132 @@ function formatIssueAsMarkdown(issue) {
762
1026
  `# ${issue.title}`
763
1027
  ];
764
1028
  if (issue.body) {
765
- const body = truncateBody(issue.body, limit);
766
- lines.push("", body);
767
- }
768
- if (issue.topComments.length > 0) {
769
- lines.push("", "---", "", "## Top Comments");
770
- for (const c of issue.topComments) {
771
- const reactions = c.reactions > 0 ? ` (+${c.reactions})` : "";
772
- const maintainer = c.isMaintainer ? " [maintainer]" : "";
773
- const commentBody = truncateBody(c.body, 600);
774
- lines.push("", `**@${c.author}**${maintainer}${reactions}:`, "", commentBody);
775
- }
776
- }
777
- return lines.join("\n");
778
- }
779
- function generateIssueIndex(issues) {
780
- const byType = /* @__PURE__ */ new Map();
781
- for (const issue of issues) mapInsert(byType, issue.type, () => []).push(issue);
782
- const typeLabels = {
783
- bug: "Bugs & Regressions",
784
- question: "Questions & Usage Help",
785
- docs: "Documentation",
786
- feature: "Feature Requests",
787
- other: "Other"
788
- };
789
- const typeOrder = [
790
- "bug",
791
- "question",
792
- "docs",
793
- "other",
794
- "feature"
795
- ];
796
- const sections = [
797
- [
798
- "---",
799
- `total: ${issues.length}`,
800
- `open: ${issues.filter((i) => i.state === "open").length}`,
801
- `closed: ${issues.filter((i) => i.state !== "open").length}`,
802
- "---"
803
- ].join("\n"),
804
- "",
805
- "# Issues Index",
806
- ""
807
- ];
808
- for (const type of typeOrder) {
809
- const group = byType.get(type);
810
- if (!group?.length) continue;
811
- sections.push(`## ${typeLabels[type]} (${group.length})`, "");
812
- for (const issue of group) {
813
- const reactions = issue.reactions > 0 ? ` (+${issue.reactions})` : "";
814
- const state = issue.state === "open" ? "" : " [closed]";
815
- const resolved = issue.resolvedIn ? ` [fixed in ${issue.resolvedIn}]` : "";
816
- const date = isoDate(issue.createdAt);
817
- sections.push(`- [#${issue.number}](./issue-${issue.number}.md): ${issue.title}${reactions}${state}${resolved} (${date})`);
818
- }
819
- sections.push("");
820
- }
821
- return sections.join("\n");
822
- }
823
- async function fetchLlmsUrl(docsUrl) {
824
- const llmsUrl = `${new URL(docsUrl).origin}/llms.txt`;
825
- if (await verifyUrl(llmsUrl)) return llmsUrl;
826
- return null;
827
- }
828
- async function fetchLlmsTxt(url) {
829
- const content = await fetchText(url);
830
- if (!content || content.length < 50) return null;
831
- return {
832
- raw: content,
833
- links: parseMarkdownLinks(content)
834
- };
835
- }
836
- function parseMarkdownLinks(content) {
837
- return extractLinks(content).filter((l) => l.url.endsWith(".md"));
838
- }
839
- function isSafeUrl(url) {
840
- try {
841
- const parsed = new URL(url);
842
- if (parsed.protocol !== "https:") return false;
843
- const host = parsed.hostname;
844
- if (host === "localhost" || host === "0.0.0.0" || host === "[::1]") return false;
845
- if (/^(?:127\.|10\.|172\.(?:1[6-9]|2\d|3[01])\.|192\.168\.|169\.254\.)/.test(host)) return false;
846
- if (/^\[(?:f[cd]|fe[89ab]|::ffff:)/i.test(host)) return false;
847
- return true;
848
- } catch {
849
- return false;
850
- }
851
- }
852
- async function downloadLlmsDocs(llmsContent, baseUrl, onProgress) {
853
- const limit = pLimit(5);
854
- let completed = 0;
855
- return (await Promise.all(llmsContent.links.map((link) => limit(async () => {
856
- const url = link.url.startsWith("http") ? link.url : `${baseUrl.replace(/\/$/, "")}${link.url.startsWith("/") ? "" : "/"}${link.url}`;
857
- if (!isSafeUrl(url)) return null;
858
- const content = await fetchText(url);
859
- onProgress?.(link.url, ++completed, llmsContent.links.length);
860
- if (content && content.length > 100) return {
861
- url: link.url.startsWith("http") ? new URL(link.url).pathname : link.url,
862
- title: link.title,
863
- content
864
- };
865
- return null;
866
- })))).filter((d) => d !== null);
867
- }
868
- function normalizeLlmsLinks(content, baseUrl) {
869
- let normalized = content;
870
- if (baseUrl) {
871
- const escaped = baseUrl.replace(/\/$/, "").replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
872
- normalized = normalized.replace(new RegExp(`\\]\\(${escaped}(/[^)]+\\.md)\\)`, "g"), "](./docs$1)");
873
- }
874
- normalized = normalized.replace(/\]\(\/([^)]+\.md)\)/g, "](./docs/$1)");
875
- return normalized;
876
- }
877
- function extractSections(content, patterns) {
878
- const sections = [];
879
- const parts = content.split(/\n---\n/);
880
- for (const part of parts) {
881
- const urlMatch = part.match(/^url: *(\S.*)$/m);
882
- if (!urlMatch) continue;
883
- const url = urlMatch[1];
884
- if (patterns.some((p) => url.includes(p))) {
885
- const contentStart = part.indexOf("\n", part.indexOf("url:"));
886
- if (contentStart > -1) sections.push(part.slice(contentStart + 1));
887
- }
888
- }
889
- if (sections.length === 0) return null;
890
- return sections.join("\n\n---\n\n");
891
- }
892
- const MIN_GIT_DOCS = 5;
893
- const isShallowGitDocs = (n) => n > 0 && n < 5;
894
- async function listFilesAtRef(owner, repo, ref) {
895
- if (!isKnownPrivateRepo(owner, repo)) {
896
- const data = await $fetch(`https://ungh.cc/repos/${owner}/${repo}/files/${ref}`).catch(() => null);
897
- if (data?.files?.length) return data.files.map((f) => f.path);
898
- }
899
- const tree = await ghApi(`repos/${owner}/${repo}/git/trees/${ref}?recursive=1`);
900
- if (tree?.tree?.length) {
901
- markRepoPrivate(owner, repo);
902
- return tree.tree.map((f) => f.path);
903
- }
904
- return [];
905
- }
906
- async function findGitTag(owner, repo, version, packageName, branchHint) {
907
- const candidates = [`v${version}`, version];
908
- if (packageName) candidates.push(`${packageName}@${version}`);
909
- for (const tag of candidates) {
910
- const files = await listFilesAtRef(owner, repo, tag);
911
- if (files.length > 0) return {
912
- ref: tag,
913
- files
914
- };
915
- }
916
- if (packageName) {
917
- const latestTag = await findLatestReleaseTag(owner, repo, packageName);
918
- if (latestTag) {
919
- const files = await listFilesAtRef(owner, repo, latestTag);
920
- if (files.length > 0) return {
921
- ref: latestTag,
922
- files
923
- };
924
- }
925
- }
926
- const branches = branchHint ? [branchHint, ...["main", "master"].filter((b) => b !== branchHint)] : ["main", "master"];
927
- for (const branch of branches) {
928
- const files = await listFilesAtRef(owner, repo, branch);
929
- if (files.length > 0) return {
930
- ref: branch,
931
- files,
932
- fallback: true
933
- };
934
- }
935
- return null;
936
- }
937
- async function fetchUnghReleases(owner, repo) {
938
- if (!isKnownPrivateRepo(owner, repo)) {
939
- const data = await $fetch(`https://ungh.cc/repos/${owner}/${repo}/releases`).catch(() => null);
940
- if (data?.releases?.length) return data.releases;
941
- }
942
- const raw = await ghApiPaginated(`repos/${owner}/${repo}/releases`);
943
- if (raw.length > 0) {
944
- markRepoPrivate(owner, repo);
945
- return raw.map((r) => ({
946
- tag: r.tag_name,
947
- publishedAt: r.published_at
948
- }));
949
- }
950
- return [];
951
- }
952
- async function findLatestReleaseTag(owner, repo, packageName) {
953
- const prefix = `${packageName}@`;
954
- return (await fetchUnghReleases(owner, repo)).find((r) => r.tag.startsWith(prefix))?.tag ?? null;
955
- }
956
- function filterDocFiles(files, pathPrefix) {
957
- return files.filter((f) => f.startsWith(pathPrefix) && /\.(?:md|mdx)$/.test(f));
958
- }
959
- const FRAMEWORK_NAMES = new Set([
960
- "vue",
961
- "react",
962
- "solid",
963
- "angular",
964
- "svelte",
965
- "preact",
966
- "lit",
967
- "qwik"
968
- ]);
969
- function filterFrameworkDocs(files, packageName) {
970
- if (!packageName) return files;
971
- const shortName = packageName.replace(/^@.*\//, "");
972
- const targetFramework = [...FRAMEWORK_NAMES].find((fw) => shortName.includes(fw));
973
- if (!targetFramework) return files;
974
- const otherFrameworks = [...FRAMEWORK_NAMES].filter((fw) => fw !== targetFramework);
975
- const excludePattern = new RegExp(`\\b(?:${otherFrameworks.join("|")})\\b`);
976
- return files.filter((f) => !excludePattern.test(f));
977
- }
978
- const NOISE_PATTERNS = [
979
- /^\.changeset\//,
980
- /CHANGELOG\.md$/i,
981
- /CONTRIBUTING\.md$/i,
982
- /^\.github\//
983
- ];
984
- const EXCLUDE_DIRS = new Set([
985
- "test",
986
- "tests",
987
- "__tests__",
988
- "fixtures",
989
- "fixture",
990
- "examples",
991
- "example",
992
- "node_modules",
993
- ".git",
994
- "dist",
995
- "build",
996
- "coverage",
997
- "e2e",
998
- "spec",
999
- "mocks",
1000
- "__mocks__"
1001
- ]);
1002
- const DOC_DIR_BONUS = new Set([
1003
- "docs",
1004
- "documentation",
1005
- "pages",
1006
- "content",
1007
- "website",
1008
- "guide",
1009
- "guides",
1010
- "wiki",
1011
- "manual",
1012
- "api"
1013
- ]);
1014
- function hasExcludedDir(path) {
1015
- return path.split("/").some((p) => EXCLUDE_DIRS.has(p.toLowerCase()));
1016
- }
1017
- function getPathDepth(path) {
1018
- return path.split("/").filter(Boolean).length;
1019
- }
1020
- function hasDocDirBonus(path) {
1021
- return path.split("/").some((p) => DOC_DIR_BONUS.has(p.toLowerCase()));
1022
- }
1023
- function scoreDocDir(dir, fileCount) {
1024
- const depth = getPathDepth(dir) || 1;
1025
- return fileCount * (hasDocDirBonus(dir) ? 1.5 : 1) / depth;
1026
- }
1027
- function discoverDocFiles(allFiles, packageName) {
1028
- const mdFiles = allFiles.filter((f) => /\.(?:md|mdx)$/.test(f)).filter((f) => !NOISE_PATTERNS.some((p) => p.test(f))).filter((f) => f.includes("/"));
1029
- if (packageName?.includes("/")) {
1030
- const subPkgPrefix = `packages/${packageName.split("/").pop().toLowerCase()}/`;
1031
- const subPkgFiles = mdFiles.filter((f) => f.startsWith(subPkgPrefix));
1032
- if (subPkgFiles.length >= 3) return {
1033
- files: subPkgFiles,
1034
- prefix: subPkgPrefix
1035
- };
1036
- }
1037
- const docsGroups = /* @__PURE__ */ new Map();
1038
- for (const file of mdFiles) {
1039
- const docsIdx = file.lastIndexOf("/docs/");
1040
- if (docsIdx === -1) continue;
1041
- mapInsert(docsGroups, file.slice(0, docsIdx + 6), () => []).push(file);
1029
+ const body = truncateBody(issue.body, limit);
1030
+ lines.push("", body);
1042
1031
  }
1043
- if (docsGroups.size > 0) {
1044
- const largest = [...docsGroups.entries()].sort((a, b) => b[1].length - a[1].length)[0];
1045
- if (largest[1].length >= 3) {
1046
- const fullPrefix = largest[0];
1047
- const docsIdx = fullPrefix.lastIndexOf("docs/");
1048
- const stripPrefix = docsIdx > 0 ? fullPrefix.slice(0, docsIdx) : "";
1049
- return {
1050
- files: largest[1],
1051
- prefix: stripPrefix
1052
- };
1032
+ if (issue.topComments.length > 0) {
1033
+ lines.push("", "---", "", "## Top Comments");
1034
+ for (const c of issue.topComments) {
1035
+ const reactions = c.reactions > 0 ? ` (+${c.reactions})` : "";
1036
+ const maintainer = c.isMaintainer ? " [maintainer]" : "";
1037
+ const commentBody = truncateBody(c.body, 600);
1038
+ lines.push("", `**@${c.author}**${maintainer}${reactions}:`, "", commentBody);
1053
1039
  }
1054
1040
  }
1055
- const dirGroups = /* @__PURE__ */ new Map();
1056
- for (const file of mdFiles) {
1057
- if (hasExcludedDir(file)) continue;
1058
- const lastSlash = file.lastIndexOf("/");
1059
- if (lastSlash === -1) continue;
1060
- mapInsert(dirGroups, file.slice(0, lastSlash + 1), () => []).push(file);
1041
+ return lines.join("\n");
1042
+ }
1043
+ function generateIssueIndex(issues) {
1044
+ const byType = /* @__PURE__ */ new Map();
1045
+ for (const issue of issues) mapInsert(byType, issue.type, () => []).push(issue);
1046
+ const typeLabels = {
1047
+ bug: "Bugs & Regressions",
1048
+ question: "Questions & Usage Help",
1049
+ docs: "Documentation",
1050
+ feature: "Feature Requests",
1051
+ other: "Other"
1052
+ };
1053
+ const typeOrder = [
1054
+ "bug",
1055
+ "question",
1056
+ "docs",
1057
+ "other",
1058
+ "feature"
1059
+ ];
1060
+ const sections = [
1061
+ [
1062
+ "---",
1063
+ `total: ${issues.length}`,
1064
+ `open: ${issues.filter((i) => i.state === "open").length}`,
1065
+ `closed: ${issues.filter((i) => i.state !== "open").length}`,
1066
+ "---"
1067
+ ].join("\n"),
1068
+ "",
1069
+ "# Issues Index",
1070
+ ""
1071
+ ];
1072
+ for (const type of typeOrder) {
1073
+ const group = byType.get(type);
1074
+ if (!group?.length) continue;
1075
+ sections.push(`## ${typeLabels[type]} (${group.length})`, "");
1076
+ for (const issue of group) {
1077
+ const reactions = issue.reactions > 0 ? ` (+${issue.reactions})` : "";
1078
+ const state = issue.state === "open" ? "" : " [closed]";
1079
+ const resolved = issue.resolvedIn ? ` [fixed in ${issue.resolvedIn}]` : "";
1080
+ const date = isoDate(issue.createdAt);
1081
+ sections.push(`- [#${issue.number}](./issue-${issue.number}.md): ${issue.title}${reactions}${state}${resolved} (${date})`);
1082
+ }
1083
+ sections.push("");
1061
1084
  }
1062
- if (dirGroups.size === 0) return null;
1063
- const scored = Array.from(dirGroups.entries(), ([dir, files]) => ({
1064
- dir,
1065
- files,
1066
- score: scoreDocDir(dir, files.length)
1067
- })).filter((d) => d.files.length >= 5).sort((a, b) => b.score - a.score);
1068
- if (scored.length === 0) return null;
1069
- const best = scored[0];
1085
+ return sections.join("\n");
1086
+ }
1087
+ async function fetchLlmsUrl(docsUrl) {
1088
+ const llmsUrl = `${new URL(docsUrl).origin}/llms.txt`;
1089
+ if (await verifyUrl(llmsUrl)) return llmsUrl;
1090
+ return null;
1091
+ }
1092
+ async function fetchLlmsTxt(url) {
1093
+ const content = await fetchText(url);
1094
+ if (!content || content.length < 50) return null;
1070
1095
  return {
1071
- files: best.files,
1072
- prefix: best.dir
1096
+ raw: content,
1097
+ links: parseMarkdownLinks(content)
1073
1098
  };
1074
1099
  }
1075
- async function listDocsAtRef(owner, repo, ref, pathPrefix = "docs/") {
1076
- return filterDocFiles(await listFilesAtRef(owner, repo, ref), pathPrefix);
1100
+ function parseMarkdownLinks(content) {
1101
+ return extractLinks(content).filter((l) => l.url.endsWith(".md"));
1077
1102
  }
1078
- async function fetchGitDocs(owner, repo, version, packageName, repoUrl) {
1079
- const override = packageName ? getDocOverride(packageName) : void 0;
1080
- if (override) {
1081
- const ref = override.ref || "main";
1082
- const fallback = !override.ref;
1083
- const files = await listDocsAtRef(override.owner, override.repo, ref, `${override.path}/`);
1084
- if (files.length === 0) return null;
1085
- return {
1086
- baseUrl: `https://raw.githubusercontent.com/${override.owner}/${override.repo}/${ref}`,
1087
- ref,
1088
- files,
1089
- fallback,
1090
- docsPrefix: `${override.path}/` !== "docs/" ? `${override.path}/` : void 0
1091
- };
1092
- }
1093
- const tag = await findGitTag(owner, repo, version, packageName, repoUrl ? extractBranchHint(repoUrl) : void 0);
1094
- if (!tag) return null;
1095
- let docs = filterDocFiles(tag.files, "docs/");
1096
- let docsPrefix;
1097
- let allFiles;
1098
- if (docs.length === 0) {
1099
- const discovered = discoverDocFiles(tag.files, packageName);
1100
- if (discovered) {
1101
- docs = discovered.files;
1102
- docsPrefix = discovered.prefix || void 0;
1103
- allFiles = tag.files;
1104
- }
1103
+ function isSafeUrl(url) {
1104
+ try {
1105
+ const parsed = new URL(url);
1106
+ if (parsed.protocol !== "https:") return false;
1107
+ const host = parsed.hostname;
1108
+ if (host === "localhost" || host === "0.0.0.0" || host === "[::1]") return false;
1109
+ if (/^(?:127\.|10\.|172\.(?:1[6-9]|2\d|3[01])\.|192\.168\.|169\.254\.)/.test(host)) return false;
1110
+ if (/^\[(?:f[cd]|fe[89ab]|::ffff:)/i.test(host)) return false;
1111
+ return true;
1112
+ } catch {
1113
+ return false;
1105
1114
  }
1106
- docs = filterFrameworkDocs(docs, packageName);
1107
- if (docs.length === 0) return null;
1108
- return {
1109
- baseUrl: `https://raw.githubusercontent.com/${owner}/${repo}/${tag.ref}`,
1110
- ref: tag.ref,
1111
- files: docs,
1112
- docsPrefix,
1113
- allFiles,
1114
- fallback: tag.fallback
1115
- };
1116
1115
  }
1117
- function normalizePath(p) {
1118
- return p.replace(/^\//, "").replace(/\.(?:md|mdx)$/, "");
1116
+ async function downloadLlmsDocs(llmsContent, baseUrl, onProgress) {
1117
+ const limit = pLimit(5);
1118
+ let completed = 0;
1119
+ return (await Promise.all(llmsContent.links.map((link) => limit(async () => {
1120
+ const url = link.url.startsWith("http") ? link.url : `${baseUrl.replace(/\/$/, "")}${link.url.startsWith("/") ? "" : "/"}${link.url}`;
1121
+ if (!isSafeUrl(url)) return null;
1122
+ const content = await fetchText(url);
1123
+ onProgress?.(link.url, ++completed, llmsContent.links.length);
1124
+ if (content && content.length > 100) return {
1125
+ url: link.url.startsWith("http") ? new URL(link.url).pathname : link.url,
1126
+ title: link.title,
1127
+ content
1128
+ };
1129
+ return null;
1130
+ })))).filter((d) => d !== null);
1119
1131
  }
1120
- function validateGitDocsWithLlms(llmsLinks, repoFiles) {
1121
- if (llmsLinks.length === 0) return {
1122
- isValid: true,
1123
- matchRatio: 1
1124
- };
1125
- const sample = llmsLinks.slice(0, 10);
1126
- const normalizedLinks = sample.map((link) => {
1127
- let path = link.url;
1128
- if (path.startsWith("http")) try {
1129
- path = new URL(path).pathname;
1130
- } catch {}
1131
- return normalizePath(path);
1132
- });
1133
- const repoNormalized = new Set(repoFiles.map(normalizePath));
1134
- let matches = 0;
1135
- for (const linkPath of normalizedLinks) for (const repoPath of repoNormalized) if (repoPath === linkPath || repoPath.endsWith(`/${linkPath}`)) {
1136
- matches++;
1137
- break;
1132
+ function normalizeLlmsLinks(content, baseUrl) {
1133
+ let normalized = content;
1134
+ if (baseUrl) {
1135
+ const escaped = baseUrl.replace(/\/$/, "").replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
1136
+ normalized = normalized.replace(new RegExp(`\\]\\(${escaped}(/[^)]+\\.md)\\)`, "g"), "](./docs$1)");
1138
1137
  }
1139
- const matchRatio = matches / sample.length;
1140
- return {
1141
- isValid: matchRatio >= .3,
1142
- matchRatio
1143
- };
1138
+ normalized = normalized.replace(/\]\(\/([^)]+\.md)\)/g, "](./docs/$1)");
1139
+ return normalized;
1140
+ }
1141
+ function extractSections(content, patterns) {
1142
+ const sections = [];
1143
+ const parts = content.split(/\n---\n/);
1144
+ for (const part of parts) {
1145
+ const urlMatch = part.match(/^url: *(\S.*)$/m);
1146
+ if (!urlMatch) continue;
1147
+ const url = urlMatch[1];
1148
+ if (patterns.some((p) => url.includes(p))) {
1149
+ const contentStart = part.indexOf("\n", part.indexOf("url:"));
1150
+ if (contentStart > -1) sections.push(part.slice(contentStart + 1));
1151
+ }
1152
+ }
1153
+ if (sections.length === 0) return null;
1154
+ return sections.join("\n\n---\n\n");
1144
1155
  }
1145
1156
  async function verifyNpmRepo(owner, repo, packageName) {
1146
1157
  const base = `https://raw.githubusercontent.com/${owner}/${repo}/HEAD`;
@@ -2062,6 +2073,17 @@ async function fetchGitLabSkills(source, onProgress) {
2062
2073
  });
2063
2074
  }
2064
2075
  }
2076
+ async function resolveLocalDep(packageName, cwd) {
2077
+ const result = readPackageJsonSafe(join(cwd, "package.json"));
2078
+ if (!result) return null;
2079
+ const pkg = result.parsed;
2080
+ const depVersion = {
2081
+ ...pkg.dependencies,
2082
+ ...pkg.devDependencies
2083
+ }[packageName];
2084
+ if (!depVersion?.startsWith("link:")) return null;
2085
+ return resolveLocalPackageDocs(resolve(cwd, depVersion.slice(5)));
2086
+ }
2065
2087
  async function searchNpmPackages(query, size = 5) {
2066
2088
  const data = await $fetch(`https://registry.npmjs.org/-/v1/search?text=${encodeURIComponent(query)}&size=${size}`).catch(() => null);
2067
2089
  if (!data?.objects?.length) return [];
@@ -2472,6 +2494,161 @@ function getInstalledSkillVersion(skillDir) {
2472
2494
  if (!existsSync(skillPath)) return null;
2473
2495
  return readFileSync(skillPath, "utf-8").match(/^version:\s*"?([^"\n]+)"?/m)?.[1] || null;
2474
2496
  }
2475
- export { fetchText as $, filterFrameworkDocs as A, fetchGitHubIssues as B, toCrawlPattern as C, fetchGitHubRepoMeta as D, fetchGitDocs as E, extractSections as F, compareSemver as G, generateIssueIndex as H, fetchLlmsTxt as I, isPrerelease as J, fetchReleaseNotes as K, fetchLlmsUrl as L, resolveGitHubRepo as M, validateGitDocsWithLlms as N, fetchReadme as O, downloadLlmsDocs as P, fetchGitHubRaw as Q, normalizeLlmsLinks as R, fetchCrawledDocs as S, MIN_GIT_DOCS as T, isGhAvailable as U, formatIssueAsMarkdown as V, fetchBlogReleases as W, $fetch as X, parseSemver as Y, extractBranchHint as Z, resolveEntryFiles as _, getInstalledSkillVersion as a, verifyUrl as at, formatDiscussionAsMarkdown as b, readLocalPackageInfo as c, resolvePackageDocs as d, isGitHubRepoUrl as et, resolvePackageDocsWithAttempts as f, parseSkillFrontmatterName as g, parseGitSkillInput as h, fetchPkgDist as i, parsePackageSpec as it, isShallowGitDocs as j, fetchReadmeContent as k, resolveInstalledVersion as l, fetchGitSkills as m, fetchNpmPackage as n, parseGitHubRepoSlug as nt, parseVersionSpecifier as o, searchNpmPackages as p, generateReleaseIndex as q, fetchNpmRegistryMeta as r, parseGitHubUrl as rt, readLocalDependencies as s, fetchLatestVersion as t, normalizeRepoUrl as tt, resolveLocalPackageDocs as u, generateDocsIndex as v, resolveCrateDocsWithAttempts as w, generateDiscussionIndex as x, fetchGitHubDiscussions as y, parseMarkdownLinks as z };
2497
+ function parseSkillInput(input) {
2498
+ const trimmed = input.trim();
2499
+ if (trimmed.startsWith("npm:")) {
2500
+ const { name, tag } = splitPackageTag(trimmed.slice(4));
2501
+ return {
2502
+ type: "npm",
2503
+ package: name,
2504
+ tag
2505
+ };
2506
+ }
2507
+ if (trimmed.startsWith("crate:")) {
2508
+ const rest = trimmed.slice(6).trim();
2509
+ const atIdx = rest.indexOf("@");
2510
+ return {
2511
+ type: "crate",
2512
+ package: (atIdx === -1 ? rest : rest.slice(0, atIdx)).toLowerCase(),
2513
+ version: atIdx === -1 ? void 0 : rest.slice(atIdx + 1) || void 0
2514
+ };
2515
+ }
2516
+ if (trimmed.startsWith("gh:") || trimmed.startsWith("github:")) {
2517
+ const rest = trimmed.startsWith("gh:") ? trimmed.slice(3) : trimmed.slice(7);
2518
+ const gitSource = parseGitSkillInput(rest);
2519
+ if (gitSource) return {
2520
+ type: "git",
2521
+ source: gitSource
2522
+ };
2523
+ if (/^[\w.-]+\/[\w.-]+/.test(rest)) {
2524
+ const [owner, repo] = rest.split("/");
2525
+ return {
2526
+ type: "git",
2527
+ source: {
2528
+ type: "github",
2529
+ owner,
2530
+ repo
2531
+ }
2532
+ };
2533
+ }
2534
+ return {
2535
+ type: "bare",
2536
+ package: rest
2537
+ };
2538
+ }
2539
+ if (trimmed.startsWith("@")) {
2540
+ const rest = trimmed.slice(1);
2541
+ if (rest.indexOf("/") === -1) return {
2542
+ type: "curator",
2543
+ handle: rest
2544
+ };
2545
+ const { name, tag } = splitPackageTag(trimmed);
2546
+ return {
2547
+ type: "bare",
2548
+ package: name,
2549
+ tag
2550
+ };
2551
+ }
2552
+ const gitSource = parseGitSkillInput(trimmed);
2553
+ if (gitSource) return {
2554
+ type: "git",
2555
+ source: gitSource
2556
+ };
2557
+ const { name, tag } = splitPackageTag(trimmed);
2558
+ return {
2559
+ type: "bare",
2560
+ package: name,
2561
+ tag
2562
+ };
2563
+ }
2564
+ function resolveSkillName(input) {
2565
+ const source = parseSkillInput(input);
2566
+ switch (source.type) {
2567
+ case "npm":
2568
+ case "bare": return source.package;
2569
+ case "crate": return `crate:${source.package}`;
2570
+ case "git":
2571
+ if (source.source.type === "github" && source.source.repo) return source.source.repo;
2572
+ return null;
2573
+ case "curator":
2574
+ case "collection": return null;
2575
+ default: throw new Error(`Unhandled SkillSource type: ${JSON.stringify(source)}`);
2576
+ }
2577
+ }
2578
+ function toStoragePackageName(identityName) {
2579
+ if (identityName.startsWith("crate:")) return `@skilld-crate/${identityName.slice(6)}`;
2580
+ return identityName;
2581
+ }
2582
+ function isCrateSpec(spec) {
2583
+ return spec.startsWith("crate:");
2584
+ }
2585
+ function toCrateIdentity(crateName) {
2586
+ return `crate:${crateName}`;
2587
+ }
2588
+ function splitPackageTag(spec) {
2589
+ if (spec.startsWith("@")) {
2590
+ const slashIdx = spec.indexOf("/");
2591
+ if (slashIdx !== -1) {
2592
+ const afterSlash = spec.indexOf("@", slashIdx);
2593
+ if (afterSlash !== -1) return {
2594
+ name: spec.slice(0, afterSlash),
2595
+ tag: spec.slice(afterSlash + 1) || void 0
2596
+ };
2597
+ }
2598
+ return { name: spec };
2599
+ }
2600
+ const atIdx = spec.indexOf("@");
2601
+ if (atIdx !== -1) return {
2602
+ name: spec.slice(0, atIdx),
2603
+ tag: spec.slice(atIdx + 1) || void 0
2604
+ };
2605
+ return { name: spec };
2606
+ }
2607
+ const RESOLVE_STEP_LABELS = {
2608
+ "npm": "npm registry",
2609
+ "github-docs": "GitHub docs",
2610
+ "github-meta": "GitHub meta",
2611
+ "github-search": "GitHub search",
2612
+ "readme": "README",
2613
+ "llms.txt": "llms.txt",
2614
+ "crawl": "website crawl",
2615
+ "local": "node_modules"
2616
+ };
2617
+ async function resolvePackageOrCrate(packageSpec, opts) {
2618
+ const { cwd, onProgress } = opts;
2619
+ const isCrate = isCrateSpec(packageSpec);
2620
+ const normalizedSpec = isCrate ? packageSpec.slice(6).trim() : packageSpec;
2621
+ const { name: parsedName, tag: requestedTag } = parsePackageSpec(normalizedSpec);
2622
+ const packageName = isCrate ? parsedName.toLowerCase() : parsedName;
2623
+ const identityPackageName = isCrate ? toCrateIdentity(packageName) : packageName;
2624
+ const storagePackageName = toStoragePackageName(identityPackageName);
2625
+ const localDeps = isCrate ? [] : await readLocalDependencies(cwd).catch(() => []);
2626
+ const localVersion = isCrate ? void 0 : localDeps.find((d) => d.name === packageName)?.version;
2627
+ const resolveResult = isCrate ? await resolveCrateDocsWithAttempts(packageName, {
2628
+ version: requestedTag,
2629
+ onProgress
2630
+ }) : await resolvePackageDocsWithAttempts(requestedTag ? normalizedSpec : packageName, {
2631
+ version: localVersion,
2632
+ cwd,
2633
+ onProgress: (step) => onProgress?.(RESOLVE_STEP_LABELS[step] ?? step)
2634
+ });
2635
+ let resolved = resolveResult.package;
2636
+ if (!resolved && !isCrate) {
2637
+ onProgress?.(RESOLVE_STEP_LABELS.local);
2638
+ resolved = await resolveLocalDep(packageName, cwd);
2639
+ }
2640
+ return {
2641
+ packageName,
2642
+ identityPackageName,
2643
+ storagePackageName,
2644
+ isCrate,
2645
+ requestedTag,
2646
+ localVersion,
2647
+ resolved,
2648
+ attempts: resolveResult.attempts,
2649
+ registryVersion: resolveResult.registryVersion
2650
+ };
2651
+ }
2652
+ export { fetchReleaseNotes as $, resolveCrateDocsWithAttempts as A, parseMarkdownLinks as B, resolveEntryFiles as C, generateDiscussionIndex as D, formatDiscussionAsMarkdown as E, downloadLlmsDocs as F, MIN_GIT_DOCS as G, formatIssueAsMarkdown as H, extractSections as I, isShallowGitDocs as J, fetchGitDocs as K, fetchLlmsTxt as L, fetchReadme as M, fetchReadmeContent as N, fetchCrawledDocs as O, resolveGitHubRepo as P, compareSemver as Q, fetchLlmsUrl as R, parseSkillFrontmatterName as S, fetchGitHubDiscussions as T, generateIssueIndex as U, fetchGitHubIssues as V, isGhAvailable as W, mapInsert as X, validateGitDocsWithLlms as Y, fetchBlogReleases as Z, resolvePackageDocsWithAttempts as _, toStoragePackageName as a, fetchGitHubRaw as at, fetchGitSkills as b, fetchNpmRegistryMeta as c, normalizeRepoUrl as ct, parseVersionSpecifier as d, parsePackageSpec as dt, generateReleaseIndex as et, readLocalDependencies as f, verifyUrl as ft, resolvePackageDocs as g, resolveLocalPackageDocs as h, resolveSkillName as i, extractBranchHint as it, fetchGitHubRepoMeta as j, toCrawlPattern as k, fetchPkgDist as l, parseGitHubRepoSlug as lt, resolveInstalledVersion as m, isCrateSpec as n, parseSemver as nt, fetchLatestVersion as o, fetchText as ot, readLocalPackageInfo as p, filterFrameworkDocs as q, parseSkillInput as r, $fetch as rt, fetchNpmPackage as s, isGitHubRepoUrl as st, resolvePackageOrCrate as t, isPrerelease as tt, getInstalledSkillVersion as u, parseGitHubUrl as ut, searchNpmPackages as v, generateDocsIndex as w, parseGitSkillInput as x, resolveLocalDep as y, normalizeLlmsLinks as z };
2476
2653
 
2477
2654
  //# sourceMappingURL=sources.mjs.map