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.
- package/dist/_chunks/agent.mjs +693 -599
- package/dist/_chunks/agent.mjs.map +1 -1
- package/dist/_chunks/assemble.mjs +3 -3
- package/dist/_chunks/author.mjs +51 -121
- package/dist/_chunks/author.mjs.map +1 -1
- package/dist/_chunks/cache.mjs +315 -9
- package/dist/_chunks/cache.mjs.map +1 -1
- package/dist/_chunks/cache2.mjs +2 -2
- package/dist/_chunks/cli-helpers.mjs +3 -3
- package/dist/_chunks/core.mjs +7 -4
- package/dist/_chunks/detect.mjs +1 -1
- package/dist/_chunks/embedding-cache2.mjs +2 -2
- package/dist/_chunks/index.d.mts +305 -112
- package/dist/_chunks/index.d.mts.map +1 -1
- package/dist/_chunks/index2.d.mts +267 -32
- package/dist/_chunks/index2.d.mts.map +1 -1
- package/dist/_chunks/index3.d.mts +32 -577
- package/dist/_chunks/index3.d.mts.map +1 -1
- package/dist/_chunks/index4.d.mts +553 -0
- package/dist/_chunks/index4.d.mts.map +1 -0
- package/dist/_chunks/install.mjs +48 -88
- package/dist/_chunks/install.mjs.map +1 -1
- package/dist/_chunks/list.mjs +1 -1
- package/dist/_chunks/lockfile.mjs +29 -6
- package/dist/_chunks/lockfile.mjs.map +1 -1
- package/dist/_chunks/monorepo.mjs +71 -0
- package/dist/_chunks/monorepo.mjs.map +1 -0
- package/dist/_chunks/{shared.mjs → package-registry.mjs} +2 -40
- package/dist/_chunks/package-registry.mjs.map +1 -0
- package/dist/_chunks/paths.mjs +49 -0
- package/dist/_chunks/paths.mjs.map +1 -0
- package/dist/_chunks/pool2.mjs +1 -1
- package/dist/_chunks/prepare.mjs +1 -1
- package/dist/_chunks/prepare2.mjs +5 -5
- package/dist/_chunks/prepare2.mjs.map +1 -1
- package/dist/_chunks/prompts.mjs +366 -18
- package/dist/_chunks/prompts.mjs.map +1 -1
- package/dist/_chunks/search-helpers.mjs +5 -6
- package/dist/_chunks/search-helpers.mjs.map +1 -1
- package/dist/_chunks/search-interactive.mjs +1 -1
- package/dist/_chunks/search.mjs +1 -2
- package/dist/_chunks/search.mjs.map +1 -1
- package/dist/_chunks/semver.mjs +13 -0
- package/dist/_chunks/semver.mjs.map +1 -0
- package/dist/_chunks/skill-installer.mjs +2 -0
- package/dist/_chunks/skill-installer2.mjs +155 -0
- package/dist/_chunks/skill-installer2.mjs.map +1 -0
- package/dist/_chunks/skills.mjs +10 -9
- package/dist/_chunks/skills.mjs.map +1 -1
- package/dist/_chunks/sources.mjs +549 -372
- package/dist/_chunks/sources.mjs.map +1 -1
- package/dist/_chunks/sync-pipeline.mjs +952 -0
- package/dist/_chunks/sync-pipeline.mjs.map +1 -0
- package/dist/_chunks/sync-registry.mjs +19 -13
- package/dist/_chunks/sync-registry.mjs.map +1 -1
- package/dist/_chunks/sync.mjs +797 -886
- package/dist/_chunks/sync.mjs.map +1 -1
- package/dist/_chunks/sync2.mjs +4 -2
- package/dist/_chunks/types.d.mts +65 -77
- package/dist/_chunks/types.d.mts.map +1 -1
- package/dist/_chunks/types2.d.mts +88 -0
- package/dist/_chunks/types2.d.mts.map +1 -0
- package/dist/_chunks/uninstall.mjs +7 -8
- package/dist/_chunks/uninstall.mjs.map +1 -1
- package/dist/_chunks/upload.mjs +2 -2
- package/dist/_chunks/validate.mjs +1 -1
- package/dist/_chunks/version.mjs +3 -13
- package/dist/_chunks/version.mjs.map +1 -1
- package/dist/_chunks/wizard.mjs +2 -2
- package/dist/agent/index.d.mts +2 -346
- package/dist/agent/index.mjs +2 -3
- package/dist/cache/index.d.mts +2 -2
- package/dist/cache/index.mjs +4 -3
- package/dist/cli.mjs +12 -13
- package/dist/cli.mjs.map +1 -1
- package/dist/index.d.mts +5 -4
- package/dist/index.mjs +4 -3
- package/dist/prepare.mjs +2 -2
- package/dist/prepare.mjs.map +1 -1
- package/dist/retriv/index.d.mts +2 -2
- package/dist/retriv/worker.d.mts +1 -1
- package/dist/sources/index.d.mts +3 -2
- package/dist/sources/index.mjs +3 -3
- package/dist/types.d.mts +3 -3
- package/package.json +2 -2
- package/dist/_chunks/config.mjs +0 -122
- package/dist/_chunks/config.mjs.map +0 -1
- package/dist/_chunks/prefix.mjs +0 -108
- package/dist/_chunks/prefix.mjs.map +0 -1
- package/dist/_chunks/shared.mjs.map +0 -1
- package/dist/_chunks/skill.mjs +0 -329
- package/dist/_chunks/skill.mjs.map +0 -1
- package/dist/_chunks/sync-shared.mjs +0 -2
- package/dist/_chunks/sync-shared2.mjs +0 -1020
- package/dist/_chunks/sync-shared2.mjs.map +0 -1
- package/dist/agent/index.d.mts.map +0 -1
package/dist/_chunks/sources.mjs
CHANGED
|
@@ -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 {
|
|
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 (
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
const
|
|
1047
|
-
const
|
|
1048
|
-
const
|
|
1049
|
-
|
|
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
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
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
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
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
|
-
|
|
1072
|
-
|
|
1096
|
+
raw: content,
|
|
1097
|
+
links: parseMarkdownLinks(content)
|
|
1073
1098
|
};
|
|
1074
1099
|
}
|
|
1075
|
-
|
|
1076
|
-
return
|
|
1100
|
+
function parseMarkdownLinks(content) {
|
|
1101
|
+
return extractLinks(content).filter((l) => l.url.endsWith(".md"));
|
|
1077
1102
|
}
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
const
|
|
1083
|
-
|
|
1084
|
-
if (
|
|
1085
|
-
return
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
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
|
|
1118
|
-
|
|
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
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
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
|
-
|
|
1140
|
-
return
|
|
1141
|
-
|
|
1142
|
-
|
|
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
|
-
|
|
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
|