@farming-labs/docs 0.2.59 → 0.2.61

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 (56) hide show
  1. package/README.md +1 -1
  2. package/dist/{agent-DlxriaTs.mjs → agent-DFHlw_JC.mjs} +3 -3
  3. package/dist/{agent-BFqyqEnC.mjs → agent-Fl0pjVNF.mjs} +136 -331
  4. package/dist/{agent-evals-kJs2Y9xR.mjs → agent-evals-f4_OL10T.mjs} +3 -3
  5. package/dist/{agent-export-BgUaiW8f.mjs → agent-export-D0zQhasD.mjs} +87 -46
  6. package/dist/agent-skills-bundle.d.mts +13 -0
  7. package/dist/agent-skills-bundle.mjs +12 -0
  8. package/dist/agent-skills-server-CIeBszxp.mjs +263 -0
  9. package/dist/agent-skills-server-CKq3_jMj.d.mts +12 -0
  10. package/dist/agent-skills-vite.d.mts +31 -0
  11. package/dist/agent-skills-vite.mjs +70 -0
  12. package/dist/{agents-Djh-HXih.mjs → agents-ibnXrWyp.mjs} +9 -7
  13. package/dist/cli/index.mjs +32 -30
  14. package/dist/client/react.d.mts +1 -1
  15. package/dist/{cloud-ask-ai-B2WnG4fF.d.mts → cloud-ask-ai-D7ZgF47y.d.mts} +1 -1
  16. package/dist/{cloud-BH_sHX64.mjs → cloud-pdNC-tyj.mjs} +3 -3
  17. package/dist/{codeblocks-Bq67u32v.mjs → codeblocks-CFuurVIH.mjs} +2 -2
  18. package/dist/{config-DASewQ0x.mjs → config-Wcdj-D0a.mjs} +7 -1
  19. package/dist/{dev-CAQlbguk.mjs → dev-Cmy6DtdF.mjs} +2 -2
  20. package/dist/docs-cloud-server.d.mts +2 -2
  21. package/dist/docs-cloud-server.mjs +1 -1
  22. package/dist/{doctor-CO1VMcF_.mjs → doctor-CXostbsI.mjs} +151 -21
  23. package/dist/{downgrade-BZs86NVr.mjs → downgrade-w7e6Se0L.mjs} +2 -2
  24. package/dist/{golden-evaluations-BN9u2wxw.mjs → golden-evaluations-CBZ_JZjf.mjs} +19 -4
  25. package/dist/index.d.mts +52 -10
  26. package/dist/index.mjs +8 -7
  27. package/dist/{init-B_9ENq8Z.mjs → init-CQY0Woe3.mjs} +36 -5
  28. package/dist/mcp-DyPcoLwm.mjs +156 -0
  29. package/dist/mcp.d.mts +13 -2
  30. package/dist/mcp.mjs +699 -408
  31. package/dist/{metadata-BDuewuzq.mjs → metadata-Dv1ah0Aj.mjs} +1 -1
  32. package/dist/{package-version-qik_4J6C.mjs → package-version-n5AFur8a.mjs} +1 -1
  33. package/dist/{reading-time-BkEft6SD.mjs → reading-time-C-SAhQT9.mjs} +10 -9
  34. package/dist/{review-NC-sOdXn.mjs → review-D2UBrxFq.mjs} +18 -10
  35. package/dist/{robots-DskPvGPw.mjs → robots-5Yqz9mz7.mjs} +5 -4
  36. package/dist/{robots-ltltiLJF.mjs → robots-C08kDLsz.mjs} +6 -2
  37. package/dist/{search-D57JXQLj.mjs → search-9OnMGMvt.mjs} +1 -1
  38. package/dist/{search-C1JitPwi.d.mts → search-C6heDO8h.d.mts} +3 -126
  39. package/dist/{search-o4Ud6OXv.mjs → search-CNsRpz90.mjs} +8 -6
  40. package/dist/server.d.mts +6 -5
  41. package/dist/server.mjs +9 -7
  42. package/dist/{sitemap-Cq-Yj_iA.mjs → sitemap-BpYnSsfJ.mjs} +9 -7
  43. package/dist/{sitemap-server-C1ibVKOy.mjs → sitemap-server-D_0Kzanj.mjs} +1 -1
  44. package/dist/standards-discovery-C4HUqMd2.d.mts +227 -0
  45. package/dist/standards-discovery-C54V_aJH.mjs +510 -0
  46. package/dist/{templates-CfQjpDWW.mjs → templates-Bq_P7ctv.mjs} +102 -9
  47. package/dist/{types-XHABMh_f.d.mts → types-EhFhYGfr.d.mts} +58 -1
  48. package/dist/{upgrade-BCJTCW3O.mjs → upgrade-oz-GChgt.mjs} +2 -2
  49. package/package.json +11 -1
  50. package/dist/mcp-BAJr3wC2.mjs +0 -104
  51. /package/dist/{agent-scope-CCaIY1aK.mjs → agent-scope-C_U--OZ7.mjs} +0 -0
  52. /package/dist/{cloud-ask-ai-hnJfj8-X.mjs → cloud-ask-ai-sbpjOR2K.mjs} +0 -0
  53. /package/dist/{code-blocks-qe0T8-xe.mjs → code-blocks-DnNVNK2M.mjs} +0 -0
  54. /package/dist/{errors-CVqZ3kOO.mjs → errors-DbOhkE1h.mjs} +0 -0
  55. /package/dist/{i18n-CAlj1ADU.mjs → i18n-CCaFUnAN.mjs} +0 -0
  56. /package/dist/{utils-6UCLxv4B.mjs → utils-DpiIioYb.mjs} +0 -0
