skilld 0.11.3 → 0.12.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,2 +1,2 @@
1
- import { C as CacheConfig, D as REFERENCES_DIR, E as CACHE_DIR, O as getPackageDbPath, S as writeToCache, T as CachedPackage, _ as listReferenceFiles, a as clearAllCache, b as resolvePkgDir, c as getPkgKeyFiles, d as isCached, f as linkCachedDir, g as listCached, h as linkShippedSkill, i as ShippedSkill, l as getShippedSkills, m as linkPkgNamed, n as getCacheKey, o as clearCache, p as linkPkg, r as getVersionKey, s as ensureCacheDir, t as getCacheDir, u as hasShippedDocs, v as readCachedDocs, w as CachedDoc, x as writeSections, y as readCachedSection } from "../_chunks/version.mjs";
2
- export { CACHE_DIR, type CacheConfig, type CachedDoc, type CachedPackage, REFERENCES_DIR, type ShippedSkill, clearAllCache, clearCache, ensureCacheDir, getCacheDir, getCacheKey, getPackageDbPath, getPkgKeyFiles, getShippedSkills, getVersionKey, hasShippedDocs, isCached, linkCachedDir, linkPkg, linkPkgNamed, linkShippedSkill, listCached, listReferenceFiles, readCachedDocs, readCachedSection, resolvePkgDir, writeSections, writeToCache };
1
+ import { A as REPOS_DIR, C as writeToCache, D as CachedPackage, E as CachedDoc, M as getRepoCacheDir, O as CACHE_DIR, S as writeSections, T as CacheConfig, _ as listCached, a as clearAllCache, b as readCachedSection, c as getPkgKeyFiles, d as isCached, f as linkCachedDir, g as linkShippedSkill, h as linkRepoCachedDir, i as ShippedSkill, j as getPackageDbPath, k as REFERENCES_DIR, l as getShippedSkills, m as linkPkgNamed, n as getCacheKey, o as clearCache, p as linkPkg, r as getVersionKey, s as ensureCacheDir, t as getCacheDir, u as hasShippedDocs, v as listReferenceFiles, w as writeToRepoCache, x as resolvePkgDir, y as readCachedDocs } from "../_chunks/version.mjs";
2
+ export { CACHE_DIR, type CacheConfig, type CachedDoc, type CachedPackage, REFERENCES_DIR, REPOS_DIR, type ShippedSkill, clearAllCache, clearCache, ensureCacheDir, getCacheDir, getCacheKey, getPackageDbPath, getPkgKeyFiles, getRepoCacheDir, getShippedSkills, getVersionKey, hasShippedDocs, isCached, linkCachedDir, linkPkg, linkPkgNamed, linkRepoCachedDir, linkShippedSkill, listCached, listReferenceFiles, readCachedDocs, readCachedSection, resolvePkgDir, writeSections, writeToCache, writeToRepoCache };
@@ -1,3 +1,3 @@
1
- import { a as getCacheKey, i as getCacheDir, n as REFERENCES_DIR, o as getVersionKey, r as getPackageDbPath, t as CACHE_DIR } from "../_chunks/config.mjs";
2
- import { _ as writeSections, a as getShippedSkills, c as linkCachedDir, d as linkShippedSkill, f as listCached, g as resolvePkgDir, h as readCachedSection, i as getPkgKeyFiles, l as linkPkg, m as readCachedDocs, n as clearCache, o as hasShippedDocs, p as listReferenceFiles, r as ensureCacheDir, s as isCached, t as clearAllCache, u as linkPkgNamed, v as writeToCache } from "../_chunks/storage.mjs";
3
- export { CACHE_DIR, REFERENCES_DIR, clearAllCache, clearCache, ensureCacheDir, getCacheDir, getCacheKey, getPackageDbPath, getPkgKeyFiles, getShippedSkills, getVersionKey, hasShippedDocs, isCached, linkCachedDir, linkPkg, linkPkgNamed, linkShippedSkill, listCached, listReferenceFiles, readCachedDocs, readCachedSection, resolvePkgDir, writeSections, writeToCache };
1
+ import { a as getRepoCacheDir, c as getVersionKey, i as getPackageDbPath, n as REFERENCES_DIR, o as getCacheDir, r as REPOS_DIR, s as getCacheKey, t as CACHE_DIR } from "../_chunks/config.mjs";
2
+ import { _ as resolvePkgDir, a as getShippedSkills, b as writeToRepoCache, c as linkCachedDir, d as linkRepoCachedDir, f as linkShippedSkill, g as readCachedSection, h as readCachedDocs, i as getPkgKeyFiles, l as linkPkg, m as listReferenceFiles, n as clearCache, o as hasShippedDocs, p as listCached, r as ensureCacheDir, s as isCached, t as clearAllCache, u as linkPkgNamed, v as writeSections, y as writeToCache } from "../_chunks/storage.mjs";
3
+ export { CACHE_DIR, REFERENCES_DIR, REPOS_DIR, clearAllCache, clearCache, ensureCacheDir, getCacheDir, getCacheKey, getPackageDbPath, getPkgKeyFiles, getRepoCacheDir, getShippedSkills, getVersionKey, hasShippedDocs, isCached, linkCachedDir, linkPkg, linkPkgNamed, linkRepoCachedDir, linkShippedSkill, listCached, listReferenceFiles, readCachedDocs, readCachedSection, resolvePkgDir, writeSections, writeToCache, writeToRepoCache };
package/dist/cli.mjs CHANGED
@@ -1,14 +1,14 @@
1
1
  #!/usr/bin/env node
