skilld 1.7.2 → 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 (118) 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/assemble.mjs.map +1 -1
  5. package/dist/_chunks/author-group.mjs.map +1 -1
  6. package/dist/_chunks/author.mjs +51 -121
  7. package/dist/_chunks/author.mjs.map +1 -1
  8. package/dist/_chunks/cache.mjs +315 -9
  9. package/dist/_chunks/cache.mjs.map +1 -1
  10. package/dist/_chunks/cache2.mjs +2 -2
  11. package/dist/_chunks/cache2.mjs.map +1 -1
  12. package/dist/_chunks/cli-helpers.mjs +3 -3
  13. package/dist/_chunks/cli-helpers.mjs.map +1 -1
  14. package/dist/_chunks/core.mjs +7 -4
  15. package/dist/_chunks/detect.mjs +1 -1
  16. package/dist/_chunks/detect.mjs.map +1 -1
  17. package/dist/_chunks/embedding-cache2.mjs +2 -2
  18. package/dist/_chunks/embedding-cache2.mjs.map +1 -1
  19. package/dist/_chunks/index.d.mts +305 -112
  20. package/dist/_chunks/index.d.mts.map +1 -1
  21. package/dist/_chunks/index2.d.mts +267 -32
  22. package/dist/_chunks/index2.d.mts.map +1 -1
  23. package/dist/_chunks/index3.d.mts +32 -577
  24. package/dist/_chunks/index3.d.mts.map +1 -1
  25. package/dist/_chunks/index4.d.mts +553 -0
  26. package/dist/_chunks/index4.d.mts.map +1 -0
  27. package/dist/_chunks/install.mjs +48 -88
  28. package/dist/_chunks/install.mjs.map +1 -1
  29. package/dist/_chunks/list.mjs +1 -1
  30. package/dist/_chunks/list.mjs.map +1 -1
  31. package/dist/_chunks/lockfile.mjs +29 -6
  32. package/dist/_chunks/lockfile.mjs.map +1 -1
  33. package/dist/_chunks/markdown.mjs.map +1 -1
  34. package/dist/_chunks/monorepo.mjs +71 -0
  35. package/dist/_chunks/monorepo.mjs.map +1 -0
  36. package/dist/_chunks/package-json.mjs.map +1 -1
  37. package/dist/_chunks/{shared.mjs → package-registry.mjs} +2 -40
  38. package/dist/_chunks/package-registry.mjs.map +1 -0
  39. package/dist/_chunks/paths.mjs +49 -0
  40. package/dist/_chunks/paths.mjs.map +1 -0
  41. package/dist/_chunks/pool2.mjs +7 -2
  42. package/dist/_chunks/pool2.mjs.map +1 -1
  43. package/dist/_chunks/prepare.mjs +1 -1
  44. package/dist/_chunks/prepare.mjs.map +1 -1
  45. package/dist/_chunks/prepare2.mjs +5 -5
  46. package/dist/_chunks/prepare2.mjs.map +1 -1
  47. package/dist/_chunks/prompts.mjs +366 -18
  48. package/dist/_chunks/prompts.mjs.map +1 -1
  49. package/dist/_chunks/retriv.mjs.map +1 -1
  50. package/dist/_chunks/sanitize.mjs.map +1 -1
  51. package/dist/_chunks/search-helpers.mjs +5 -6
  52. package/dist/_chunks/search-helpers.mjs.map +1 -1
  53. package/dist/_chunks/search-interactive.mjs +1 -1
  54. package/dist/_chunks/search-interactive.mjs.map +1 -1
  55. package/dist/_chunks/search.mjs +1 -2
  56. package/dist/_chunks/search.mjs.map +1 -1
  57. package/dist/_chunks/semver.mjs +13 -0
  58. package/dist/_chunks/semver.mjs.map +1 -0
  59. package/dist/_chunks/setup.mjs.map +1 -1
  60. package/dist/_chunks/skill-installer.mjs +2 -0
  61. package/dist/_chunks/skill-installer2.mjs +155 -0
  62. package/dist/_chunks/skill-installer2.mjs.map +1 -0
  63. package/dist/_chunks/skills.mjs +10 -9
  64. package/dist/_chunks/skills.mjs.map +1 -1
  65. package/dist/_chunks/sources.mjs +575 -386
  66. package/dist/_chunks/sources.mjs.map +1 -1
  67. package/dist/_chunks/sync-pipeline.mjs +952 -0
  68. package/dist/_chunks/sync-pipeline.mjs.map +1 -0
  69. package/dist/_chunks/sync-registry.mjs +19 -13
  70. package/dist/_chunks/sync-registry.mjs.map +1 -1
  71. package/dist/_chunks/sync.mjs +797 -886
  72. package/dist/_chunks/sync.mjs.map +1 -1
  73. package/dist/_chunks/sync2.mjs +4 -2
  74. package/dist/_chunks/types.d.mts +65 -77
  75. package/dist/_chunks/types.d.mts.map +1 -1
  76. package/dist/_chunks/types2.d.mts +88 -0
  77. package/dist/_chunks/types2.d.mts.map +1 -0
  78. package/dist/_chunks/uninstall.mjs +7 -8
  79. package/dist/_chunks/uninstall.mjs.map +1 -1
  80. package/dist/_chunks/upload.mjs +2 -2
  81. package/dist/_chunks/upload.mjs.map +1 -1
  82. package/dist/_chunks/validate.mjs +1 -1
  83. package/dist/_chunks/validate.mjs.map +1 -1
  84. package/dist/_chunks/version.mjs +3 -13
  85. package/dist/_chunks/version.mjs.map +1 -1
  86. package/dist/_chunks/wizard.mjs +2 -2
  87. package/dist/_chunks/wizard.mjs.map +1 -1
  88. package/dist/_chunks/yaml.mjs.map +1 -1
  89. package/dist/agent/index.d.mts +2 -346
  90. package/dist/agent/index.mjs +2 -3
  91. package/dist/cache/index.d.mts +2 -2
  92. package/dist/cache/index.mjs +4 -3
  93. package/dist/cli.mjs +12 -13
  94. package/dist/cli.mjs.map +1 -1
  95. package/dist/index.d.mts +5 -4
  96. package/dist/index.mjs +4 -3
  97. package/dist/prepare.mjs +2 -2
  98. package/dist/prepare.mjs.map +1 -1
  99. package/dist/retriv/index.d.mts +2 -2
  100. package/dist/retriv/worker.d.mts +2 -1
  101. package/dist/retriv/worker.d.mts.map +1 -1
  102. package/dist/retriv/worker.mjs +2 -1
  103. package/dist/retriv/worker.mjs.map +1 -1
  104. package/dist/sources/index.d.mts +3 -2
  105. package/dist/sources/index.mjs +3 -3
  106. package/dist/types.d.mts +3 -3
  107. package/package.json +5 -5
  108. package/dist/_chunks/config.mjs +0 -122
  109. package/dist/_chunks/config.mjs.map +0 -1
  110. package/dist/_chunks/prefix.mjs +0 -108
  111. package/dist/_chunks/prefix.mjs.map +0 -1
  112. package/dist/_chunks/shared.mjs.map +0 -1
  113. package/dist/_chunks/skill.mjs +0 -329
  114. package/dist/_chunks/skill.mjs.map +0 -1
  115. package/dist/_chunks/sync-shared.mjs +0 -2
  116. package/dist/_chunks/sync-shared2.mjs +0 -1020
  117. package/dist/_chunks/sync-shared2.mjs.map +0 -1
  118. 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;
