skilld 1.7.4 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (156) hide show
  1. package/dist/_chunks/add.mjs +66 -0
  2. package/dist/_chunks/add.mjs.map +1 -0
  3. package/dist/_chunks/agent-prompt.mjs +88 -0
  4. package/dist/_chunks/agent-prompt.mjs.map +1 -0
  5. package/dist/_chunks/agent.mjs +81 -57
  6. package/dist/_chunks/agent.mjs.map +1 -1
  7. package/dist/_chunks/args.mjs +42 -0
  8. package/dist/_chunks/args.mjs.map +1 -0
  9. package/dist/_chunks/assemble.mjs +10 -7
  10. package/dist/_chunks/assemble.mjs.map +1 -1
  11. package/dist/_chunks/author.mjs +33 -17
  12. package/dist/_chunks/author.mjs.map +1 -1
  13. package/dist/_chunks/cache.mjs +143 -183
  14. package/dist/_chunks/cache.mjs.map +1 -1
  15. package/dist/_chunks/cache2.mjs +7 -6
  16. package/dist/_chunks/cache2.mjs.map +1 -1
  17. package/dist/_chunks/client.mjs +117 -0
  18. package/dist/_chunks/client.mjs.map +1 -0
  19. package/dist/_chunks/core.mjs +5 -5
  20. package/dist/_chunks/detect.mjs +53 -43
  21. package/dist/_chunks/detect.mjs.map +1 -1
  22. package/dist/_chunks/eject.mjs +69 -0
  23. package/dist/_chunks/eject.mjs.map +1 -0
  24. package/dist/_chunks/embedding-cache2.mjs +1 -1
  25. package/dist/_chunks/env.mjs +19 -0
  26. package/dist/_chunks/env.mjs.map +1 -0
  27. package/dist/_chunks/install-many.mjs +376 -0
  28. package/dist/_chunks/install-many.mjs.map +1 -0
  29. package/dist/_chunks/install.mjs +81 -326
  30. package/dist/_chunks/install.mjs.map +1 -1
  31. package/dist/_chunks/intro.mjs +63 -0
  32. package/dist/_chunks/intro.mjs.map +1 -0
  33. package/dist/_chunks/list.mjs +2 -2
  34. package/dist/_chunks/list.mjs.map +1 -1
  35. package/dist/_chunks/lockfile.mjs +3 -2
  36. package/dist/_chunks/lockfile.mjs.map +1 -1
  37. package/dist/_chunks/login.mjs +233 -0
  38. package/dist/_chunks/login.mjs.map +1 -0
  39. package/dist/_chunks/logout.mjs +27 -0
  40. package/dist/_chunks/logout.mjs.map +1 -0
  41. package/dist/_chunks/map.mjs +11 -0
  42. package/dist/_chunks/map.mjs.map +1 -0
  43. package/dist/_chunks/markdown.mjs +79 -54
  44. package/dist/_chunks/markdown.mjs.map +1 -1
  45. package/dist/_chunks/menu.mjs +33 -0
  46. package/dist/_chunks/menu.mjs.map +1 -0
  47. package/dist/_chunks/model-picker.mjs +61 -0
  48. package/dist/_chunks/model-picker.mjs.map +1 -0
  49. package/dist/_chunks/monorepo.mjs +4 -2
  50. package/dist/_chunks/monorepo.mjs.map +1 -1
  51. package/dist/_chunks/package-json.mjs.map +1 -1
  52. package/dist/_chunks/paths.mjs +3 -5
  53. package/dist/_chunks/paths.mjs.map +1 -1
  54. package/dist/_chunks/{sync-pipeline.mjs → pipeline.mjs} +346 -313
  55. package/dist/_chunks/pipeline.mjs.map +1 -0
  56. package/dist/_chunks/pool2.mjs +1 -1
  57. package/dist/_chunks/portable.mjs +151 -0
  58. package/dist/_chunks/portable.mjs.map +1 -0
  59. package/dist/_chunks/prepare-hook.mjs +2 -0
  60. package/dist/_chunks/prepare-hook2.mjs +61 -0
  61. package/dist/_chunks/prepare-hook2.mjs.map +1 -0
  62. package/dist/_chunks/prepare.mjs +47 -3
  63. package/dist/_chunks/prepare.mjs.map +1 -1
  64. package/dist/_chunks/prepare2.mjs +7 -6
  65. package/dist/_chunks/prepare2.mjs.map +1 -1
  66. package/dist/_chunks/prompts.mjs +484 -74
  67. package/dist/_chunks/prompts.mjs.map +1 -1
  68. package/dist/_chunks/pull.mjs +219 -0
  69. package/dist/_chunks/pull.mjs.map +1 -0
  70. package/dist/_chunks/regex.mjs +19 -0
  71. package/dist/_chunks/regex.mjs.map +1 -0
  72. package/dist/_chunks/retriv.mjs +2 -171
  73. package/dist/_chunks/retriv2.mjs +159 -0
  74. package/dist/_chunks/retriv2.mjs.map +1 -0
  75. package/dist/_chunks/sanitize.mjs +12 -9
  76. package/dist/_chunks/sanitize.mjs.map +1 -1
  77. package/dist/_chunks/search-helpers.mjs +8 -6
  78. package/dist/_chunks/search-helpers.mjs.map +1 -1
  79. package/dist/_chunks/search-interactive.mjs +23 -20
  80. package/dist/_chunks/search-interactive.mjs.map +1 -1
  81. package/dist/_chunks/search.mjs +3 -3
  82. package/dist/_chunks/search.mjs.map +1 -1
  83. package/dist/_chunks/semver.mjs +2755 -1
  84. package/dist/_chunks/semver.mjs.map +1 -1
  85. package/dist/_chunks/skill-installer2.mjs +10 -11
  86. package/dist/_chunks/skill-installer2.mjs.map +1 -1
  87. package/dist/_chunks/skills.mjs +6 -7
  88. package/dist/_chunks/skills.mjs.map +1 -1
  89. package/dist/_chunks/store.mjs +107 -0
  90. package/dist/_chunks/store.mjs.map +1 -0
  91. package/dist/_chunks/sync.mjs +411 -910
  92. package/dist/_chunks/sync.mjs.map +1 -1
  93. package/dist/_chunks/sync2.mjs +2 -5
  94. package/dist/_chunks/telemetry.mjs +26 -0
  95. package/dist/_chunks/telemetry.mjs.map +1 -0
  96. package/dist/_chunks/uninstall.mjs +12 -9
  97. package/dist/_chunks/uninstall.mjs.map +1 -1
  98. package/dist/_chunks/update.mjs +171 -0
  99. package/dist/_chunks/update.mjs.map +1 -0
  100. package/dist/_chunks/upload.mjs +3 -3
  101. package/dist/_chunks/validate.mjs +1 -1
  102. package/dist/_chunks/version.mjs +16 -17
  103. package/dist/_chunks/version.mjs.map +1 -1
  104. package/dist/_chunks/whoami.mjs +21 -0
  105. package/dist/_chunks/whoami.mjs.map +1 -0
  106. package/dist/_chunks/wizard.mjs +2 -190
  107. package/dist/_chunks/wizard2.mjs +200 -0
  108. package/dist/_chunks/wizard2.mjs.map +1 -0
  109. package/dist/cli.mjs +72 -53
  110. package/dist/cli.mjs.map +1 -1
  111. package/dist/prepare.mjs +4 -3
  112. package/dist/prepare.mjs.map +1 -1
  113. package/dist/retriv/worker.d.mts +5 -1
  114. package/dist/retriv/worker.d.mts.map +1 -1
  115. package/dist/retriv/worker.mjs +1 -1
  116. package/package.json +19 -28
  117. package/dist/_chunks/author-group.mjs +0 -17
  118. package/dist/_chunks/author-group.mjs.map +0 -1
  119. package/dist/_chunks/cli-helpers.mjs +0 -335
  120. package/dist/_chunks/cli-helpers.mjs.map +0 -1
  121. package/dist/_chunks/cli-helpers2.mjs +0 -2
  122. package/dist/_chunks/index.d.mts +0 -344
  123. package/dist/_chunks/index.d.mts.map +0 -1
  124. package/dist/_chunks/index2.d.mts +0 -279
  125. package/dist/_chunks/index2.d.mts.map +0 -1
  126. package/dist/_chunks/index3.d.mts +0 -44
  127. package/dist/_chunks/index3.d.mts.map +0 -1
  128. package/dist/_chunks/index4.d.mts +0 -553
  129. package/dist/_chunks/index4.d.mts.map +0 -1
  130. package/dist/_chunks/package-registry.mjs +0 -465
  131. package/dist/_chunks/package-registry.mjs.map +0 -1
  132. package/dist/_chunks/retriv.mjs.map +0 -1
  133. package/dist/_chunks/setup.mjs +0 -17
  134. package/dist/_chunks/setup.mjs.map +0 -1
  135. package/dist/_chunks/sources.mjs +0 -2654
  136. package/dist/_chunks/sources.mjs.map +0 -1
  137. package/dist/_chunks/sync-pipeline.mjs.map +0 -1
  138. package/dist/_chunks/sync-registry.mjs +0 -65
  139. package/dist/_chunks/sync-registry.mjs.map +0 -1
  140. package/dist/_chunks/types.d.mts +0 -76
  141. package/dist/_chunks/types.d.mts.map +0 -1
  142. package/dist/_chunks/types2.d.mts +0 -88
  143. package/dist/_chunks/types2.d.mts.map +0 -1
  144. package/dist/_chunks/wizard.mjs.map +0 -1
  145. package/dist/agent/index.d.mts +0 -2
  146. package/dist/agent/index.mjs +0 -4
  147. package/dist/cache/index.d.mts +0 -2
  148. package/dist/cache/index.mjs +0 -5
  149. package/dist/index.d.mts +0 -6
  150. package/dist/index.mjs +0 -6
  151. package/dist/retriv/index.d.mts +0 -3
  152. package/dist/retriv/index.mjs +0 -2
  153. package/dist/sources/index.d.mts +0 -3
  154. package/dist/sources/index.mjs +0 -3
  155. package/dist/types.d.mts +0 -4
  156. package/dist/types.mjs +0 -1