@@ -1,19 +1,21 @@
1
- import { Lt as renderDocsSitemapMarkdown, M as buildDocsAgentDiscoverySpec, Pt as buildDocsSitemapManifest, Rt as renderDocsSitemapXml, St as toDocsMarkdownUrl, T as DEFAULT_SKILL_MD_WELL_KNOWN_ROUTE, a as DEFAULT_AGENT_MD_ROUTE, at as renderDocsMarkdownDocument, c as DEFAULT_AGENT_SPEC_WELL_KNOWN_JSON_ROUTE, en as buildDocsAgentSkillsIndex, g as DEFAULT_LLMS_FULL_TXT_WELL_KNOWN_ROUTE, h as DEFAULT_LLMS_FULL_TXT_ROUTE, it as renderDocsLlmsTxt, l as DEFAULT_AGENT_SPEC_WELL_KNOWN_ROUTE, lt as resolveDocsAgentFeedbackConfig, n as DEFAULT_AGENTS_MD_WELL_KNOWN_ROUTE, o as DEFAULT_AGENT_MD_WELL_KNOWN_ROUTE, on as resolveDocsPublishedAgentSkill, qt as DEFAULT_AGENT_SKILLS_INDEX_ROUTE, rt as renderDocsAgentsDocument, st as renderDocsSkillDocument, t as DEFAULT_AGENTS_MD_ROUTE, v as DEFAULT_LLMS_TXT_ROUTE, w as DEFAULT_SKILL_MD_ROUTE, y as DEFAULT_LLMS_TXT_WELL_KNOWN_ROUTE, zt as resolveDocsSitemapConfig } from "./agent-BFqyqEnC.mjs";
2
- import "./search-D57JXQLj.mjs";
3
- import { t as resolveDocsI18n } from "./i18n-CAlj1ADU.mjs";
4
- import { c as renderDocsRobotsGeneratedBlock, f as upsertDocsRobotsGeneratedBlock, i as DOCS_ROBOTS_GENERATED_BLOCK_START, r as DOCS_ROBOTS_GENERATED_BLOCK_END, u as resolveDocsRobotsConfig } from "./robots-ltltiLJF.mjs";
5
- import "./sitemap-server-C1ibVKOy.mjs";
6
- import "./agent-evals-kJs2Y9xR.mjs";
1
+ import { $ as renderDocsAgentsDocument, At as buildDocsSitemapManifest, Ft as resolveDocsSitemapConfig, Nt as renderDocsSitemapMarkdown, Pt as renderDocsSitemapXml, S as DEFAULT_SKILL_MD_WELL_KNOWN_ROUTE, a as DEFAULT_AGENT_MD_ROUTE, at as resolveDocsAgentFeedbackConfig, c as DEFAULT_AGENT_SPEC_WELL_KNOWN_JSON_ROUTE, et as renderDocsLlmsTxt, g as DEFAULT_LLMS_FULL_TXT_WELL_KNOWN_ROUTE, h as DEFAULT_LLMS_FULL_TXT_ROUTE, k as buildDocsAgentDiscoverySpec, l as DEFAULT_AGENT_SPEC_WELL_KNOWN_ROUTE, n as DEFAULT_AGENTS_MD_WELL_KNOWN_ROUTE, o as DEFAULT_AGENT_MD_WELL_KNOWN_ROUTE, rt as renderDocsSkillDocument, t as DEFAULT_AGENTS_MD_ROUTE, tt as renderDocsMarkdownDocument, v as DEFAULT_LLMS_TXT_ROUTE, vt as toDocsMarkdownUrl, x as DEFAULT_SKILL_MD_ROUTE, y as DEFAULT_LLMS_TXT_WELL_KNOWN_ROUTE } from "./agent-Fl0pjVNF.mjs";
2
+ import { S as buildDocsAgentSkillsIndex, a as DEFAULT_A2A_AGENT_CARD_ROUTE, c as DEFAULT_AGENT_SKILLS_INDEX_ROUTE, k as resolveDocsPublishedAgentSkill, u as DEFAULT_AGENT_SKILLS_ROUTE_PREFIX, v as DEFAULT_LEGACY_SKILLS_INDEX_ROUTE, w as buildDocsLegacySkillsIndex, x as buildDocsA2AAgentCard, y as DEFAULT_LEGACY_SKILLS_ROUTE_PREFIX } from "./standards-discovery-C54V_aJH.mjs";
3
+ import "./search-9OnMGMvt.mjs";
4
+ import { t as resolveDocsI18n } from "./i18n-CCaFUnAN.mjs";
5
+ import { c as renderDocsRobotsGeneratedBlock, f as upsertDocsRobotsGeneratedBlock, i as DOCS_ROBOTS_GENERATED_BLOCK_START, r as DOCS_ROBOTS_GENERATED_BLOCK_END, u as resolveDocsRobotsConfig } from "./robots-C08kDLsz.mjs";
6
+ import "./sitemap-server-D_0Kzanj.mjs";
7
+ import "./agent-evals-f4_OL10T.mjs";
7
8
  import { createFilesystemDocsMcpSource, resolveDocsMcpConfig } from "./mcp.mjs";
8
- import "./code-blocks-qe0T8-xe.mjs";
9
+ import "./code-blocks-DnNVNK2M.mjs";
10
+ import { t as resolveConfiguredAgentSkills } from "./agent-skills-server-CIeBszxp.mjs";
9
11
  import "./server.mjs";
10
- import { d as readStringProperty, f as readTopLevelBooleanProperty, h as resolveDocsContentDir, i as loadDocsConfigModule, l as readNavTitle, m as resolveDocsConfigPath, p as readTopLevelStringProperty, r as extractTopLevelConfigObject, s as readBooleanProperty, t as extractNestedObjectLiteral } from "./config-DASewQ0x.mjs";
11
- import { t as detectFramework } from "./utils-6UCLxv4B.mjs";
12
+ import { _ as resolveDocsContentDir, a as loadDocsConfigModule, d as readNavTitle, g as resolveDocsConfigPath, h as readTopLevelStringProperty, l as readBooleanProperty, m as readTopLevelBooleanProperty, p as readStringProperty, r as extractTopLevelConfigObject, t as extractNestedObjectLiteral } from "./config-Wcdj-D0a.mjs";
13
+ import { t as detectFramework } from "./utils-DpiIioYb.mjs";
12
14
  import { existsSync, lstatSync, mkdirSync, readFileSync, realpathSync, renameSync, rmSync, writeFileSync } from "node:fs";
13
15
  import path from "node:path";
14
16
  import { execFileSync } from "node:child_process";