@@ -758,389 +1022,136 @@ function formatIssueAsMarkdown(issue) {
758
1022
  if (issue.labels.length > 0) fmFields.labels = `[${issue.labels.join(", ")}]`;
759
1023
  const lines = [
760
1024
  buildFrontmatter(fmFields),
761
- "",
762
- `# ${issue.title}`
763
- ];
764
- 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);
1042
- }
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
- };
1025
+ "",
1026
+ `# ${issue.title}`
1027
+ ];
1028
+ if (issue.body) {
1029
+ const body = truncateBody(issue.body, limit);
1030
+ lines.push("", body);
1031
+ }
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`;
@@ -1887,6 +1898,21 @@ function parseSkillFrontmatterName(content) {
1887
1898
  description: fm.description
1888
1899
  };
1889
1900
  }
1901
+ function findSkillDirs(root, prefix = "") {
1902
+ const out = [];
1903
+ if (!existsSync(root)) return out;
1904
+ for (const entry of readdirSync(root, { withFileTypes: true })) {
1905
+ if (!entry.isDirectory()) continue;
1906
+ const dir = resolve(root, entry.name);
1907
+ const repoPath = prefix ? `${prefix}/${entry.name}` : entry.name;
1908
+ if (existsSync(resolve(dir, "SKILL.md"))) out.push({
1909
+ dir,
1910
+ repoPath
1911
+ });
1912
+ else out.push(...findSkillDirs(dir, repoPath));
1913
+ }
1914
+ return out;
1915
+ }
1890
1916
  function collectFiles(dir, prefix = "") {
1891
1917
  const files = [];
1892
1918
  if (!existsSync(dir)) return files;
@@ -1912,9 +1938,8 @@ function fetchLocalSkills(source) {
1912
1938
  if (!existsSync(base)) return { skills: [] };
1913
1939
  const skills = [];
1914
1940
  const skillsDir = resolve(base, "skills");
1915
- if (existsSync(skillsDir)) for (const entry of readdirSync(skillsDir, { withFileTypes: true })) {
1916
- if (!entry.isDirectory()) continue;
1917
- const skill = readLocalSkill(resolve(skillsDir, entry.name), `skills/${entry.name}`);
1941
+ if (existsSync(skillsDir)) for (const { dir, repoPath } of findSkillDirs(skillsDir, "skills")) {
1942
+ const skill = readLocalSkill(dir, repoPath);
1918
1943
  if (skill) skills.push(skill);
1919
1944
  }
1920
1945
  if (skills.length === 0) {
@@ -1971,9 +1996,8 @@ async function downloadGitHubSkills(owner, repo, ref, skillPath, onProgress) {
1971
1996
  auth: getGitHubToken() || void 0
1972
1997
  });
1973
1998
  const skills = [];
1974
- for (const entry of readdirSync(dir, { withFileTypes: true })) {
1975
- if (!entry.isDirectory()) continue;
1976
- const skill = readLocalSkill(resolve(dir, entry.name), `skills/${entry.name}`);
1999
+ for (const { dir: skillDir, repoPath } of findSkillDirs(dir, "skills")) {
2000
+ const skill = readLocalSkill(skillDir, repoPath);
1977
2001
  if (skill) skills.push(skill);
1978
2002
  }
1979
2003
  if (skills.length > 0) {
@@ -2020,9 +2044,8 @@ async function fetchGitLabSkills(source, onProgress) {
2020
2044
  return { skills: skill ? [skill] : [] };
2021
2045
  }
2022
2046
  const skills = [];
2023
- for (const entry of readdirSync(dir, { withFileTypes: true })) {
2024
- if (!entry.isDirectory()) continue;
2025
- const skill = readLocalSkill(resolve(dir, entry.name), `skills/${entry.name}`);
2047
+ for (const { dir: skillDir, repoPath } of findSkillDirs(dir, "skills")) {
2048
+ const skill = readLocalSkill(skillDir, repoPath);
2026
2049
  if (skill) skills.push(skill);
2027
2050
  }
2028
2051
  if (skills.length > 0) {
@@ -2050,6 +2073,17 @@ async function fetchGitLabSkills(source, onProgress) {
2050
2073
  });
2051
2074
  }
2052
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
+ }
2053
2087
  async function searchNpmPackages(query, size = 5) {
2054
2088
  const data = await $fetch(`https://registry.npmjs.org/-/v1/search?text=${encodeURIComponent(query)}&size=${size}`).catch(() => null);
2055
2089
  if (!data?.objects?.length) return [];
@@ -2460,6 +2494,161 @@ function getInstalledSkillVersion(skillDir) {
2460
2494
  if (!existsSync(skillPath)) return null;
2461
2495
  return readFileSync(skillPath, "utf-8").match(/^version:\s*"?([^"\n]+)"?/m)?.[1] || null;
2462
2496
  }
2463
- 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 };
2464
2653
 
2465
2654
  //# sourceMappingURL=sources.mjs.map