@@ -1,20 +1,19 @@
1
- import { l as getPackageDbPath, p as skillInternalDir, u as getRepoCacheDir } from "./paths.mjs";
2
- import { L as updateConfig, P as readConfig, b as writeToRepoCache, h as listReferenceFiles, k as defaultFeatures, t as createReferenceCache, y as writeToCache } from "./cache.mjs";
3
- import { t as getCacheDir } from "./version.mjs";
4
- import { r as resolvePkgDir } from "./prepare.mjs";
1
+ import { a as getModelName, i as getModelLabel, o as createToolProgress, r as getAvailableModels, t as optimizeDocs } from "./agent.mjs";
2
+ import { C as SECTION_OUTPUT_FILES, E as getBlogPreset, S as SECTION_MERGE_ORDER, T as maxLines, _ as buildAllSectionPrompts, k as getPrereleaseChangelogRef, t as writeGeneratedSkillMd, w as maxItems, x as wrapSection } from "./prompts.mjs";
3
+ import { d as getRepoCacheDir, m as skillInternalDir, u as getPackageDbPath } from "./paths.mjs";
5
4
  import { n as sanitizeMarkdown } from "./sanitize.mjs";
5
+ import { a as resolvePkgDir, s as getCacheDir } from "./prepare.mjs";
6
+ import { a as writeToRepoCache, d as readConfig, i as listReferenceFiles, m as updateConfig, o as defaultFeatures, t as createReferenceCache } from "./cache.mjs";
7
+ import { t as isInteractive } from "./env.mjs";
8
+ import { r as pickModel, t as NO_MODELS_MESSAGE } from "./model-picker.mjs";
9
+ import { A as fetchGitHubIssues, B as fetchBlogReleases, C as fetchCrawledDocs, D as downloadLlmsDocs, F as filterFrameworkDocs, H as generateReleaseIndex, I as isShallowGitDocs, M as generateIssueIndex, N as isGhAvailable, O as fetchLlmsTxt, P as fetchGitDocs, R as parseGitHubUrl, S as generateDiscussionIndex, T as fetchReadmeContent, U as isPrerelease, V as fetchReleaseNotes, W as fetchGitHubRaw, b as fetchGitHubDiscussions, d as fetchNpmPackage, j as formatIssueAsMarkdown, k as normalizeLlmsLinks, t as semverDiff, v as resolveEntryFiles, w as toCrawlPattern, x as formatDiscussionAsMarkdown, y as generateDocsIndex } from "./semver.mjs";
6
10
  import { i as parseFrontmatter } from "./markdown.mjs";