15
- import pc from "picocolors";
16
17
  import { createHash, randomUUID } from "node:crypto";
18
+ import pc from "picocolors";
17
19
 
18
20
  //#region src/cli/agent-export.ts
19
21
  const AGENT_EXPORT_AGENTS_MARKER = "<!-- Generated by @farming-labs/docs agent export. -->";
@@ -67,8 +69,17 @@ function normalizePathSegment(value) {
67
69
  function normalizeContent(content) {
68
70
  return `${content.trimEnd()}\n`;
69
71
  }
72
+ function encodeRoutePath(relativePath) {
73
+ return relativePath.split("/").map((segment) => encodeURIComponent(segment)).join("/");
74
+ }
70
75
  function publicFilePath(publicDir, route) {
71
- const resolved = resolveContainedPath(publicDir, route.replace(/^\/+/, ""));
76
+ let relativeRoute;
77
+ try {
78
+ relativeRoute = route.replace(/^\/+/, "").split("/").map((segment) => decodeURIComponent(segment)).join("/");
79
+ } catch {
80
+ throw new Error(`Agent Bundle route contains invalid URL encoding: ${route}`);
81
+ }
82
+ const resolved = resolveContainedPath(publicDir, relativeRoute);
72
83
  if (!resolved) throw new Error(`Agent Bundle route must stay inside the public directory: ${route}`);
73
84
  return resolved;
74
85
  }
@@ -119,7 +130,7 @@ function sha256(content) {
119
130
  return createHash("sha256").update(content).digest("hex");
120
131
  }
121
132
  function byteLength(content) {
122
- return Buffer.byteLength(content, "utf-8");
133
+ return typeof content === "string" ? Buffer.byteLength(content, "utf-8") : content.byteLength;
123
134
  }
124
135
  function readExisting(filePath) {
125
136
  return existsSync(filePath) ? readFileSync(filePath, "utf-8") : void 0;
@@ -128,7 +139,8 @@ function atomicWriteFile(filePath, content) {
128
139
  mkdirSync(path.dirname(filePath), { recursive: true });
129
140
  const temporaryPath = `${filePath}.${process.pid}.${randomUUID()}.tmp`;
130
141
  try {
131
- writeFileSync(temporaryPath, content, "utf-8");
142
+ if (typeof content === "string") writeFileSync(temporaryPath, content, "utf-8");
143
+ else writeFileSync(temporaryPath, content);
132
144
  renameSync(temporaryPath, filePath);
133
145
  } finally {
134
146
  if (existsSync(temporaryPath)) rmSync(temporaryPath, { force: true });
@@ -381,7 +393,7 @@ function findPublicAgentsSource(publicDir) {
381
393
  if (content !== void 0 && !isManagedAgentsContent(content)) return normalizeContent(content);
382
394
  }
383
395
  }
384
- function addOutput(outputs, publicDir, route, kind, mediaType, content, managed = true) {
396
+ function addOutput(outputs, publicDir, route, kind, mediaType, content, managed = true, normalizeText = true) {
385
397
  const absolutePath = publicFilePath(publicDir, route);
386
398
  if (absolutePath === publicFilePath(publicDir, AGENT_BUNDLE_MANIFEST_ROUTE)) throw new Error(`Agent Bundle output collision at ${route} (reserved bundle manifest). Change the conflicting docs slug or configured route.`);
387
399
  const collision = outputs.find((output) => output.absolutePath === absolutePath);
@@ -392,7 +404,7 @@ function addOutput(outputs, publicDir, route, kind, mediaType, content, managed
392
404
  route,
393
405
  kind,
394
406
  mediaType,
395
- content: normalizeContent(content),
407
+ content: typeof content === "string" && normalizeText ? normalizeContent(content) : content,
396
408
  managed
397
409
  });
398
410
  }
@@ -431,6 +443,8 @@ function resolveUserOwnedOverrides(outputs, previous) {
431
443
  const previousByPath = new Map(previous?.files.map((file) => [file.path, file]) ?? []);
432
444
  return outputs.map((output) => {
433
445
  if (!preserveKinds.has(output.kind)) return output;
446
+ if (output.route.startsWith("/.well-known/agent-skills/") || output.route.startsWith("/.well-known/skills/") || output.route === DEFAULT_A2A_AGENT_CARD_ROUTE) return output;
447
+ if (typeof output.content !== "string") return output;
434
448
  const current = readExisting(output.absolutePath);
435
449
  if (current === void 0 || current === output.content) return output;
436
450
  const previousFile = previousByPath.get(output.publicPath);
@@ -442,7 +456,7 @@ function resolveUserOwnedOverrides(outputs, previous) {
442
456
  };
443
457
  });
444
458
  }
445
- function resolveRobotsOutput(publicDir, entry, sitemap, robots) {
459
+ function resolveRobotsOutput(publicDir, entry, sitemap, robots, agentCard = false) {
446
460
  const route = "/robots.txt";
447
461
  const absolutePath = publicFilePath(publicDir, route);
448
462
  const existing = readExisting(absolutePath);
@@ -451,7 +465,8 @@ function resolveRobotsOutput(publicDir, entry, sitemap, robots) {
451
465
  apiCatalog: false,
452
466
  sitemap,
453
467
  baseUrl: robots.baseUrl,
454
- robots
468
+ robots,
469
+ agentCard
455
470
  });
456
471
  const hasManagedBlock = existing?.includes(DOCS_ROBOTS_GENERATED_BLOCK_START) === true && existing.includes(DOCS_ROBOTS_GENERATED_BLOCK_END);
457
472
  if (existing !== void 0 && !hasManagedBlock) return {
@@ -544,8 +559,9 @@ function preservedStaleManifestFiles(publicDir, previous, outputs) {
544
559
  const expected = new Set(outputs.map((output) => output.publicPath));
545
560
  return previous.files.flatMap((file) => {
546
561
  if (!file.managed && file.orphaned !== true || expected.has(file.path)) return [];
547
- const current = readExisting(resolvePreviousOutputPath(publicDir, file.path, "public"));
548
- if (current === void 0) return [];
562
+ const filePath = resolvePreviousOutputPath(publicDir, file.path, "public");
563
+ if (!existsSync(filePath)) return [];
564
+ const current = readFileSync(filePath);
549
565
  if (file.orphaned !== true && sha256(current) === file.sha256) return [];
550
566
  return [{
551
567
  ...file,
@@ -561,7 +577,8 @@ function preservedStaleInternalManifestFiles(rootDir, previous, outputs) {
561
577
  const expected = new Set(outputs.map((output) => output.path));
562
578
  return previous.internalFiles.flatMap((file) => {
563
579
  if (expected.has(file.path)) return [];
564
- const current = readExisting(resolvePreviousOutputPath(rootDir, file.path, "internal"));
580
+ const filePath = resolvePreviousOutputPath(rootDir, file.path, "internal");
581
+ const current = existsSync(filePath) ? readFileSync(filePath) : void 0;
565
582
  if (current === void 0) return [];
566
583
  if (file.orphaned !== true && sha256(current) === file.sha256) return [];
567
584
  return [{
@@ -578,7 +595,7 @@ function removeStaleManagedFiles(publicDir, previous, stalePaths) {
578
595
  const previousByPath = new Map(previous.files.map((file) => [resolvePreviousOutputPath(publicDir, file.path, "public"), file]));
579
596
  for (const filePath of stalePaths) {
580
597
  const previousFile = previousByPath.get(filePath);
581
- const current = readExisting(filePath);
598
+ const current = existsSync(filePath) ? readFileSync(filePath) : void 0;
582
599
  if (!previousFile?.managed || previousFile.orphaned === true || current === void 0 || sha256(current) !== previousFile.sha256) continue;
583
600
  rmSync(filePath);
584
601
  removed.push(filePath);
@@ -599,7 +616,13 @@ function removeStaleInternalFiles(rootDir, previous, stalePaths) {
599
616
  return removed;
600
617
  }
601
618
  function changedOutputs(outputs) {
602
- return outputs.filter((output) => readExisting(output.absolutePath) !== output.content);
619
+ return outputs.filter((output) => !outputMatchesExisting(output));
620
+ }
621
+ function outputMatchesExisting(output) {
622
+ if (!existsSync(output.absolutePath)) return false;
623
+ if (typeof output.content === "string") return readExisting(output.absolutePath) === output.content;
624
+ const current = readFileSync(output.absolutePath);
625
+ return current.byteLength === output.content.byteLength && current.equals(Buffer.from(output.content));
603
626
  }
604
627
  async function exportAgentBundle(options = {}) {
605
628
  if (!options.public && !options.check) throw new Error("Pass --public to write the static Agent Bundle into the framework public directory.");
@@ -681,6 +704,7 @@ async function exportAgentBundle(options = {}) {
681
704
  openapi,
682
705
  markdown: { acceptHeader: false }
683
706
  };
707
+ const configuredAgentSkills = await resolveConfiguredAgentSkills(config?.agent?.skills, { rootDir });
684
708
  let outputs = [];
685
709
  const internalOutputs = [];
686
710
  for (const { page } of localizedPages) addOutput(outputs, publicDir, staticMarkdownRoute(page, sourceEntry, routeEntry), "page", "text/markdown", renderDocsMarkdownDocument({
@@ -719,23 +743,6 @@ async function exportAgentBundle(options = {}) {
719
743
  addOutput(outputs, publicDir, section.fullRoute, "llms", "text/plain", section.llmsFullTxt);
720
744
  }
721
745
  }
722
- const discoveryWithBundle = {
723
- ...buildDocsAgentDiscoverySpec({
724
- ...documentOptions,
725
- i18n
726
- }),
727
- staticBundle: {
728
- format: "farming-labs-agent-bundle.v1",
729
- manifest: AGENT_BUNDLE_MANIFEST_ROUTE,
730
- check: "docs agent export --check",
731
- locales: i18n ? {
732
- default: i18n.defaultLocale,
733
- pathPattern: `${routeEntry ? `/${routeEntry}` : ""}/{locale}/{slug}.md`
734
- } : void 0
735
- }
736
- };
737
- const discoveryJson = JSON.stringify(discoveryWithBundle, null, 2);
738
- for (const route of [DEFAULT_AGENT_SPEC_WELL_KNOWN_JSON_ROUTE, DEFAULT_AGENT_SPEC_WELL_KNOWN_ROUTE]) addOutput(outputs, publicDir, route, "discovery", "application/json", discoveryJson);
739
746
  const generatedSkill = renderDocsSkillDocument(documentOptions);
740
747
  const rootSkillPath = path.join(rootDir, "skill.md");
741
748
  const publicSkill = existsSync(rootSkillPath) ? readFileSync(rootSkillPath, "utf-8") : generatedSkill;
@@ -787,14 +794,48 @@ async function exportAgentBundle(options = {}) {
787
794
  ]) if (route) addOutput(outputs, publicDir, route, "sitemap", "text/markdown", sitemapMarkdown);
788
795
  }
789
796
  }
790
- if (robots.enabled) outputs.push(resolveRobotsOutput(publicDir, routeEntry || "docs", sitemapInput, robots));
797
+ if (robots.enabled) outputs.push(resolveRobotsOutput(publicDir, routeEntry || "docs", sitemapInput, robots, Boolean(config?.agent?.a2a)));
791
798
  outputs = resolveUserOwnedOverrides(outputs, previous);
792
- const publishedAgentSkill = await resolveDocsPublishedAgentSkill({
793
- preferredDocument: outputs.find((output) => output.route === DEFAULT_SKILL_MD_ROUTE)?.content ?? normalizeContent(publicSkill),
799
+ const effectiveSkillOutput = outputs.find((output) => output.route === DEFAULT_SKILL_MD_ROUTE)?.content;
800
+ const allPublishedSkills = [await resolveDocsPublishedAgentSkill({
801
+ preferredDocument: typeof effectiveSkillOutput === "string" ? effectiveSkillOutput : normalizeContent(publicSkill),
794
802
  fallbackDocument: normalizeContent(generatedSkill)
795
- });
796
- addOutput(outputs, publicDir, publishedAgentSkill.url, "skill", "text/markdown", publishedAgentSkill.content);
797
- addOutput(outputs, publicDir, DEFAULT_AGENT_SKILLS_INDEX_ROUTE, "discovery", "application/json", JSON.stringify(buildDocsAgentSkillsIndex(publishedAgentSkill), null, 2));
803
+ }), ...configuredAgentSkills];
804
+ const publishedNames = /* @__PURE__ */ new Set();
805
+ for (const skill of allPublishedSkills) {
806
+ if (publishedNames.has(skill.name)) throw new Error(`Duplicate published Agent Skill name: ${skill.name}`);
807
+ publishedNames.add(skill.name);
808
+ addOutput(outputs, publicDir, skill.url, "skill", skill.type === "archive" ? "application/gzip" : "text/markdown", skill.content, true, false);
809
+ for (const file of skill.files) {
810
+ if (file.url !== skill.url) addOutput(outputs, publicDir, file.url, "skill", file.mediaType, file.content, true, false);
811
+ if (file.path === "SKILL.md") addOutput(outputs, publicDir, `${DEFAULT_AGENT_SKILLS_ROUTE_PREFIX}/${encodeURIComponent(skill.name)}/skill.md`, "skill", file.mediaType, file.content, true, false);
812
+ const legacyPath = file.path === "SKILL.md" ? "skill.md" : encodeRoutePath(file.path);
813
+ addOutput(outputs, publicDir, `${DEFAULT_LEGACY_SKILLS_ROUTE_PREFIX}/${encodeURIComponent(skill.name)}/${legacyPath}`, "skill", file.mediaType, file.content, true, false);
814
+ }
815
+ }
816
+ addOutput(outputs, publicDir, DEFAULT_AGENT_SKILLS_INDEX_ROUTE, "discovery", "application/json", JSON.stringify(buildDocsAgentSkillsIndex(allPublishedSkills), null, 2));
817
+ addOutput(outputs, publicDir, DEFAULT_LEGACY_SKILLS_INDEX_ROUTE, "discovery", "application/json", JSON.stringify(buildDocsLegacySkillsIndex(allPublishedSkills), null, 2));
818
+ if (config?.agent?.a2a) addOutput(outputs, publicDir, DEFAULT_A2A_AGENT_CARD_ROUTE, "discovery", "application/json", JSON.stringify(buildDocsA2AAgentCard(config.agent.a2a, allPublishedSkills), null, 2));
819
+ const discoveryWithBundle = {
820
+ ...buildDocsAgentDiscoverySpec({
821
+ ...documentOptions,
822
+ i18n,
823
+ publishedSkills: allPublishedSkills,
824
+ agentCard: config?.agent?.a2a
825
+ }),
826
+ staticBundle: {
827
+ format: "farming-labs-agent-bundle.v1",
828
+ manifest: AGENT_BUNDLE_MANIFEST_ROUTE,
829
+ check: "docs agent export --check",
830
+ locales: i18n ? {
831
+ default: i18n.defaultLocale,
832
+ pathPattern: `${routeEntry ? `/${routeEntry}` : ""}/{locale}/{slug}.md`
833
+ } : void 0
834
+ }
835
+ };
836
+ const discoveryJson = JSON.stringify(discoveryWithBundle, null, 2);
837
+ for (const route of [DEFAULT_AGENT_SPEC_WELL_KNOWN_JSON_ROUTE, DEFAULT_AGENT_SPEC_WELL_KNOWN_ROUTE]) addOutput(outputs, publicDir, route, "discovery", "application/json", discoveryJson);
838
+ outputs = resolveUserOwnedOverrides(outputs, previous);
798
839
  assertOutputPathsDoNotCollide({
799
840
  outputs,
800
841
  internalOutputs,
@@ -832,7 +873,7 @@ async function exportAgentBundle(options = {}) {
832
873
  const internalChanged = readExisting(internalManifestPath) !== manifestJson;
833
874
  if (options.check && (changed.length > 0 || changedInternalOutputs.length > 0 || internalChanged || stalePaths.length > 0 || staleInternal.length > 0)) throw new Error(`Static Agent Bundle is stale (${changed.length + changedInternalOutputs.length + (internalChanged ? 1 : 0) + stalePaths.length + staleInternal.length} output(s)). Run \`docs agent export --public\` to update it.`);
834
875
  if (!options.check) {
835
- for (const output of outputs) if (readExisting(output.absolutePath) !== output.content) atomicWriteFile(output.absolutePath, output.content);
876
+ for (const output of outputs) if (!outputMatchesExisting(output)) atomicWriteFile(output.absolutePath, output.content);
836
877
  for (const output of internalOutputs) if (readExisting(output.absolutePath) !== output.content) atomicWriteFile(output.absolutePath, output.content);
837
878
  atomicWriteFile(publicManifestPath, manifestJson);
838
879
  atomicWriteFile(internalManifestPath, manifestJson);
@@ -0,0 +1,13 @@
1
+ import { A as DocsPublishedAgentSkill } from "./standards-discovery-C4HUqMd2.mjs";
2
+
3
+ //#region src/agent-skills-bundle.d.ts
4
+ /**
5
+ * Build-time snapshot of configured Agent Skills.
6
+ *
7
+ * `docsAgentSkills()` replaces this module in production bundles. The undefined
8
+ * fallback keeps direct Node usage and development setups on the filesystem
9
+ * resolver when the build plugin is not installed.
10
+ */
11
+ declare const bundledAgentSkills: readonly DocsPublishedAgentSkill[] | undefined;
12
+ //#endregion
13
+ export { bundledAgentSkills };
@@ -0,0 +1,12 @@
1
+ //#region src/agent-skills-bundle.ts
2
+ /**
3
+ * Build-time snapshot of configured Agent Skills.
4
+ *
5
+ * `docsAgentSkills()` replaces this module in production bundles. The undefined
6
+ * fallback keeps direct Node usage and development setups on the filesystem
7
+ * resolver when the build plugin is not installed.
8
+ */
9
+ const bundledAgentSkills = void 0;
10
+
11
+ //#endregion
12
+ export { bundledAgentSkills };
@@ -0,0 +1,263 @@
1
+ import { k as resolveDocsPublishedAgentSkill, u as DEFAULT_AGENT_SKILLS_ROUTE_PREFIX } from "./standards-discovery-C54V_aJH.mjs";
2
+ import { existsSync, lstatSync, readFileSync, readdirSync, realpathSync, statSync } from "node:fs";
3
+ import path from "node:path";
4
+ import { createHash } from "node:crypto";
5
+ import { gzipSync } from "node:zlib";
6
+
7
+ //#region src/agent-skills-server.ts
8
+ const COMPANION_DIRECTORIES = new Set([
9
+ "references",
10
+ "scripts",
11
+ "assets"
12
+ ]);
13
+ const IGNORED_COLLECTION_DIRECTORIES = new Set([".git", "node_modules"]);
14
+ const MAX_COLLECTION_DEPTH = 12;
15
+ const MAX_FILES_PER_SKILL = 256;
16
+ const MAX_FILE_BYTES = 1024 * 1024;
17
+ const MAX_SKILL_BYTES = 8 * 1024 * 1024;
18
+ function isInside(parent, candidate) {
19
+ const relative = path.relative(parent, candidate);
20
+ return relative === "" || !relative.startsWith("..") && !path.isAbsolute(relative);
21
+ }
22
+ function findWorkspaceRoot(rootDir) {
23
+ let current = realpathSync(rootDir);
24
+ for (;;) {
25
+ if (existsSync(path.join(current, ".git")) || existsSync(path.join(current, "pnpm-workspace.yaml")) || existsSync(path.join(current, "pnpm-workspace.yml"))) return current;
26
+ const parent = path.dirname(current);
27
+ if (parent === current) return realpathSync(rootDir);
28
+ current = parent;
29
+ }
30
+ }
31
+ function normalizeConfiguredPaths(input) {
32
+ if (!input) return [];
33
+ const value = typeof input === "string" || Array.isArray(input) ? input : input.paths;
34
+ return (typeof value === "string" ? [value] : [...value]).map((candidate) => candidate.trim()).filter(Boolean);
35
+ }
36
+ function resolveSafeConfiguredPath(configuredPath, rootDir, workspaceRoot) {
37
+ const candidate = path.resolve(rootDir, configuredPath);
38
+ if (!existsSync(candidate)) throw new Error(`Configured Agent Skill path does not exist: ${configuredPath}`);
39
+ if (lstatSync(candidate).isSymbolicLink()) throw new Error(`Configured Agent Skill paths may not be symlinks: ${configuredPath}`);
40
+ const resolved = realpathSync(candidate);
41
+ if (!isInside(workspaceRoot, resolved)) throw new Error(`Agent Skill symlink escapes the workspace: ${configuredPath}`);
42
+ return resolved;
43
+ }
44
+ function collectSkillDocuments(candidate, workspaceRoot, results, visited, depth = 0) {
45
+ if (depth > MAX_COLLECTION_DEPTH) throw new Error(`Agent Skill collection exceeds ${MAX_COLLECTION_DEPTH} directory levels.`);
46
+ const resolved = realpathSync(candidate);
47
+ if (!isInside(workspaceRoot, resolved)) throw new Error(`Agent Skill symlink escapes the workspace: ${candidate}`);
48
+ if (visited.has(resolved)) return;
49
+ visited.add(resolved);
50
+ const info = statSync(resolved);
51
+ if (info.isFile()) {
52
+ if (path.basename(resolved) !== "SKILL.md") throw new Error(`Agent Skill file must be named SKILL.md: ${candidate}`);
53
+ results.add(resolved);
54
+ return;
55
+ }
56
+ if (!info.isDirectory()) throw new Error(`Agent Skill path must be a regular file or directory: ${candidate}`);
57
+ const directSkill = path.join(resolved, "SKILL.md");
58
+ if (existsSync(directSkill)) {
59
+ const directInfo = lstatSync(directSkill);
60
+ if (!directInfo.isFile() || directInfo.isSymbolicLink()) throw new Error(`Agent Skill SKILL.md must be a non-symlink regular file: ${directSkill}`);
61
+ results.add(directSkill);
62
+ return;
63
+ }
64
+ for (const entry of readdirSync(resolved, { withFileTypes: true }).sort((a, b) => a.name.localeCompare(b.name))) {
65
+ if (IGNORED_COLLECTION_DIRECTORIES.has(entry.name) || entry.name.startsWith(".") || COMPANION_DIRECTORIES.has(entry.name)) continue;
66
+ const entryPath = path.join(resolved, entry.name);
67
+ if (entry.isSymbolicLink()) throw new Error(`Agent Skill collections may not contain symlinks: ${entryPath}`);
68
+ else if (entry.isDirectory() || entry.isFile()) {
69
+ if (entry.isDirectory() || entry.name === "SKILL.md") collectSkillDocuments(entryPath, workspaceRoot, results, visited, depth + 1);
70
+ } else throw new Error(`Unsafe filesystem entry in Agent Skill collection: ${entryPath}`);
71
+ }
72
+ }
73
+ function encodeSkillFileUrl(name, relativePath) {
74
+ const encodedPath = relativePath.split("/").map((segment) => encodeURIComponent(segment)).join("/");
75
+ return `${DEFAULT_AGENT_SKILLS_ROUTE_PREFIX}/${encodeURIComponent(name)}/${encodedPath}`;
76
+ }
77
+ function mediaTypeFor(relativePath) {
78
+ const extension = path.extname(relativePath).toLowerCase();
79
+ if ([".md", ".mdx"].includes(extension)) return "text/markdown";
80
+ if ([
81
+ ".txt",
82
+ ".sh",
83
+ ".bash",
84
+ ".zsh",
85
+ ".py",
86
+ ".js",
87
+ ".mjs",
88
+ ".cjs",
89
+ ".ts",
90
+ ".tsx",
91
+ ".jsx",
92
+ ".css",
93
+ ".html",
94
+ ".svg",
95
+ ".csv",
96
+ ".yaml",
97
+ ".yml"
98
+ ].includes(extension)) return "text/plain";
99
+ if (extension === ".json") return "application/json";
100
+ if (extension === ".png") return "image/png";
101
+ if ([".jpg", ".jpeg"].includes(extension)) return "image/jpeg";
102
+ if (extension === ".gif") return "image/gif";
103
+ if (extension === ".webp") return "image/webp";
104
+ if (extension === ".pdf") return "application/pdf";
105
+ return "application/octet-stream";
106
+ }
107
+ function hashBytes(content) {
108
+ return createHash("sha256").update(content).digest("hex");
109
+ }
110
+ function preserveFileBytes(content, mediaType) {
111
+ if (mediaType.startsWith("text/") || mediaType === "application/json") {
112
+ const text = content.toString("utf8");
113
+ if (Buffer.from(text, "utf8").equals(content)) return text;
114
+ }
115
+ return new Uint8Array(content);
116
+ }
117
+ function compareSkillFilePath(left, right) {
118
+ if (left.path === "SKILL.md") return -1;
119
+ if (right.path === "SKILL.md") return 1;
120
+ return left.path.localeCompare(right.path);
121
+ }
122
+ function readCompanionFiles(skillDir, name, rootSkillBytes) {
123
+ const files = [];
124
+ let totalBytes = rootSkillBytes;
125
+ function visit(absoluteDir, relativeDir, depth = 0) {
126
+ if (depth > MAX_COLLECTION_DEPTH) throw new Error(`Agent Skill companion tree exceeds ${MAX_COLLECTION_DEPTH} levels: ${skillDir}`);
127
+ for (const entry of readdirSync(absoluteDir, { withFileTypes: true }).sort((a, b) => a.name.localeCompare(b.name))) {
128
+ const absolutePath = path.join(absoluteDir, entry.name);
129
+ const relativePath = path.posix.join(relativeDir, entry.name);
130
+ if (entry.isSymbolicLink()) throw new Error(`Agent Skill companion files may not be symlinks: ${absolutePath}`);
131
+ if (entry.isDirectory()) {
132
+ visit(absolutePath, relativePath, depth + 1);
133
+ continue;
134
+ }
135
+ if (!entry.isFile()) throw new Error(`Unsafe filesystem entry in Agent Skill: ${absolutePath}`);
136
+ const executable = (statSync(absolutePath).mode & 73) !== 0;
137
+ const content = readFileSync(absolutePath);
138
+ if (content.byteLength > MAX_FILE_BYTES) throw new Error(`Agent Skill file exceeds ${MAX_FILE_BYTES} bytes: ${absolutePath}`);
139
+ totalBytes += content.byteLength;
140
+ if (totalBytes > MAX_SKILL_BYTES || files.length >= MAX_FILES_PER_SKILL - 1) throw new Error(`Agent Skill exceeds safe publication limits: ${skillDir}`);
141
+ const mediaType = mediaTypeFor(relativePath);
142
+ const value = preserveFileBytes(content, mediaType);
143
+ const sha256 = hashBytes(value);
144
+ files.push({
145
+ path: relativePath,
146
+ url: encodeSkillFileUrl(name, relativePath),
147
+ mediaType,
148
+ content: value,
149
+ sha256,
150
+ digest: `sha256:${sha256}`,
151
+ executable
152
+ });
153
+ }
154
+ }
155
+ for (const directory of [...COMPANION_DIRECTORIES].sort()) {
156
+ const absoluteDir = path.join(skillDir, directory);
157
+ if (!existsSync(absoluteDir)) continue;
158
+ const info = lstatSync(absoluteDir);
159
+ if (info.isSymbolicLink() || !info.isDirectory()) throw new Error(`Agent Skill ${directory}/ must be a non-symlink directory: ${absoluteDir}`);
160
+ visit(absoluteDir, directory);
161
+ }
162
+ return files;
163
+ }
164
+ function writeTarString(header, offset, length, value) {
165
+ const encoded = Buffer.from(value, "utf8");
166
+ if (encoded.byteLength > length) throw new Error(`Agent Skill archive path is too long: ${value}`);
167
+ header.set(encoded, offset);
168
+ }
169
+ function writeTarOctal(header, offset, length, value) {
170
+ writeTarString(header, offset, length, value.toString(8).padStart(length - 1, "0"));
171
+ }
172
+ function createTarHeader(name, size, executable) {
173
+ const header = new Uint8Array(512);
174
+ writeTarString(header, 0, 100, name);
175
+ writeTarOctal(header, 100, 8, executable ? 493 : 420);
176
+ writeTarOctal(header, 108, 8, 0);
177
+ writeTarOctal(header, 116, 8, 0);
178
+ writeTarOctal(header, 124, 12, size);
179
+ writeTarOctal(header, 136, 12, 0);
180
+ header.fill(32, 148, 156);
181
+ header[156] = "0".charCodeAt(0);
182
+ writeTarString(header, 257, 6, "ustar");
183
+ writeTarString(header, 263, 2, "00");
184
+ writeTarString(header, 148, 8, `${header.reduce((sum, byte) => sum + byte, 0).toString(8).padStart(6, "0")}\0 `);
185
+ return header;
186
+ }
187
+ function createDeterministicTarGzip(files) {
188
+ const chunks = [];
189
+ let total = 0;
190
+ for (const file of [...files].sort(compareSkillFilePath)) {
191
+ const content = typeof file.content === "string" ? Buffer.from(file.content) : file.content;
192
+ const header = createTarHeader(file.path, content.byteLength, file.executable === true);
193
+ chunks.push(header, content);
194
+ total += header.byteLength + content.byteLength;
195
+ const padding = (512 - content.byteLength % 512) % 512;
196
+ if (padding) {
197
+ chunks.push(new Uint8Array(padding));
198
+ total += padding;
199
+ }
200
+ }
201
+ chunks.push(new Uint8Array(1024));
202
+ total += 1024;
203
+ const tar = new Uint8Array(total);
204
+ let offset = 0;
205
+ for (const chunk of chunks) {
206
+ tar.set(chunk, offset);
207
+ offset += chunk.byteLength;
208
+ }
209
+ const archive = new Uint8Array(gzipSync(tar, { level: 9 }));
210
+ if (archive.byteLength > 9) archive[9] = 255;
211
+ return archive;
212
+ }
213
+ async function publishSkillDocument(skillPath) {
214
+ const skillDir = path.dirname(skillPath);
215
+ const skillDocument = readFileSync(skillPath, "utf8");
216
+ const skillDocumentBytes = Buffer.byteLength(skillDocument, "utf8");
217
+ if (skillDocumentBytes > MAX_FILE_BYTES) throw new Error(`Agent Skill SKILL.md exceeds ${MAX_FILE_BYTES} bytes: ${skillPath}`);
218
+ const base = await resolveDocsPublishedAgentSkill({
219
+ preferredDocument: skillDocument,
220
+ fallbackDocument: skillDocument
221
+ });
222
+ if (base.name !== path.basename(skillDir)) throw new Error(`Agent Skill frontmatter name "${base.name}" must match its directory "${path.basename(skillDir)}".`);
223
+ const companions = readCompanionFiles(skillDir, base.name, skillDocumentBytes);
224
+ const files = [...base.files, ...companions].sort(compareSkillFilePath);
225
+ if (companions.length === 0) return {
226
+ ...base,
227
+ files
228
+ };
229
+ const content = createDeterministicTarGzip(files);
230
+ const sha256 = hashBytes(content);
231
+ return {
232
+ name: base.name,
233
+ type: "archive",
234
+ description: base.description,
235
+ url: `${DEFAULT_AGENT_SKILLS_ROUTE_PREFIX}/${encodeURIComponent(base.name)}.tar.gz`,
236
+ digest: `sha256:${sha256}`,
237
+ content,
238
+ sha256,
239
+ skillDocument,
240
+ files
241
+ };
242
+ }
243
+ /** Resolve and safely package all project skills configured through `agent.skills`. */
244
+ async function resolveConfiguredAgentSkills(input, options = {}) {
245
+ const configuredPaths = normalizeConfiguredPaths(input);
246
+ if (configuredPaths.length === 0) return [];
247
+ const rootDir = realpathSync(options.rootDir ?? process.cwd());
248
+ const workspaceRoot = realpathSync(options.workspaceRoot ?? findWorkspaceRoot(rootDir));
249
+ if (!isInside(workspaceRoot, rootDir)) throw new Error("Agent Skill rootDir must stay inside the configured workspace root.");
250
+ const documents = /* @__PURE__ */ new Set();
251
+ const visited = /* @__PURE__ */ new Set();
252
+ for (const configuredPath of configuredPaths) collectSkillDocuments(resolveSafeConfiguredPath(configuredPath, rootDir, workspaceRoot), workspaceRoot, documents, visited);
253
+ const published = await Promise.all([...documents].sort().map(publishSkillDocument));
254
+ const names = /* @__PURE__ */ new Set();
255
+ for (const skill of published) {
256
+ if (names.has(skill.name)) throw new Error(`Duplicate configured Agent Skill name: ${skill.name}`);
257
+ names.add(skill.name);
258
+ }
259
+ return published.sort((left, right) => left.name.localeCompare(right.name));
260
+ }
261
+
262
+ //#endregion
263
+ export { resolveConfiguredAgentSkills as t };
@@ -0,0 +1,12 @@
1
+ import { A as DocsPublishedAgentSkill } from "./standards-discovery-C4HUqMd2.mjs";
2
+ import { P as DocsAgentSkillsInput } from "./types-EhFhYGfr.mjs";
3
+
4
+ //#region src/agent-skills-server.d.ts
5
+ interface ResolveConfiguredAgentSkillsOptions {
6
+ rootDir?: string;
7
+ workspaceRoot?: string;
8
+ }
9
+ /** Resolve and safely package all project skills configured through `agent.skills`. */
10
+ declare function resolveConfiguredAgentSkills(input: DocsAgentSkillsInput | undefined, options?: ResolveConfiguredAgentSkillsOptions): Promise<DocsPublishedAgentSkill[]>;
11
+ //#endregion
12
+ export { resolveConfiguredAgentSkills as n, ResolveConfiguredAgentSkillsOptions as t };
@@ -0,0 +1,31 @@
1
+ import { A as DocsPublishedAgentSkill } from "./standards-discovery-C4HUqMd2.mjs";
2
+ import { P as DocsAgentSkillsInput } from "./types-EhFhYGfr.mjs";
3
+ import { t as ResolveConfiguredAgentSkillsOptions } from "./agent-skills-server-CKq3_jMj.mjs";
4
+
5
+ //#region src/agent-skills-vite.d.ts
6
+ declare const DOCS_AGENT_SKILLS_BUNDLE_MODULE = "@farming-labs/docs/agent-skills-bundle";
7
+ interface DocsAgentSkillsBuildConfig {
8
+ agent?: {
9
+ skills?: DocsAgentSkillsInput;
10
+ };
11
+ rootDir?: string;
12
+ }
13
+ interface DocsAgentSkillsBuildPluginOptions extends ResolveConfiguredAgentSkillsOptions {}
14
+ /** Minimal Rollup/Vite plugin surface, kept dependency-free for framework configs. */
15
+ interface DocsAgentSkillsBuildPlugin {
16
+ name: string;
17
+ enforce: "pre";
18
+ resolveId(source: string): string | undefined;
19
+ load(id: string): Promise<string | undefined>;
20
+ }
21
+ /** Render a self-contained virtual module without relying on Node at runtime. */
22
+ declare function renderDocsAgentSkillsBundle(skills: readonly DocsPublishedAgentSkill[]): string;
23
+ /**
24
+ * Snapshot configured Agent Skills into the server bundle.
25
+ *
26
+ * The same plugin object works in Vite, Astro/Svelte/TanStack, and Nitro's
27
+ * Rollup build. Paths remain relative to the project root unless overridden.
28
+ */
29
+ declare function docsAgentSkills(config: DocsAgentSkillsBuildConfig, options?: DocsAgentSkillsBuildPluginOptions): DocsAgentSkillsBuildPlugin;
30
+ //#endregion
31
+ export { DOCS_AGENT_SKILLS_BUNDLE_MODULE, DocsAgentSkillsBuildPlugin, DocsAgentSkillsBuildPluginOptions, docsAgentSkills, renderDocsAgentSkillsBundle };