2
2
  import { t as __exportAll } from "./_chunks/chunk.mjs";
3
- import { i as getCacheDir, n as REFERENCES_DIR, o as getVersionKey, r as getPackageDbPath, t as CACHE_DIR } from "./_chunks/config.mjs";
4
- import { a as getShippedSkills, b as sanitizeMarkdown, c as linkCachedDir, d as linkShippedSkill, g as resolvePkgDir, i as getPkgKeyFiles, l as linkPkg, m as readCachedDocs, n as clearCache, o as hasShippedDocs, p as listReferenceFiles, r as ensureCacheDir, s as isCached, u as linkPkgNamed, v as writeToCache } from "./_chunks/storage.mjs";
3
+ import { a as getRepoCacheDir, c as getVersionKey, i as getPackageDbPath, n as REFERENCES_DIR, o as getCacheDir, t as CACHE_DIR } from "./_chunks/config.mjs";
4
+ import { S as sanitizeMarkdown, _ as resolvePkgDir, a as getShippedSkills, b as writeToRepoCache, c as linkCachedDir, d as linkRepoCachedDir, f as linkShippedSkill, h as readCachedDocs, i as getPkgKeyFiles, l as linkPkg, m as listReferenceFiles, n as clearCache, o as hasShippedDocs, r as ensureCacheDir, s as isCached, u as linkPkgNamed, y as writeToCache } from "./_chunks/storage.mjs";
5
5
  import "./cache/index.mjs";
6
6
  import { n as yamlParseKV, r as yamlUnescape, t as yamlEscape } from "./_chunks/yaml.mjs";
7
7
  import { i as parseFrontmatter } from "./_chunks/markdown.mjs";
8
8
  import { n as clearEmbeddingCache } from "./_chunks/embedding-cache.mjs";
9
9
  import { closePool, createIndex, openPool, searchPooled, searchSnippets } from "./retriv/index.mjs";
10
- import { a as getPrereleaseChangelogRef, t as getBlogPreset } from "./_chunks/package-registry.mjs";
11
- import { $ as isGhAvailable, B as isPrerelease, E as normalizeLlmsLinks, F as generateDiscussionIndex, H as $fetch, I as fetchBlogReleases, J as parsePackageSpec, M as generateDocsIndex, N as fetchGitHubDiscussions, O as fetchGitSkills, P as formatDiscussionAsMarkdown, Q as generateIssueIndex, R as fetchReleaseNotes, S as downloadLlmsDocs, X as fetchGitHubIssues, Z as formatIssueAsMarkdown, b as resolveGitHubRepo, d as resolvePackageDocs, et as SHARED_SKILLS_DIR, f as resolvePackageDocsWithAttempts, h as fetchGitDocs, i as fetchPkgDist, j as resolveEntryFiles, k as parseGitSkillInput, n as fetchNpmPackage, nt as mapInsert, p as searchNpmPackages, q as parseGitHubUrl, r as fetchNpmRegistryMeta, rt as semverGt, s as readLocalDependencies, t as fetchLatestVersion, tt as getSharedSkillsDir, u as resolveLocalPackageDocs, v as fetchReadmeContent, w as fetchLlmsTxt, y as isShallowGitDocs, z as generateReleaseIndex } from "./_chunks/npm.mjs";
10
+ import { o as getPrereleaseChangelogRef, t as getBlogPreset } from "./_chunks/package-registry.mjs";
11
+ import { $ as formatIssueAsMarkdown, B as fetchReleaseNotes, E as normalizeLlmsLinks, F as generateDiscussionIndex, H as isPrerelease, I as fetchCrawledDocs, L as toCrawlPattern, M as generateDocsIndex, N as fetchGitHubDiscussions, O as fetchGitSkills, P as formatDiscussionAsMarkdown, Q as fetchGitHubIssues, R as fetchBlogReleases, S as downloadLlmsDocs, V as generateReleaseIndex, W as $fetch, X as parsePackageSpec, Y as parseGitHubUrl, at as semverGt, b as resolveGitHubRepo, d as resolvePackageDocs, et as generateIssueIndex, f as resolvePackageDocsWithAttempts, h as fetchGitDocs, i as fetchPkgDist, it as mapInsert, j as resolveEntryFiles, k as parseGitSkillInput, n as fetchNpmPackage, nt as SHARED_SKILLS_DIR, p as searchNpmPackages, r as fetchNpmRegistryMeta, rt as getSharedSkillsDir, s as readLocalDependencies, t as fetchLatestVersion, tt as isGhAvailable, u as resolveLocalPackageDocs, v as fetchReadmeContent, w as fetchLlmsTxt, y as isShallowGitDocs } from "./_chunks/npm.mjs";
12
12
  import "./sources/index.mjs";