7
- import { o as listIndexIds, r as createIndex, t as SearchDepsUnavailableError } from "./retriv.mjs";
8
- import { o as getPrereleaseChangelogRef, t as getBlogPreset } from "./package-registry.mjs";
9
- import { $ as fetchReleaseNotes, C as resolveEntryFiles, D as generateDiscussionIndex, E as formatDiscussionAsMarkdown, F as downloadLlmsDocs, H as formatIssueAsMarkdown, J as isShallowGitDocs, K as fetchGitDocs, L as fetchLlmsTxt, N as fetchReadmeContent, O as fetchCrawledDocs, T as fetchGitHubDiscussions, U as generateIssueIndex, V as fetchGitHubIssues, W as isGhAvailable, Z as fetchBlogReleases, at as fetchGitHubRaw, et as generateReleaseIndex, k as toCrawlPattern, q as filterFrameworkDocs, s as fetchNpmPackage, tt as isPrerelease, ut as parseGitHubUrl, w as generateDocsIndex, z as normalizeLlmsLinks } from "./sources.mjs";
10
- import { a as getModelName, i as getModelLabel, o as createToolProgress, r as getAvailableModels, t as optimizeDocs } from "./agent.mjs";
11
- import { D as maxItems, E as SECTION_OUTPUT_FILES, O as maxLines, T as SECTION_MERGE_ORDER, n as writeGeneratedSkillMd, w as wrapSection, y as buildAllSectionPrompts } from "./prompts.mjs";
12
- import { g as pickModel, n as NO_MODELS_MESSAGE, p as isInteractive } from "./cli-helpers.mjs";
13
11
  import { c as readLock, t as buildPackageDirMap } from "./lockfile.mjs";
14
- import { t as semverDiff } from "./semver.mjs";
12
+ import { a as listIndexIds, r as createIndex, t as SearchDepsUnavailableError } from "./retriv2.mjs";
15
13
  import { existsSync, mkdirSync, readdirSync, writeFileSync } from "node:fs";
16
- import { join, relative } from "pathe";
14
+ import { styleText } from "node:util";
17
15
  import * as p from "@clack/prompts";
16
+ import { join, relative } from "pathe";
18
17
  const RATE_LIMIT_RE = /\b429\b|rate.?limit|exhausted.*capacity|quota.*reset/i;
19
18
  async function runSkillEnhancement(ctx, run, onProgress) {
20
19
  const { packageName, cachePackageName, version, skillDir, dirName, resolved, relatedSkills, references, packages, features, overheadLines } = ctx;
@@ -81,8 +80,8 @@ async function enhanceSkillWithLLM(ctx, run) {
81
80
  const costSuffix = costParts.length > 0 ? ` (${costParts.join(", ")})` : "";
82
81
  llmLog.success(`Generated best practices${costSuffix}`);
83
82
  if (debugLogsDir) p.log.info(`Debug logs: ${relative(process.cwd(), debugLogsDir)}`);
84
- if (error) p.log.warn(`\x1B[33mPartial failure: ${error}\x1B[0m`);
85
- if (warnings?.length) for (const w of warnings) p.log.warn(`\x1B[33m${w}\x1B[0m`);
83
+ if (error) p.log.warn(styleText("yellow", `Partial failure: ${error}`));
84
+ if (warnings?.length) for (const w of warnings) p.log.warn(styleText("yellow", w));
86
85
  } else if (error && RATE_LIMIT_RE.test(error)) llmLog.error(`Rate limited by LLM provider. Try again shortly or use a different model via \`skilld config\``);
87
86
  else llmLog.error(`Enhancement failed${error ? `: ${error}` : ""}`);
88
87
  }
@@ -156,7 +155,7 @@ function writePromptFiles(ctx, run) {
156
155
  const relDir = relative(process.cwd(), skillDir);
157
156
  const promptFiles = written.map((s) => `PROMPT_${s}.md`).join(", ");
158
157
  const outputFileList = written.map((s) => SECTION_OUTPUT_FILES[s]).join(", ");
159
- p.log.info(`Prompt files written to ${relDir}/.skilld/\n\x1B[2m\x1B[3m Read each prompt file (${promptFiles}) in ${relDir}/.skilld/, read the\n referenced files, then write your output to the matching file (${outputFileList}).\n When done, run: skilld assemble\x1B[0m`);
158
+ p.log.info(`Prompt files written to ${relDir}/.skilld/\n${styleText(["dim", "italic"], ` Read each prompt file (${promptFiles}) in ${relDir}/.skilld/, read the\n referenced files, then write your output to the matching file (${outputFileList}).\n When done, run: skilld assemble`)}`);
160
159
  }
161
160
  return written;
162
161
  }
@@ -265,7 +264,7 @@ async function selectLlmConfig(presetModel, message, updateCtx) {
265
264
  let defaultModel;
266
265
  if (config.model && available.some((m) => m.id === config.model)) defaultModel = config.model;
267
266
  else {
268
- if (config.model) p.log.warn(`Configured model \x1B[36m${config.model}\x1B[0m is unavailable — using auto-selected fallback`);
267
+ if (config.model) p.log.warn(`Configured model ${styleText("cyan", config.model)} is unavailable — using auto-selected fallback`);
269
268
  defaultModel = available.find((m) => m.recommended)?.id ?? available[0].id;
270
269
  }
271
270
  const defaultModelName = getModelName(defaultModel);
@@ -288,7 +287,7 @@ async function selectLlmConfig(presetModel, message, updateCtx) {
288
287
  }
289
288
  if (updateCtx.wasEnhanced) ageParts.push("LLM-enhanced");
290
289
  const hint = [updateCtx.oldVersion && updateCtx.newVersion ? `${updateCtx.oldVersion} → ${updateCtx.newVersion}` : null, ...ageParts].filter(Boolean).join(" · ");
291
- if (hint) enhanceMessage = `Enhance SKILL.md? \x1B[90m(${hint})\x1B[0m`;
290
+ if (hint) enhanceMessage = `Enhance SKILL.md? ${styleText("gray", `(${hint})`)}`;
292
291
  if (updateCtx.wasEnhanced && isSmallBump) defaultToSkip = true;
293
292
  }
294
293
  const choice = await p.select({
@@ -448,241 +447,374 @@ async function indexResources(opts) {
448
447
  else throw err;
449
448
  }
450
449
  }
451
- async function resolveContentDocs(opts) {
452
- const { packageName, resolved, version, onProgress } = opts;
453
- const docs = [];
454
- const docsToIndex = [];
455
- const warnings = [];
456
- let docSource = resolved.readmeUrl || "readme";
457
- let docsType = "readme";
458
- const isFrameworkDoc = (path) => filterFrameworkDocs([path], packageName).length > 0;
459
- if (resolved.gitDocsUrl && resolved.repoUrl) {
460
- const gh = parseGitHubUrl(resolved.repoUrl);
461
- if (gh) {
462
- const r = await tryGitDocs({
463
- owner: gh.owner,
464
- repo: gh.repo,
465
- version,
466
- packageName,
467
- repoUrl: resolved.repoUrl,
468
- llmsUrl: resolved.llmsUrl,
469
- docsUrl: resolved.docsUrl,
470
- onProgress
471
- });
472
- if (r) {
473
- docs.push(...r.docs);
474
- docsToIndex.push(...r.docsToIndex);
475
- if (r.warning) warnings.push(r.warning);
476
- if (r.kind === "git") {
477
- docSource = r.docSource;
478
- docsType = "docs";
450
+ function defineStep(step) {
451
+ return step;
452
+ }
453
+ async function walkSteps(steps, ctx) {
454
+ for (const step of steps) {
455
+ if (step.canResolve && !step.canResolve(ctx)) continue;
456
+ await step.run(ctx);
457
+ }
458
+ }
459
+ const crawlUrlStep = defineStep({
460
+ id: "crawl-url",
461
+ canResolve: (ctx) => !!ctx.resolved.crawlUrl && ctx.docs.length === 0,
462
+ async run(ctx) {
463
+ const crawlUrl = ctx.resolved.crawlUrl;
464
+ ctx.onProgress("Crawling website");
465
+ const crawled = await fetchCrawledDocs(crawlUrl, ctx.onProgress).catch((err) => {
466
+ ctx.warnings.push(`Crawl failed for ${crawlUrl}: ${err?.message || err}`);
467
+ return [];
468
+ });
469
+ if (crawled.length === 0) ctx.warnings.push(`Crawl returned 0 docs from ${crawlUrl}`);
470
+ let added = 0;
471
+ for (const doc of crawled) {
472
+ if (!ctx.isFrameworkDoc(doc.path)) continue;
473
+ ctx.docs.push(doc);
474
+ ctx.docsToIndex.push({
475
+ id: doc.path,
476
+ content: doc.content,
477
+ metadata: {
478
+ package: ctx.packageName,
479
+ source: doc.path,
480
+ type: "doc"
479
481
  }
480
- }
482
+ });
483
+ added++;
484
+ }
485
+ if (added > 0) {
486
+ ctx.docSource = crawlUrl;
487
+ ctx.docsType = "docs";
481
488
  }
482
489
  }
483
- if (resolved.crawlUrl && docs.length === 0) {
484
- onProgress("Crawling website");
485
- const crawled = await fetchCrawledDocs(resolved.crawlUrl, onProgress).catch((err) => {
486
- warnings.push(`Crawl failed for ${resolved.crawlUrl}: ${err?.message || err}`);
490
+ });
491
+ const docsCrawlStep = defineStep({
492
+ id: "docs-crawl",
493
+ canResolve: (ctx) => !!ctx.resolved.docsUrl && !ctx.docs.some((d) => d.path.startsWith("docs/")),
494
+ async run(ctx) {
495
+ const crawlPattern = ctx.resolved.crawlUrl || toCrawlPattern(ctx.resolved.docsUrl);
496
+ ctx.onProgress("Crawling docs site");
497
+ const maxPages = ctx.resolved.crawlUrl ? 200 : 400;
498
+ const crawled = await fetchCrawledDocs(crawlPattern, ctx.onProgress, maxPages).catch((err) => {
499
+ ctx.warnings.push(`Crawl failed for ${crawlPattern}: ${err?.message || err}`);
487
500
  return [];
488
501
  });
489
- if (crawled.length === 0) warnings.push(`Crawl returned 0 docs from ${resolved.crawlUrl}`);
502
+ let added = 0;
490
503
  for (const doc of crawled) {
491
- if (!isFrameworkDoc(doc.path)) continue;
492
- docs.push(doc);
493
- docsToIndex.push({
504
+ if (!ctx.isFrameworkDoc(doc.path)) continue;
505
+ ctx.docs.push(doc);
506
+ ctx.docsToIndex.push({
494
507
  id: doc.path,
495
508
  content: doc.content,
496
509
  metadata: {
497
- package: packageName,
510
+ package: ctx.packageName,
498
511
  source: doc.path,
499
512
  type: "doc"
500
513
  }
501
514
  });
515
+ added++;
502
516
  }
503
- if (docs.length > 0) {
504
- docSource = resolved.crawlUrl;
505
- docsType = "docs";
517
+ if (added > 0) {
518
+ ctx.docSource = crawlPattern;
519
+ ctx.docsType = "docs";
506
520
  }
507
521
  }
508
- if (resolved.llmsUrl && docs.length === 0) {
509
- onProgress("Fetching llms.txt");
510
- const llmsContent = await fetchLlmsTxt(resolved.llmsUrl);
511
- if (llmsContent) {
512
- docSource = resolved.llmsUrl;
513
- docsType = "llms.txt";
514
- const baseUrl = resolved.docsUrl || new URL(resolved.llmsUrl).origin;
515
- docs.push({
522
+ });
523
+ const BATCH_SIZE = 20;
524
+ const defaultContentSteps = [
525
+ defineStep({
526
+ id: "git-docs",
527
+ canResolve: (ctx) => !!ctx.resolved.gitDocsUrl && !!ctx.resolved.repoUrl,
528
+ async run(ctx) {
529
+ const gh = parseGitHubUrl(ctx.resolved.repoUrl);
530
+ if (!gh) return;
531
+ ctx.onProgress("Fetching git docs");
532
+ const gitDocs = await fetchGitDocs(gh.owner, gh.repo, ctx.version, ctx.packageName);
533
+ if (!gitDocs || gitDocs.files.length === 0) return;
534
+ if (gitDocs.fallback) ctx.warnings.push(`Docs fetched from ${gitDocs.ref} branch (no tag found for v${ctx.version})`);
535
+ const results = [];
536
+ for (let i = 0; i < gitDocs.files.length; i += BATCH_SIZE) {
537
+ const batch = gitDocs.files.slice(i, i + BATCH_SIZE);
538
+ ctx.onProgress(`Downloading docs ${Math.min(i + BATCH_SIZE, gitDocs.files.length)}/${gitDocs.files.length} from ${gitDocs.ref}`);
539
+ const batchResults = await Promise.all(batch.map(async (file) => {
540
+ const content = await fetchGitHubRaw(`${gitDocs.baseUrl}/${file}`);
541
+ return content ? {
542
+ file,
543
+ content
544
+ } : null;
545
+ }));
546
+ results.push(...batchResults);
547
+ }
548
+ const docs = [];
549
+ const docsToIndex = [];
550
+ for (const r of results) {
551
+ if (!r) continue;
552
+ const stripped = gitDocs.docsPrefix ? r.file.replace(gitDocs.docsPrefix, "") : r.file;
553
+ const cachePath = stripped.startsWith("docs/") ? stripped : `docs/${stripped}`;
554
+ docs.push({
555
+ path: cachePath,
556
+ content: r.content
557
+ });
558
+ docsToIndex.push({
559
+ id: cachePath,
560
+ content: r.content,
561
+ metadata: {
562
+ package: ctx.packageName,
563
+ source: cachePath,
564
+ type: "doc"
565
+ }
566
+ });
567
+ }
568
+ if (isShallowGitDocs(docs.length) && ctx.resolved.llmsUrl) {
569
+ ctx.onProgress(`Shallow git-docs (${docs.length} files), trying llms.txt`);
570
+ return;
571
+ }
572
+ ctx.docs.push(...docs);
573
+ ctx.docsToIndex.push(...docsToIndex);
574
+ ctx.docSource = `${ctx.resolved.repoUrl}/tree/${gitDocs.ref}/docs`;
575
+ ctx.docsType = "docs";
576
+ if (ctx.resolved.llmsUrl) {
577
+ ctx.onProgress("Caching supplementary llms.txt");
578
+ const llmsContent = await fetchLlmsTxt(ctx.resolved.llmsUrl);
579
+ if (llmsContent) {
580
+ const baseUrl = ctx.resolved.docsUrl || new URL(ctx.resolved.llmsUrl).origin;
581
+ ctx.docs.push({
582
+ path: "llms.txt",
583
+ content: normalizeLlmsLinks(llmsContent.raw, baseUrl)
584
+ });
585
+ if (llmsContent.links.length > 0) {
586
+ ctx.onProgress(`Downloading ${llmsContent.links.length} supplementary docs`);
587
+ const supplementary = await downloadLlmsDocs(llmsContent, baseUrl, (_url, done, total) => {
588
+ ctx.onProgress(`Downloading supplementary doc ${done + 1}/${total}`);
589
+ });
590
+ for (const doc of supplementary) {
591
+ if (!ctx.isFrameworkDoc(doc.url)) continue;
592
+ const localPath = doc.url.startsWith("/") ? doc.url.slice(1) : doc.url;
593
+ ctx.docs.push({
594
+ path: join("llms-docs", ...localPath.split("/")),
595
+ content: doc.content
596
+ });
597
+ }
598
+ }
599
+ }
600
+ }
601
+ }
602
+ }),
603
+ crawlUrlStep,
604
+ defineStep({
605
+ id: "llms.txt",
606
+ canResolve: (ctx) => !!ctx.resolved.llmsUrl && ctx.docs.length === 0,
607
+ async run(ctx) {
608
+ const llmsUrl = ctx.resolved.llmsUrl;
609
+ ctx.onProgress("Fetching llms.txt");
610
+ const llmsContent = await fetchLlmsTxt(llmsUrl);
611
+ if (!llmsContent) return;
612
+ ctx.docSource = llmsUrl;
613
+ ctx.docsType = "llms.txt";
614
+ const baseUrl = ctx.resolved.docsUrl || new URL(llmsUrl).origin;
615
+ ctx.docs.push({
516
616
  path: "llms.txt",
517
617
  content: normalizeLlmsLinks(llmsContent.raw, baseUrl)
518
618
  });
519
619
  if (llmsContent.links.length > 0) {
520
- onProgress(`Downloading ${llmsContent.links.length} linked docs`);
620
+ ctx.onProgress(`Downloading ${llmsContent.links.length} linked docs`);
521
621
  const linked = await downloadLlmsDocs(llmsContent, baseUrl, (_url, done, total) => {
522
- onProgress(`Downloading linked doc ${done + 1}/${total}`);
622
+ ctx.onProgress(`Downloading linked doc ${done + 1}/${total}`);
523
623
  });
524
624
  for (const doc of linked) {
525
- if (!isFrameworkDoc(doc.url)) continue;
625
+ if (!ctx.isFrameworkDoc(doc.url)) continue;
526
626
  const cachePath = join("docs", ...(doc.url.startsWith("/") ? doc.url.slice(1) : doc.url).split("/"));
527
- docs.push({
627
+ ctx.docs.push({
528
628
  path: cachePath,
529
629
  content: doc.content
530
630
  });
531
- docsToIndex.push({
631
+ ctx.docsToIndex.push({
532
632
  id: doc.url,
533
633
  content: doc.content,
534
634
  metadata: {
535
- package: packageName,
635
+ package: ctx.packageName,
536
636
  source: cachePath,
537
637
  type: "doc"
538
638
  }
539
639
  });
540
640
  }
541
- if (linked.length > 0) docsType = "docs";
641
+ if (linked.length > 0) ctx.docsType = "docs";
542
642
  }
543
643
  }
544
- }
545
- if (resolved.docsUrl && !docs.some((d) => d.path.startsWith("docs/"))) {
546
- const crawlPattern = resolved.crawlUrl || toCrawlPattern(resolved.docsUrl);
547
- onProgress("Crawling docs site");
548
- const crawled = await fetchCrawledDocs(crawlPattern, onProgress, resolved.crawlUrl ? 200 : 400).catch((err) => {
549
- warnings.push(`Crawl failed for ${crawlPattern}: ${err?.message || err}`);
550
- return [];
551
- });
552
- let added = 0;
553
- for (const doc of crawled) {
554
- if (!isFrameworkDoc(doc.path)) continue;
555
- docs.push(doc);
556
- docsToIndex.push({
557
- id: doc.path,
558
- content: doc.content,
559
- metadata: {
560
- package: packageName,
561
- source: doc.path,
562
- type: "doc"
563
- }
564
- });
565
- added++;
566
- }
567
- if (added > 0) {
568
- docSource = crawlPattern;
569
- docsType = "docs";
570
- }
571
- }
572
- if (resolved.readmeUrl && docs.length === 0) {
573
- onProgress("Fetching README");
574
- const content = await fetchReadmeContent(resolved.readmeUrl);
575
- if (content) {
576
- docs.push({
644
+ }),
645
+ docsCrawlStep,
646
+ defineStep({
647
+ id: "readme",
648
+ canResolve: (ctx) => !!ctx.resolved.readmeUrl && ctx.docs.length === 0,
649
+ async run(ctx) {
650
+ ctx.onProgress("Fetching README");
651
+ const content = await fetchReadmeContent(ctx.resolved.readmeUrl);
652
+ if (!content) return;
653
+ ctx.docs.push({
577
654
  path: "docs/README.md",
578
655
  content
579
656
  });
580
- docsToIndex.push({
657
+ ctx.docsToIndex.push({
581
658
  id: "README.md",
582
659
  content,
583
660
  metadata: {
584
- package: packageName,
661
+ package: ctx.packageName,
585
662
  source: "docs/README.md",
586
663
  type: "doc"
587
664
  }
588
665
  });
589
666
  }
590
- }
667
+ })
668
+ ];
669
+ async function resolveContentDocs(opts) {
670
+ const { packageName, resolved, version, onProgress } = opts;
671
+ const ctx = {
672
+ packageName,
673
+ resolved,
674
+ version,
675
+ onProgress,
676
+ isFrameworkDoc: (path) => filterFrameworkDocs([path], packageName).length > 0,
677
+ docs: [],
678
+ docsToIndex: [],
679
+ warnings: [],
680
+ docSource: resolved.readmeUrl || "readme",
681
+ docsType: "readme"
682
+ };
683
+ await walkSteps(defaultContentSteps, ctx);
591
684
  return {
592
- docs,
593
- docsToIndex,
594
- docSource,
595
- docsType,
596
- warnings
685
+ docs: ctx.docs,
686
+ docsToIndex: ctx.docsToIndex,
687
+ docSource: ctx.docSource,
688
+ docsType: ctx.docsType,
689
+ warnings: ctx.warnings
597
690
  };
598
691
  }
599
- async function tryGitDocs(opts) {
600
- const { owner, repo, version, packageName, repoUrl, llmsUrl, docsUrl, onProgress } = opts;
601
- onProgress("Fetching git docs");
602
- const gitDocs = await fetchGitDocs(owner, repo, version, packageName);
603
- if (!gitDocs || gitDocs.files.length === 0) return null;
604
- let warning;
605
- if (gitDocs.fallback) warning = `Docs fetched from ${gitDocs.ref} branch (no tag found for v${version})`;
606
- const BATCH_SIZE = 20;
607
- const results = [];
608
- for (let i = 0; i < gitDocs.files.length; i += BATCH_SIZE) {
609
- const batch = gitDocs.files.slice(i, i + BATCH_SIZE);
610
- onProgress(`Downloading docs ${Math.min(i + BATCH_SIZE, gitDocs.files.length)}/${gitDocs.files.length} from ${gitDocs.ref}`);
611
- const batchResults = await Promise.all(batch.map(async (file) => {
612
- const content = await fetchGitHubRaw(`${gitDocs.baseUrl}/${file}`);
613
- return content ? {
614
- file,
615
- content
616
- } : null;
617
- }));
618
- results.push(...batchResults);
619
- }
620
- const docs = [];
621
- const docsToIndex = [];
622
- for (const r of results) {
623
- if (!r) continue;
624
- const stripped = gitDocs.docsPrefix ? r.file.replace(gitDocs.docsPrefix, "") : r.file;
625
- const cachePath = stripped.startsWith("docs/") ? stripped : `docs/${stripped}`;
626
- docs.push({
627
- path: cachePath,
628
- content: r.content
629
- });
630
- docsToIndex.push({
631
- id: cachePath,
632
- content: r.content,
692
+ const discussionsStep = defineStep({
693
+ id: "discussions",
694
+ canResolve: (ctx) => ctx.features.discussions && !!ctx.repoInfo && isGhAvailable() && !existsSync(ctx.discussionsDir),
695
+ async run(ctx) {
696
+ const { owner, repo } = ctx.repoInfo;
697
+ ctx.onProgress("Fetching discussions via GitHub API");
698
+ const discussions = await fetchGitHubDiscussions(owner, repo, 20, ctx.resolved.releasedAt, ctx.from).catch(() => []);
699
+ if (discussions.length === 0) return;
700
+ ctx.onProgress(`Caching ${discussions.length} discussions`);
701
+ writeToRepoCache(owner, repo, [...discussions.map((d) => ({
702
+ path: `discussions/discussion-${d.number}.md`,
703
+ content: formatDiscussionAsMarkdown(d)
704
+ })), {
705
+ path: "discussions/_INDEX.md",
706
+ content: generateDiscussionIndex(discussions)
707
+ }]);
708
+ for (const d of discussions) ctx.docsToIndex.push({
709
+ id: `discussion-${d.number}`,
710
+ content: sanitizeMarkdown(`#${d.number}: ${d.title}\n\n${d.body || ""}`),
633
711
  metadata: {
634
- package: packageName,
635
- source: cachePath,
636
- type: "doc"
712
+ package: ctx.packageName,
713
+ source: `discussions/discussion-${d.number}.md`,
714
+ type: "discussion",
715
+ number: d.number
637
716
  }
638
717
  });
639
718
  }
640
- if (isShallowGitDocs(docs.length) && llmsUrl) {
641
- onProgress(`Shallow git-docs (${docs.length} files), trying llms.txt`);
642
- return {
643
- kind: "discarded",
644
- docs: [],
645
- docsToIndex: [],
646
- docSource: "",
647
- warning
648
- };
719
+ });
720
+ const issuesStep = defineStep({
721
+ id: "issues",
722
+ canResolve: (ctx) => ctx.features.issues && !!ctx.repoInfo && isGhAvailable() && !existsSync(ctx.issuesDir),
723
+ async run(ctx) {
724
+ const { owner, repo } = ctx.repoInfo;
725
+ ctx.onProgress("Fetching issues via GitHub API");
726
+ const issues = await fetchGitHubIssues(owner, repo, 30, ctx.resolved.releasedAt, ctx.from).catch(() => []);
727
+ if (issues.length === 0) return;
728
+ ctx.onProgress(`Caching ${issues.length} issues`);
729
+ writeToRepoCache(owner, repo, [...issues.map((issue) => ({
730
+ path: `issues/issue-${issue.number}.md`,
731
+ content: formatIssueAsMarkdown(issue)
732
+ })), {
733
+ path: "issues/_INDEX.md",
734
+ content: generateIssueIndex(issues)
735
+ }]);
736
+ for (const issue of issues) ctx.docsToIndex.push({
737
+ id: `issue-${issue.number}`,
738
+ content: sanitizeMarkdown(`#${issue.number}: ${issue.title}\n\n${issue.body || ""}`),
739
+ metadata: {
740
+ package: ctx.packageName,
741
+ source: `issues/issue-${issue.number}.md`,
742
+ type: "issue",
743
+ number: issue.number
744
+ }
745
+ });
649
746
  }
650
- if (llmsUrl) {
651
- onProgress("Caching supplementary llms.txt");
652
- const llmsContent = await fetchLlmsTxt(llmsUrl);
653
- if (llmsContent) {
654
- const baseUrl = docsUrl || new URL(llmsUrl).origin;
655
- docs.push({
656
- path: "llms.txt",
657
- content: normalizeLlmsLinks(llmsContent.raw, baseUrl)
747
+ });
748
+ const BLOG_VERSION_RE = /blog-(.+)\.md$/;
749
+ const defaultTimelineSteps = [
750
+ issuesStep,
751
+ discussionsStep,
752
+ defineStep({
753
+ id: "releases",
754
+ canResolve: (ctx) => ctx.features.releases && !!ctx.repoInfo && isGhAvailable() && !existsSync(ctx.releasesPath),
755
+ async run(ctx) {
756
+ const { owner, repo } = ctx.repoInfo;
757
+ const { packageName, version, resolved, from } = ctx;
758
+ ctx.onProgress("Fetching releases via GitHub API");
759
+ const changelogRef = isPrerelease(version) ? getPrereleaseChangelogRef(packageName) : void 0;
760
+ const releaseDocs = await fetchReleaseNotes(owner, repo, version, resolved.gitRef, packageName, from, changelogRef).catch(() => []);
761
+ let blogDocs = [];
762
+ if (getBlogPreset(packageName)) {
763
+ ctx.onProgress("Fetching blog release notes");
764
+ blogDocs = await fetchBlogReleases(packageName, version).catch(() => []);
765
+ }
766
+ const allDocs = [...releaseDocs, ...blogDocs];
767
+ const blogEntries = blogDocs.filter((d) => !d.path.endsWith("_INDEX.md")).map((d) => {
768
+ const versionMatch = d.path.match(BLOG_VERSION_RE);
769
+ const fm = parseFrontmatter(d.content);
770
+ return {
771
+ version: versionMatch?.[1] ?? "",
772
+ title: fm.title ?? `Release ${versionMatch?.[1]}`,
773
+ date: fm.date ?? ""
774
+ };
775
+ }).filter((b) => b.version);
776
+ const ghReleases = releaseDocs.filter((d) => d.path.startsWith("releases/") && !d.path.endsWith("CHANGELOG.md")).map((d) => {
777
+ const fm = parseFrontmatter(d.content);
778
+ const tag = fm.tag ?? "";
779
+ const name = fm.name ?? tag;
780
+ const published = fm.published ?? "";
781
+ return {
782
+ id: 0,
783
+ tag,
784
+ name,
785
+ prerelease: false,
786
+ createdAt: published,
787
+ publishedAt: published,
788
+ markdown: ""
789
+ };
790
+ }).filter((r) => r.tag);
791
+ const hasChangelog = allDocs.some((d) => d.path === "releases/CHANGELOG.md");
792
+ if (ghReleases.length > 0 || blogEntries.length > 0) allDocs.push({
793
+ path: "releases/_INDEX.md",
794
+ content: generateReleaseIndex({
795
+ releases: ghReleases,
796
+ packageName,
797
+ blogReleases: blogEntries,
798
+ hasChangelog
799
+ })
658
800
  });
659
- if (llmsContent.links.length > 0) {
660
- onProgress(`Downloading ${llmsContent.links.length} supplementary docs`);
661
- const supplementary = await downloadLlmsDocs(llmsContent, baseUrl, (_url, done, total) => {
662
- onProgress(`Downloading supplementary doc ${done + 1}/${total}`);
663
- });
664
- for (const doc of supplementary) {
665
- if (filterFrameworkDocs([doc.url], packageName).length === 0) continue;
666
- const localPath = doc.url.startsWith("/") ? doc.url.slice(1) : doc.url;
667
- docs.push({
668
- path: join("llms-docs", ...localPath.split("/")),
669
- content: doc.content
670
- });
801
+ if (allDocs.length === 0) return;
802
+ ctx.onProgress(`Caching ${allDocs.length} releases`);
803
+ writeToRepoCache(owner, repo, allDocs);
804
+ for (const doc of allDocs) ctx.docsToIndex.push({
805
+ id: doc.path,
806
+ content: doc.content,
807
+ metadata: {
808
+ package: packageName,
809
+ source: doc.path,
810
+ type: "release"
671
811
  }
672
- }
812
+ });
673
813
  }
674
- }
675
- return {
676
- kind: "git",
677
- docs,
678
- docsToIndex,
679
- docSource: `${repoUrl}/tree/${gitDocs.ref}/docs`,
680
- warning
681
- };
682
- }
814
+ })
815
+ ];
683
816
  async function resolveTimelineReferences(opts) {
684
817
  const { packageName, resolved, version, features, from, onProgress } = opts;
685
- const docsToIndex = [];
686
818
  const gh = resolved.repoUrl ? parseGitHubUrl(resolved.repoUrl) : null;
687
819
  const repoInfo = gh ? {
688
820
  owner: gh.owner,
@@ -690,125 +822,25 @@ async function resolveTimelineReferences(opts) {
690
822
  } : void 0;
691
823
  const repoCacheDir = repoInfo ? getRepoCacheDir(repoInfo.owner, repoInfo.repo) : null;
692
824
  const cacheDir = getCacheDir(packageName, version);
693
- const issuesDir = repoCacheDir ? join(repoCacheDir, "issues") : join(cacheDir, "issues");
694
- const discussionsDir = repoCacheDir ? join(repoCacheDir, "discussions") : join(cacheDir, "discussions");
695
- const releasesPath = repoCacheDir ? join(repoCacheDir, "releases") : join(cacheDir, "releases");
696
- if (features.issues && gh && isGhAvailable() && !existsSync(issuesDir)) {
697
- onProgress("Fetching issues via GitHub API");
698
- const issues = await fetchGitHubIssues(gh.owner, gh.repo, 30, resolved.releasedAt, from).catch(() => []);
699
- if (issues.length > 0) {
700
- onProgress(`Caching ${issues.length} issues`);
701
- const issueDocs = [...issues.map((issue) => ({
702
- path: `issues/issue-${issue.number}.md`,
703
- content: formatIssueAsMarkdown(issue)
704
- })), {
705
- path: "issues/_INDEX.md",
706
- content: generateIssueIndex(issues)
707
- }];
708
- if (repoInfo) writeToRepoCache(repoInfo.owner, repoInfo.repo, issueDocs);
709
- else writeToCache(packageName, version, issueDocs);
710
- for (const issue of issues) docsToIndex.push({
711
- id: `issue-${issue.number}`,
712
- content: sanitizeMarkdown(`#${issue.number}: ${issue.title}\n\n${issue.body || ""}`),
713
- metadata: {
714
- package: packageName,
715
- source: `issues/issue-${issue.number}.md`,
716
- type: "issue",
717
- number: issue.number
718
- }
719
- });
720
- }
721
- }
722
- if (features.discussions && gh && isGhAvailable() && !existsSync(discussionsDir)) {
723
- onProgress("Fetching discussions via GitHub API");
724
- const discussions = await fetchGitHubDiscussions(gh.owner, gh.repo, 20, resolved.releasedAt, from).catch(() => []);
725
- if (discussions.length > 0) {
726
- onProgress(`Caching ${discussions.length} discussions`);
727
- const discussionDocs = [...discussions.map((d) => ({
728
- path: `discussions/discussion-${d.number}.md`,
729
- content: formatDiscussionAsMarkdown(d)
730
- })), {
731
- path: "discussions/_INDEX.md",
732
- content: generateDiscussionIndex(discussions)
733
- }];
734
- if (repoInfo) writeToRepoCache(repoInfo.owner, repoInfo.repo, discussionDocs);
735
- else writeToCache(packageName, version, discussionDocs);
736
- for (const d of discussions) docsToIndex.push({
737
- id: `discussion-${d.number}`,
738
- content: sanitizeMarkdown(`#${d.number}: ${d.title}\n\n${d.body || ""}`),
739
- metadata: {
740
- package: packageName,
741
- source: `discussions/discussion-${d.number}.md`,
742
- type: "discussion",
743
- number: d.number
744
- }
745
- });
746
- }
747
- }
748
- if (features.releases && gh && isGhAvailable() && !existsSync(releasesPath)) {
749
- onProgress("Fetching releases via GitHub API");
750
- const changelogRef = isPrerelease(version) ? getPrereleaseChangelogRef(packageName) : void 0;
751
- const releaseDocs = await fetchReleaseNotes(gh.owner, gh.repo, version, resolved.gitRef, packageName, from, changelogRef).catch(() => []);
752
- let blogDocs = [];
753
- if (getBlogPreset(packageName)) {
754
- onProgress("Fetching blog release notes");
755
- blogDocs = await fetchBlogReleases(packageName, version).catch(() => []);
756
- }
757
- const allDocs = [...releaseDocs, ...blogDocs];
758
- const blogEntries = blogDocs.filter((d) => !d.path.endsWith("_INDEX.md")).map((d) => {
759
- const versionMatch = d.path.match(/blog-(.+)\.md$/);
760
- const fm = parseFrontmatter(d.content);
761
- return {
762
- version: versionMatch?.[1] ?? "",
763
- title: fm.title ?? `Release ${versionMatch?.[1]}`,
764
- date: fm.date ?? ""
765
- };
766
- }).filter((b) => b.version);
767
- const ghReleases = releaseDocs.filter((d) => d.path.startsWith("releases/") && !d.path.endsWith("CHANGELOG.md")).map((d) => {
768
- const fm = parseFrontmatter(d.content);
769
- const tag = fm.tag ?? "";
770
- const name = fm.name ?? tag;
771
- const published = fm.published ?? "";
772
- return {
773
- id: 0,
774
- tag,
775
- name,
776
- prerelease: false,
777
- createdAt: published,
778
- publishedAt: published,
779
- markdown: ""
780
- };
781
- }).filter((r) => r.tag);
782
- const hasChangelog = allDocs.some((d) => d.path === "releases/CHANGELOG.md");
783
- if (ghReleases.length > 0 || blogEntries.length > 0) allDocs.push({
784
- path: "releases/_INDEX.md",
785
- content: generateReleaseIndex({
786
- releases: ghReleases,
787
- packageName,
788
- blogReleases: blogEntries,
789
- hasChangelog
790
- })
791
- });
792
- if (allDocs.length > 0) {
793
- onProgress(`Caching ${allDocs.length} releases`);
794
- if (repoInfo) writeToRepoCache(repoInfo.owner, repoInfo.repo, allDocs);
795
- else writeToCache(packageName, version, allDocs);
796
- for (const doc of allDocs) docsToIndex.push({
797
- id: doc.path,
798
- content: doc.content,
799
- metadata: {
800
- package: packageName,
801
- source: doc.path,
802
- type: "release"
803
- }
804
- });
805
- }
806
- }
825
+ const ctx = {
826
+ packageName,
827
+ version,
828
+ resolved,
829
+ features,
830
+ from,
831
+ onProgress,
832
+ repoInfo,
833
+ issuesDir: repoCacheDir ? join(repoCacheDir, "issues") : join(cacheDir, "issues"),
834
+ discussionsDir: repoCacheDir ? join(repoCacheDir, "discussions") : join(cacheDir, "discussions"),
835
+ releasesPath: repoCacheDir ? join(repoCacheDir, "releases") : join(cacheDir, "releases"),
836
+ docsToIndex: []
837
+ };
838
+ await walkSteps(defaultTimelineSteps, ctx);
807
839
  return {
808
- docsToIndex,
809
- hasIssues: features.issues && existsSync(issuesDir),
810
- hasDiscussions: features.discussions && existsSync(discussionsDir),
811
- hasReleases: features.releases && existsSync(releasesPath),
840
+ docsToIndex: ctx.docsToIndex,
841
+ hasIssues: features.issues && existsSync(ctx.issuesDir),
842
+ hasDiscussions: features.discussions && existsSync(ctx.discussionsDir),
843
+ hasReleases: features.releases && existsSync(ctx.releasesPath),
812
844
  repoInfo
813
845
  };
814
846
  }
@@ -902,11 +934,12 @@ async function fetchAndCacheResources(opts) {
902
934
  };
903
935
  }
904
936
  async function prepareSkillReferences(opts) {
905
- const { packageName, version, cwd, skillDir, resources, features, baseDir, onIndexProgress } = opts;
937
+ const { packageName, version, cwd, skillDir, resources, features, baseDir, extraPackages, onIndexProgress } = opts;
906
938
  const cache = createReferenceCache(packageName, version);
907
939
  cache.linkInto(skillDir, cwd, resources.docsType, {
908
940
  features,
909
- repoInfo: resources.repoInfo
941
+ repoInfo: resources.repoInfo,
942
+ extraPackages
910
943
  });
911
944
  if (features.search) await indexResources({
912
945
  packageName,
@@ -947,6 +980,6 @@ function buildSkillContext(opts) {
947
980
  overheadLines: opts.overheadLines
948
981
  };
949
982
  }
950
- export { prepareSkillReferences as a, resolveAutoModel as c, applyCachedSections as d, enhanceSkillWithLLM as f, writePromptFiles as h, findRelatedSkills as i, selectLlmConfig as l, writeBaseSkill as m, detectChangelog as n, indexResources as o, runSkillEnhancement as p, fetchAndCacheResources as r, DEFAULT_SECTIONS as s, buildSkillContext as t, selectSkillSections as u };
983
+ export { prepareSkillReferences as a, selectLlmConfig as c, runSkillEnhancement as d, writeBaseSkill as f, findRelatedSkills as i, applyCachedSections as l, detectChangelog as n, DEFAULT_SECTIONS as o, writePromptFiles as p, fetchAndCacheResources as r, resolveAutoModel as s, buildSkillContext as t, enhanceSkillWithLLM as u };
951
984
 
952
- //# sourceMappingURL=sync-pipeline.mjs.map
985
+ //# sourceMappingURL=pipeline.mjs.map