13
13
  import { S as targets, _ as maxItems, a as getModelName, b as detectTargetAgent, c as computeSkillDirName, d as sanitizeName, f as unlinkSkillFromAgents, i as getModelLabel, n as createToolProgress, o as optimizeDocs, r as getAvailableModels, s as generateSkillMd, t as detectImportedPackages, u as linkSkillToAgents, v as maxLines, x as getAgentVersion, y as detectInstalledAgents } from "./_chunks/detect-imports.mjs";
14
14
  import "./agent/index.mjs";
@@ -563,7 +563,7 @@ async function getProjectState(cwd = process.cwd()) {
563
563
  const matchedSkillNames = /* @__PURE__ */ new Set();
564
564
  for (const [pkgName, version] of deps) {
565
565
  const normalizedName = pkgName.replace(/^@/, "").replace(/\//g, "-");
566
- const skill = skillByName.get(normalizedName) || skillByName.get(pkgName) || skillByPkgName.get(pkgName);
566
+ const skill = skillByName.get(`${normalizedName}-skilld`) || skillByName.get(normalizedName) || skillByName.get(pkgName) || skillByPkgName.get(pkgName);
567
567
  if (!skill) missing.push(pkgName);
568
568
  else {
569
569
  matchedSkillNames.add(skill.name);
@@ -807,6 +807,7 @@ const RESOLVE_STEP_LABELS = {
807
807
  "github-search": "GitHub search",
808
808
  "readme": "README",
809
809
  "llms.txt": "llms.txt",
810
+ "crawl": "website crawl",
810
811
  "local": "node_modules"
811
812
  };
812
813
  function classifyCachedDoc(path) {
@@ -843,23 +844,33 @@ async function findRelatedSkills(packageName, skillsDir) {
843
844
  }
844
845
  return related.slice(0, 5);
845
846
  }
846
- function forceClearCache(packageName, version) {
847
+ function forceClearCache(packageName, version, repoInfo) {
847
848
  clearCache(packageName, version);
848
849
  const forcedDbPath = getPackageDbPath(packageName, version);
849
850
  if (existsSync(forcedDbPath)) rmSync(forcedDbPath, {
850
851
  recursive: true,
851
852
  force: true
852
853
  });
854
+ if (repoInfo) {
855
+ const repoDir = getRepoCacheDir(repoInfo.owner, repoInfo.repo);
856
+ if (existsSync(repoDir)) rmSync(repoDir, {
857
+ recursive: true,
858
+ force: true
859
+ });
860
+ }
853
861
  }
854
- function linkAllReferences(skillDir, packageName, cwd, version, docsType, extraPackages, features) {
862
+ function linkAllReferences(skillDir, packageName, cwd, version, docsType, extraPackages, features, repoInfo) {
855
863
  const f = features ?? readConfig().features ?? defaultFeatures;
856
864
  try {
857
865
  linkPkg(skillDir, packageName, cwd, version);
858
866
  linkPkgNamed(skillDir, packageName, cwd, version);
859
867
  if (!hasShippedDocs(packageName, cwd, version) && docsType !== "readme") linkCachedDir(skillDir, packageName, version, "docs");
860
- if (f.issues) linkCachedDir(skillDir, packageName, version, "issues");
861
- if (f.discussions) linkCachedDir(skillDir, packageName, version, "discussions");
862
- if (f.releases) linkCachedDir(skillDir, packageName, version, "releases");
868
+ if (f.issues) if (repoInfo) linkRepoCachedDir(skillDir, repoInfo.owner, repoInfo.repo, "issues");
869
+ else linkCachedDir(skillDir, packageName, version, "issues");
870
+ if (f.discussions) if (repoInfo) linkRepoCachedDir(skillDir, repoInfo.owner, repoInfo.repo, "discussions");
871
+ else linkCachedDir(skillDir, packageName, version, "discussions");
872
+ if (f.releases) if (repoInfo) linkRepoCachedDir(skillDir, repoInfo.owner, repoInfo.repo, "releases");
873
+ else linkCachedDir(skillDir, packageName, version, "releases");
863
874
  linkCachedDir(skillDir, packageName, version, "sections");
864
875
  if (extraPackages) {
865
876
  for (const pkg of extraPackages) if (pkg.name !== packageName) linkPkgNamed(skillDir, pkg.name, cwd, pkg.version);
@@ -1014,6 +1025,27 @@ async function fetchAndCacheResources(opts) {
1014
1025
  }
1015
1026
  }
1016
1027
  }
1028
+ if (resolved.crawlUrl && cachedDocs.length === 0) {
1029
+ onProgress("Crawling website");
1030
+ const crawledDocs = await fetchCrawledDocs(resolved.crawlUrl, onProgress).catch(() => []);
1031
+ if (crawledDocs.length > 0) {
1032
+ for (const doc of crawledDocs) {
1033
+ cachedDocs.push(doc);
1034
+ docsToIndex.push({
1035
+ id: doc.path,
1036
+ content: doc.content,
1037
+ metadata: {
1038
+ package: packageName,
1039
+ source: doc.path,
1040
+ type: "doc"
1041
+ }
1042
+ });
1043
+ }
1044
+ docSource = resolved.crawlUrl;
1045
+ docsType = "docs";
1046
+ writeToCache(packageName, version, cachedDocs);
1047
+ }
1048
+ }
1017
1049
  if (resolved.llmsUrl && cachedDocs.length === 0) {
1018
1050
  onProgress("Fetching llms.txt");
1019
1051
  const llmsContent = await fetchLlmsTxt(resolved.llmsUrl);
@@ -1050,6 +1082,28 @@ async function fetchAndCacheResources(opts) {
1050
1082
  writeToCache(packageName, version, cachedDocs);
1051
1083
  }
1052
1084
  }
1085
+ if (resolved.docsUrl && !cachedDocs.some((d) => d.path.startsWith("docs/"))) {
1086
+ const crawlPattern = resolved.crawlUrl || toCrawlPattern(resolved.docsUrl);
1087
+ onProgress("Crawling docs site");
1088
+ const crawledDocs = await fetchCrawledDocs(crawlPattern, onProgress).catch(() => []);
1089
+ if (crawledDocs.length > 0) {
1090
+ for (const doc of crawledDocs) {
1091
+ cachedDocs.push(doc);
1092
+ docsToIndex.push({
1093
+ id: doc.path,
1094
+ content: doc.content,
1095
+ metadata: {
1096
+ package: packageName,
1097
+ source: doc.path,
1098
+ type: "doc"
1099
+ }
1100
+ });
1101
+ }
1102
+ docSource = crawlPattern;
1103
+ docsType = "docs";
1104
+ writeToCache(packageName, version, cachedDocs);
1105
+ }
1106
+ }
1053
1107
  if (resolved.readmeUrl && cachedDocs.length === 0) {
1054
1108
  onProgress("Fetching README");
1055
1109
  const content = await fetchReadmeContent(resolved.readmeUrl);
@@ -1104,125 +1158,125 @@ async function fetchAndCacheResources(opts) {
1104
1158
  }
1105
1159
  }
1106
1160
  }
1161
+ const gh = resolved.repoUrl ? parseGitHubUrl(resolved.repoUrl) : null;
1162
+ const repoInfo = gh ? {
1163
+ owner: gh.owner,
1164
+ repo: gh.repo
1165
+ } : void 0;
1166
+ const repoCacheDir = repoInfo ? getRepoCacheDir(repoInfo.owner, repoInfo.repo) : null;
1107
1167
  const cacheDir = getCacheDir(packageName, version);
1108
- const issuesDir = join(cacheDir, "issues");
1109
- if (features.issues && resolved.repoUrl && isGhAvailable() && !existsSync(issuesDir)) {
1110
- const gh = parseGitHubUrl(resolved.repoUrl);
1111
- if (gh) {
1112
- onProgress("Fetching issues via GitHub API");
1113
- const issues = await fetchGitHubIssues(gh.owner, gh.repo, 30, resolved.releasedAt, opts.from).catch(() => []);
1114
- if (issues.length > 0) {
1115
- onProgress(`Caching ${issues.length} issues`);
1116
- writeToCache(packageName, version, issues.map((issue) => ({
1117
- path: `issues/issue-${issue.number}.md`,
1118
- content: formatIssueAsMarkdown(issue)
1119
- })));
1120
- writeToCache(packageName, version, [{
1121
- path: "issues/_INDEX.md",
1122
- content: generateIssueIndex(issues)
1123
- }]);
1124
- for (const issue of issues) docsToIndex.push({
1125
- id: `issue-${issue.number}`,
1126
- content: sanitizeMarkdown(`#${issue.number}: ${issue.title}\n\n${issue.body || ""}`),
1127
- metadata: {
1128
- package: packageName,
1129
- source: `issues/issue-${issue.number}.md`,
1130
- type: "issue",
1131
- number: issue.number
1132
- }
1133
- });
1134
- }
1168
+ const issuesDir = repoCacheDir ? join(repoCacheDir, "issues") : join(cacheDir, "issues");
1169
+ const discussionsDir = repoCacheDir ? join(repoCacheDir, "discussions") : join(cacheDir, "discussions");
1170
+ const releasesPath = repoCacheDir ? join(repoCacheDir, "releases") : join(cacheDir, "releases");
1171
+ if (features.issues && gh && isGhAvailable() && !existsSync(issuesDir)) {
1172
+ onProgress("Fetching issues via GitHub API");
1173
+ const issues = await fetchGitHubIssues(gh.owner, gh.repo, 30, resolved.releasedAt, opts.from).catch(() => []);
1174
+ if (issues.length > 0) {
1175
+ onProgress(`Caching ${issues.length} issues`);
1176
+ const issueDocs = [...issues.map((issue) => ({
1177
+ path: `issues/issue-${issue.number}.md`,
1178
+ content: formatIssueAsMarkdown(issue)
1179
+ })), {
1180
+ path: "issues/_INDEX.md",
1181
+ content: generateIssueIndex(issues)
1182
+ }];
1183
+ if (repoInfo) writeToRepoCache(repoInfo.owner, repoInfo.repo, issueDocs);
1184
+ else writeToCache(packageName, version, issueDocs);
1185
+ for (const issue of issues) docsToIndex.push({
1186
+ id: `issue-${issue.number}`,
1187
+ content: sanitizeMarkdown(`#${issue.number}: ${issue.title}\n\n${issue.body || ""}`),
1188
+ metadata: {
1189
+ package: packageName,
1190
+ source: `issues/issue-${issue.number}.md`,
1191
+ type: "issue",
1192
+ number: issue.number
1193
+ }
1194
+ });
1135
1195
  }
1136
1196
  }
1137
- const discussionsDir = join(cacheDir, "discussions");
1138
- if (features.discussions && resolved.repoUrl && isGhAvailable() && !existsSync(discussionsDir)) {
1139
- const gh = parseGitHubUrl(resolved.repoUrl);
1140
- if (gh) {
1141
- onProgress("Fetching discussions via GitHub API");
1142
- const discussions = await fetchGitHubDiscussions(gh.owner, gh.repo, 20, resolved.releasedAt, opts.from).catch(() => []);
1143
- if (discussions.length > 0) {
1144
- onProgress(`Caching ${discussions.length} discussions`);
1145
- writeToCache(packageName, version, discussions.map((d) => ({
1146
- path: `discussions/discussion-${d.number}.md`,
1147
- content: formatDiscussionAsMarkdown(d)
1148
- })));
1149
- writeToCache(packageName, version, [{
1150
- path: "discussions/_INDEX.md",
1151
- content: generateDiscussionIndex(discussions)
1152
- }]);
1153
- for (const d of discussions) docsToIndex.push({
1154
- id: `discussion-${d.number}`,
1155
- content: sanitizeMarkdown(`#${d.number}: ${d.title}\n\n${d.body || ""}`),
1156
- metadata: {
1157
- package: packageName,
1158
- source: `discussions/discussion-${d.number}.md`,
1159
- type: "discussion",
1160
- number: d.number
1161
- }
1162
- });
1163
- }
1197
+ if (features.discussions && gh && isGhAvailable() && !existsSync(discussionsDir)) {
1198
+ onProgress("Fetching discussions via GitHub API");
1199
+ const discussions = await fetchGitHubDiscussions(gh.owner, gh.repo, 20, resolved.releasedAt, opts.from).catch(() => []);
1200
+ if (discussions.length > 0) {
1201
+ onProgress(`Caching ${discussions.length} discussions`);
1202
+ const discussionDocs = [...discussions.map((d) => ({
1203
+ path: `discussions/discussion-${d.number}.md`,
1204
+ content: formatDiscussionAsMarkdown(d)
1205
+ })), {
1206
+ path: "discussions/_INDEX.md",
1207
+ content: generateDiscussionIndex(discussions)
1208
+ }];
1209
+ if (repoInfo) writeToRepoCache(repoInfo.owner, repoInfo.repo, discussionDocs);
1210
+ else writeToCache(packageName, version, discussionDocs);
1211
+ for (const d of discussions) docsToIndex.push({
1212
+ id: `discussion-${d.number}`,
1213
+ content: sanitizeMarkdown(`#${d.number}: ${d.title}\n\n${d.body || ""}`),
1214
+ metadata: {
1215
+ package: packageName,
1216
+ source: `discussions/discussion-${d.number}.md`,
1217
+ type: "discussion",
1218
+ number: d.number
1219
+ }
1220
+ });
1164
1221
  }
1165
1222
  }
1166
- const releasesPath = join(cacheDir, "releases");
1167
- if (features.releases && resolved.repoUrl && isGhAvailable() && !existsSync(releasesPath)) {
1168
- const gh = parseGitHubUrl(resolved.repoUrl);
1169
- if (gh) {
1170
- onProgress("Fetching releases via GitHub API");
1171
- const changelogRef = isPrerelease(version) ? getPrereleaseChangelogRef(packageName) : void 0;
1172
- const releaseDocs = await fetchReleaseNotes(gh.owner, gh.repo, version, resolved.gitRef, packageName, opts.from, changelogRef).catch(() => []);
1173
- let blogDocs = [];
1174
- if (getBlogPreset(packageName)) {
1175
- onProgress("Fetching blog release notes");
1176
- blogDocs = await fetchBlogReleases(packageName, version).catch(() => []);
1177
- }
1178
- const allDocs = [...releaseDocs, ...blogDocs];
1179
- const blogEntries = blogDocs.filter((d) => !d.path.endsWith("_INDEX.md")).map((d) => {
1180
- const versionMatch = d.path.match(/blog-(.+)\.md$/);
1181
- const fm = parseFrontmatter(d.content);
1182
- return {
1183
- version: versionMatch?.[1] ?? "",
1184
- title: fm.title ?? `Release ${versionMatch?.[1]}`,
1185
- date: fm.date ?? ""
1186
- };
1187
- }).filter((b) => b.version);
1188
- const ghReleases = releaseDocs.filter((d) => d.path.startsWith("releases/") && !d.path.endsWith("CHANGELOG.md")).map((d) => {
1189
- const fm = parseFrontmatter(d.content);
1190
- const tag = fm.tag ?? "";
1191
- const name = fm.name ?? tag;
1192
- const published = fm.published ?? "";
1193
- return {
1194
- id: 0,
1195
- tag,
1196
- name,
1197
- prerelease: false,
1198
- createdAt: published,
1199
- publishedAt: published,
1200
- markdown: ""
1201
- };
1202
- }).filter((r) => r.tag);
1203
- const hasChangelog = allDocs.some((d) => d.path === "releases/CHANGELOG.md");
1204
- if (ghReleases.length > 0 || blogEntries.length > 0) allDocs.push({
1205
- path: "releases/_INDEX.md",
1206
- content: generateReleaseIndex({
1207
- releases: ghReleases,
1208
- packageName,
1209
- blogReleases: blogEntries,
1210
- hasChangelog
1211
- })
1223
+ if (features.releases && gh && isGhAvailable() && !existsSync(releasesPath)) {
1224
+ onProgress("Fetching releases via GitHub API");
1225
+ const changelogRef = isPrerelease(version) ? getPrereleaseChangelogRef(packageName) : void 0;
1226
+ const releaseDocs = await fetchReleaseNotes(gh.owner, gh.repo, version, resolved.gitRef, packageName, opts.from, changelogRef).catch(() => []);
1227
+ let blogDocs = [];
1228
+ if (getBlogPreset(packageName)) {
1229
+ onProgress("Fetching blog release notes");
1230
+ blogDocs = await fetchBlogReleases(packageName, version).catch(() => []);
1231
+ }
1232
+ const allDocs = [...releaseDocs, ...blogDocs];
1233
+ const blogEntries = blogDocs.filter((d) => !d.path.endsWith("_INDEX.md")).map((d) => {
1234
+ const versionMatch = d.path.match(/blog-(.+)\.md$/);
1235
+ const fm = parseFrontmatter(d.content);
1236
+ return {
1237
+ version: versionMatch?.[1] ?? "",
1238
+ title: fm.title ?? `Release ${versionMatch?.[1]}`,
1239
+ date: fm.date ?? ""
1240
+ };
1241
+ }).filter((b) => b.version);
1242
+ const ghReleases = releaseDocs.filter((d) => d.path.startsWith("releases/") && !d.path.endsWith("CHANGELOG.md")).map((d) => {
1243
+ const fm = parseFrontmatter(d.content);
1244
+ const tag = fm.tag ?? "";
1245
+ const name = fm.name ?? tag;
1246
+ const published = fm.published ?? "";
1247
+ return {
1248
+ id: 0,
1249
+ tag,
1250
+ name,
1251
+ prerelease: false,
1252
+ createdAt: published,
1253
+ publishedAt: published,
1254
+ markdown: ""
1255
+ };
1256
+ }).filter((r) => r.tag);
1257
+ const hasChangelog = allDocs.some((d) => d.path === "releases/CHANGELOG.md");
1258
+ if (ghReleases.length > 0 || blogEntries.length > 0) allDocs.push({
1259
+ path: "releases/_INDEX.md",
1260
+ content: generateReleaseIndex({
1261
+ releases: ghReleases,
1262
+ packageName,
1263
+ blogReleases: blogEntries,
1264
+ hasChangelog
1265
+ })
1266
+ });
1267
+ if (allDocs.length > 0) {
1268
+ onProgress(`Caching ${allDocs.length} releases`);
1269
+ if (repoInfo) writeToRepoCache(repoInfo.owner, repoInfo.repo, allDocs);
1270
+ else writeToCache(packageName, version, allDocs);
1271
+ for (const doc of allDocs) docsToIndex.push({
1272
+ id: doc.path,
1273
+ content: doc.content,
1274
+ metadata: {
1275
+ package: packageName,
1276
+ source: doc.path,
1277
+ type: "release"
1278
+ }
1212
1279
  });
1213
- if (allDocs.length > 0) {
1214
- onProgress(`Caching ${allDocs.length} releases`);
1215
- writeToCache(packageName, version, allDocs);
1216
- for (const doc of allDocs) docsToIndex.push({
1217
- id: doc.path,
1218
- content: doc.content,
1219
- metadata: {
1220
- package: packageName,
1221
- source: doc.path,
1222
- type: "release"
1223
- }
1224
- });
1225
- }
1226
1280
  }
1227
1281
  }
1228
1282
  return {
@@ -1232,7 +1286,8 @@ async function fetchAndCacheResources(opts) {
1232
1286
  hasIssues: features.issues && existsSync(issuesDir),
1233
1287
  hasDiscussions: features.discussions && existsSync(discussionsDir),
1234
1288
  hasReleases: features.releases && existsSync(releasesPath),
1235
- warnings
1289
+ warnings,
1290
+ repoInfo
1236
1291
  };
1237
1292
  }
1238
1293
  async function indexResources(opts) {
@@ -1268,14 +1323,15 @@ async function indexResources(opts) {
1268
1323
  }
1269
1324
  });
1270
1325
  }
1271
- function ejectReferences(skillDir, packageName, cwd, version, docsType, features) {
1326
+ function ejectReferences(skillDir, packageName, cwd, version, docsType, features, repoInfo) {
1272
1327
  const f = features ?? readConfig().features ?? defaultFeatures;
1273
1328
  const cacheDir = getCacheDir(packageName, version);
1274
1329
  const refsDir = join(skillDir, "references");
1330
+ const repoDir = repoInfo ? getRepoCacheDir(repoInfo.owner, repoInfo.repo) : cacheDir;
1275
1331
  if (!hasShippedDocs(packageName, cwd, version) && docsType !== "readme") copyCachedSubdir(cacheDir, refsDir, "docs");
1276
- if (f.issues) copyCachedSubdir(cacheDir, refsDir, "issues");
1277
- if (f.discussions) copyCachedSubdir(cacheDir, refsDir, "discussions");
1278
- if (f.releases) copyCachedSubdir(cacheDir, refsDir, "releases");
1332
+ if (f.issues) copyCachedSubdir(repoDir, refsDir, "issues");
1333
+ if (f.discussions) copyCachedSubdir(repoDir, refsDir, "discussions");
1334
+ if (f.releases) copyCachedSubdir(repoDir, refsDir, "releases");
1279
1335
  }
1280
1336
  function copyCachedSubdir(cacheDir, refsDir, subdir) {
1281
1337
  const srcDir = join(cacheDir, subdir);
@@ -1374,7 +1430,7 @@ async function selectModel(skipPrompt) {
1374
1430
  }
1375
1431
  const DEFAULT_SECTIONS = ["best-practices", "api-changes"];
1376
1432
  async function selectSkillSections(message = "Generate SKILL.md with LLM") {
1377
- p.log.info("More sections = less budget each. Fewer sections = deeper coverage.");
1433
+ p.log.info("Budgets adapt to package release density.");
1378
1434
  const selected = await p.multiselect({
1379
1435
  message,
1380
1436
  options: [
@@ -1411,10 +1467,10 @@ async function selectSkillSections(message = "Generate SKILL.md with LLM") {
1411
1467
  const budgetLines = [];
1412
1468
  for (const s of sections) switch (s) {
1413
1469
  case "api-changes":
1414
- budgetLines.push(` API changes ≤${maxLines(50, 80, n)} lines, ${maxItems(6, 12, n)} items`);
1470
+ budgetLines.push(` API changes ${maxItems(6, 12, n)}–${maxItems(6, Math.round(12 * 1.6), n)} items (adapts to release churn)`);
1415
1471
  break;
1416
1472
  case "best-practices":
1417
- budgetLines.push(` Best practices ≤${maxLines(80, 150, n)} lines, ${maxItems(4, 10, n)} items`);
1473
+ budgetLines.push(` Best practices ${maxItems(4, 10, n)}–${maxItems(4, Math.round(10 * 1.3), n)} items`);
1418
1474
  break;
1419
1475
  case "custom":
1420
1476
  budgetLines.push(` Custom ≤${maxLines(50, 80, n)} lines`);
@@ -1909,7 +1965,7 @@ async function syncBaseSkill(packageSpec, config, cwd, update) {
1909
1965
  if (useCache) update(packageName, "downloading", "Using cache", versionKey);
1910
1966
  else update(packageName, "downloading", config.force ? "Re-fetching docs..." : "Fetching docs...", versionKey);
1911
1967
  const baseDir = resolveBaseDir(cwd, config.agent, config.global);
1912
- const skillDirName = computeSkillDirName(packageName, resolved.repoUrl);
1968
+ const skillDirName = computeSkillDirName(packageName);
1913
1969
  const skillDir = join(baseDir, skillDirName);
1914
1970
  mkdirSync(skillDir, { recursive: true });
1915
1971
  const features = readConfig().features ?? defaultFeatures;
@@ -1922,7 +1978,7 @@ async function syncBaseSkill(packageSpec, config, cwd, update) {
1922
1978
  onProgress: (msg) => update(packageName, "downloading", msg, versionKey)
1923
1979
  });
1924
1980
  update(packageName, "downloading", "Linking references...", versionKey);
1925
- linkAllReferences(skillDir, packageName, cwd, version, resources.docsType, void 0, features);
1981
+ linkAllReferences(skillDir, packageName, cwd, version, resources.docsType, void 0, features, resources.repoInfo);
1926
1982
  if (features.search) {
1927
1983
  update(packageName, "embedding", "Indexing docs", versionKey);
1928
1984
  await indexResources({
@@ -2307,7 +2363,7 @@ async function syncSinglePackage(packageSpec, config) {
2307
2363
  spin.stop(`Resolved ${packageName}@${useCache ? versionKey : version}${config.force ? " (force)" : useCache ? " (cached)" : ""}`);
2308
2364
  ensureCacheDir();
2309
2365
  const baseDir = resolveBaseDir(cwd, config.agent, config.global);
2310
- const skillDirName = config.name ? sanitizeName(config.name) : computeSkillDirName(packageName, resolved.repoUrl);
2366
+ const skillDirName = config.name ? sanitizeName(config.name) : computeSkillDirName(packageName);
2311
2367
  const skillDir = config.eject ? typeof config.eject === "string" ? join(resolve(cwd, config.eject), skillDirName) : join(cwd, "skills", skillDirName) : join(baseDir, skillDirName);
2312
2368
  mkdirSync(skillDir, { recursive: true });
2313
2369
  const existingLock = config.eject ? void 0 : readLock(baseDir)?.skills[skillDirName];
@@ -2372,7 +2428,7 @@ async function syncSinglePackage(packageSpec, config) {
2372
2428
  if (resources.hasReleases) resParts.push("releases");
2373
2429
  resSpin.stop(`Fetched ${resParts.length > 0 ? resParts.join(", ") : "resources"}`);
2374
2430
  for (const w of resources.warnings) p.log.warn(`\x1B[33m${w}\x1B[0m`);
2375
- linkAllReferences(skillDir, packageName, cwd, version, resources.docsType, void 0, features);
2431
+ linkAllReferences(skillDir, packageName, cwd, version, resources.docsType, void 0, features, resources.repoInfo);
2376
2432
  if (features.search && !config.eject) {
2377
2433
  const idxSpin = timedSpinner();
2378
2434
  idxSpin.start("Creating search index");
@@ -2460,7 +2516,7 @@ async function syncSinglePackage(packageSpec, config) {
2460
2516
  recursive: true,
2461
2517
  force: true
2462
2518
  });
2463
- ejectReferences(skillDir, packageName, cwd, version, resources.docsType, features);
2519
+ ejectReferences(skillDir, packageName, cwd, version, resources.docsType, features, resources.repoInfo);
2464
2520
  }
2465
2521
  if (!isEject) {
2466
2522
  const shared = !config.global && getSharedSkillsDir(cwd);
@@ -2748,21 +2804,26 @@ async function installCommand(opts) {
2748
2804
  if (existsSync(docsLink)) unlinkSync(docsLink);
2749
2805
  if (existsSync(cachedDocs)) symlinkSync(cachedDocs, docsLink, "junction");
2750
2806
  }
2807
+ const repoGh = info.repo ? parseGitHubUrl(`https://github.com/${info.repo}`) : null;
2808
+ const repoCachePath = repoGh ? getRepoCacheDir(repoGh.owner, repoGh.repo) : null;
2751
2809
  if (features.issues) {
2752
2810
  const issuesLink = join(referencesPath, "issues");
2753
- const cachedIssues = join(globalCachePath, "issues");
2811
+ const repoIssues = repoCachePath ? join(repoCachePath, "issues") : null;
2812
+ const cachedIssues = repoIssues && existsSync(repoIssues) ? repoIssues : join(globalCachePath, "issues");
2754
2813
  if (existsSync(issuesLink)) unlinkSync(issuesLink);
2755
2814
  if (existsSync(cachedIssues)) symlinkSync(cachedIssues, issuesLink, "junction");
2756
2815
  }
2757
2816
  if (features.discussions) {
2758
2817
  const discussionsLink = join(referencesPath, "discussions");
2759
- const cachedDiscussions = join(globalCachePath, "discussions");
2818
+ const repoDiscussions = repoCachePath ? join(repoCachePath, "discussions") : null;
2819
+ const cachedDiscussions = repoDiscussions && existsSync(repoDiscussions) ? repoDiscussions : join(globalCachePath, "discussions");
2760
2820
  if (existsSync(discussionsLink)) unlinkSync(discussionsLink);
2761
2821
  if (existsSync(cachedDiscussions)) symlinkSync(cachedDiscussions, discussionsLink, "junction");
2762
2822
  }
2763
2823
  if (features.releases) {
2764
2824
  const releasesLink = join(referencesPath, "releases");
2765
- const cachedReleases = join(globalCachePath, "releases");
2825
+ const repoReleases = repoCachePath ? join(repoCachePath, "releases") : null;
2826
+ const cachedReleases = repoReleases && existsSync(repoReleases) ? repoReleases : join(globalCachePath, "releases");
2766
2827
  if (existsSync(releasesLink)) unlinkSync(releasesLink);
2767
2828
  if (existsSync(cachedReleases)) symlinkSync(cachedReleases, releasesLink, "junction");
2768
2829
  }