@farming-labs/theme 0.1.88 → 0.1.90

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,4 +1,4 @@
1
- import { ChangelogConfig, DocsAnalyticsConfig, DocsAskAIMcpConfig, DocsI18nConfig, DocsMcpConfig, DocsObservabilityConfig, DocsRobotsConfig, DocsSearchConfig, DocsSitemapConfig, FeedbackConfig, OrderingItem } from "@farming-labs/docs";
1
+ import { ChangelogConfig, DocsAnalyticsConfig, DocsAskAIMcpConfig, DocsI18nConfig, DocsMcpConfig, DocsObservabilityConfig, DocsRobotsConfig, DocsSearchConfig, DocsSitemapConfig, FeedbackConfig, LlmsTxtConfig, OrderingItem } from "@farming-labs/docs";
2
2
 
3
3
  //#region src/docs-api.d.ts
4
4
  interface AIProviderConfig {
@@ -74,12 +74,7 @@ interface DocsMCPAPIOptions {
74
74
  analytics?: boolean | DocsAnalyticsConfig;
75
75
  observability?: boolean | DocsObservabilityConfig;
76
76
  }
77
- interface LlmsTxtOptions {
78
- enabled?: boolean;
79
- siteTitle?: string;
80
- siteDescription?: string;
81
- baseUrl?: string;
82
- }
77
+ type LlmsTxtOptions = LlmsTxtConfig;
83
78
  /**
84
79
  * Create a unified docs API route handler.
85
80
  *
package/dist/docs-api.mjs CHANGED
@@ -3,7 +3,7 @@ import { getNextAppDir } from "./get-app-dir.mjs";
3
3
  import fs from "node:fs";
4
4
  import path from "node:path";
5
5
  import matter from "gray-matter";
6
- import { buildDocsAskAIContext, createDocsAgentTraceContext, createDocsAgentTraceId, createDocsSitemapResponse, emitDocsAgentTraceEvent, emitDocsAnalyticsEvent, formatDocsAskAIPackageHints, getDocsMarkdownVaryHeader, hasDocsMarkdownSignatureAgent, normalizeDocsRelated, performDocsSearch, renderDocsMarkdownNotFound, renderDocsRelatedMarkdownLines, resolveAskAISearchRequestConfig, resolveChangelogConfig, resolveDocsI18n, resolveDocsLocale, resolveDocsSitemapConfig, resolvePageSidebarFolderIndexBehavior, resolveSearchRequestConfig, toDocsMarkdownUrl } from "@farming-labs/docs";
6
+ import { buildDocsAskAIContext, createDocsAgentTraceContext, createDocsAgentTraceId, createDocsSitemapResponse, emitDocsAgentTraceEvent, emitDocsAnalyticsEvent, formatDocsAskAIPackageHints, getDocsLlmsTxtMaxCharsIssue, getDocsMarkdownVaryHeader, hasDocsMarkdownSignatureAgent, normalizeDocsRelated, performDocsSearch, renderDocsLlmsTxt, renderDocsMarkdownNotFound, renderDocsRelatedMarkdownLines, resolveAskAISearchRequestConfig, resolveChangelogConfig, resolveDocsI18n, resolveDocsLlmsTxtRequest, resolveDocsLlmsTxtSections, resolveDocsLocale, resolveDocsSitemapConfig, resolvePageSidebarFolderIndexBehavior, resolveSearchRequestConfig, selectDocsLlmsTxtContent } from "@farming-labs/docs";
7
7
  import { createDocsMcpHttpHandler, createFilesystemDocsMcpSource, readDocsSitemapManifest, resolveDocsMcpConfig } from "@farming-labs/docs/server";
8
8
 
9
9
  //#region src/docs-api.ts
@@ -184,6 +184,7 @@ function buildAgentSpec({ origin, entry, i18n, search, mcp, feedback, llms, site
184
184
  const searchEnabled = isSearchEnabled(search);
185
185
  const sitemapConfig = resolveDocsSitemapConfig(sitemap, { baseUrl: llms.baseUrl });
186
186
  const robotsEnabled = isRobotsDiscoveryEnabled(robots);
187
+ const llmsSections = resolveDocsLlmsTxtSections(llms);
187
188
  return {
188
189
  version: "1",
189
190
  name: "@farming-labs/docs",
@@ -245,7 +246,14 @@ function buildAgentSpec({ origin, entry, i18n, search, mcp, feedback, llms, site
245
246
  publicTxt: DEFAULT_LLMS_TXT_ROUTE,
246
247
  publicFull: DEFAULT_LLMS_FULL_TXT_ROUTE,
247
248
  wellKnownTxt: DEFAULT_LLMS_TXT_WELL_KNOWN_ROUTE,
248
- wellKnownFull: DEFAULT_LLMS_FULL_TXT_WELL_KNOWN_ROUTE
249
+ wellKnownFull: DEFAULT_LLMS_FULL_TXT_WELL_KNOWN_ROUTE,
250
+ ...llmsSections.length > 0 ? { sections: llmsSections.map((section) => ({
251
+ title: section.title,
252
+ description: section.description,
253
+ match: section.match,
254
+ txt: section.route,
255
+ full: section.fullRoute
256
+ })) } : {}
249
257
  },
250
258
  sitemap: {
251
259
  enabled: sitemapConfig.enabled,
@@ -927,13 +935,6 @@ function resolveMarkdownRequest(entry, url, request) {
927
935
  }
928
936
  return null;
929
937
  }
930
- function resolveLlmsTxtFormat(url) {
931
- const pathname = normalizeUrlPath(url.pathname);
932
- if (pathname === DEFAULT_LLMS_TXT_ROUTE || pathname === DEFAULT_LLMS_TXT_WELL_KNOWN_ROUTE) return "llms";
933
- if (pathname === DEFAULT_LLMS_FULL_TXT_ROUTE || pathname === DEFAULT_LLMS_FULL_TXT_WELL_KNOWN_ROUTE) return "llms-full";
934
- const format = url.searchParams.get("format");
935
- return format === "llms" || format === "llms-full" ? format : null;
936
- }
937
938
  function renderMarkdownDocument(page) {
938
939
  if ("agentRawContent" in page && page.agentRawContent !== void 0) return page.agentRawContent;
939
940
  const relatedLines = renderDocsRelatedMarkdownLines(page.related);
@@ -950,6 +951,7 @@ function renderSkillDocument({ origin, entry, search, mcp, feedback, llms, sitem
950
951
  const searchEnabled = isSearchEnabled(search);
951
952
  const sitemapConfig = resolveDocsSitemapConfig(sitemap, { baseUrl: llms.baseUrl });
952
953
  const robotsEnabled = isRobotsDiscoveryEnabled(robots);
954
+ const llmsSections = resolveDocsLlmsTxtSections(llms);
953
955
  const lines = [
954
956
  "---",
955
957
  "name: docs",
@@ -963,7 +965,10 @@ function renderSkillDocument({ origin, entry, search, mcp, feedback, llms, sitem
963
965
  if (siteDescription) lines.push(`Description: ${siteDescription}`);
964
966
  lines.push("", "## When To Use", "Use this skill when you need to read or implement against this documentation site.", "", "## Start Here", `- Fetch ${DEFAULT_AGENT_SPEC_WELL_KNOWN_JSON_ROUTE}; fall back to ${DEFAULT_AGENT_SPEC_WELL_KNOWN_ROUTE} or ${DEFAULT_AGENT_SPEC_ROUTE}.`, `- Fetch /${normalizedEntry}.md for the root docs page.`, `- Fetch /${normalizedEntry}/{slug}.md for page-specific context.`, "- You can also request text/markdown from normal page URLs.");
965
967
  if (searchEnabled) lines.push(`- Search with ${DEFAULT_DOCS_API_ROUTE}?query={query} when you do not know the page.`);
966
- if (llms.enabled) lines.push(`- Use ${DEFAULT_LLMS_TXT_ROUTE} for a compact docs index.`, `- Use ${DEFAULT_LLMS_FULL_TXT_ROUTE} for full markdown context.`);
968
+ if (llms.enabled) {
969
+ lines.push(`- Use ${DEFAULT_LLMS_TXT_ROUTE} for a compact docs index.`, `- Use ${DEFAULT_LLMS_FULL_TXT_ROUTE} for full markdown context.`);
970
+ for (const section of llmsSections) lines.push(`- Use ${section.route} for the ${section.title} llms.txt section.`);
971
+ }
967
972
  if (sitemapConfig.enabled) {
968
973
  if (sitemapConfig.xml.enabled) lines.push(`- Use ${sitemapConfig.xml.route} to check canonical page freshness.`);
969
974
  if (sitemapConfig.markdown.enabled) lines.push(`- Use ${sitemapConfig.markdown.route} for a semantic docs map.`);
@@ -973,7 +978,13 @@ function renderSkillDocument({ origin, entry, search, mcp, feedback, llms, sitem
973
978
  if (feedback.enabled) lines.push(`- Read ${feedback.schemaRoute} before posting agent feedback to ${feedback.route}.`);
974
979
  lines.push("", "## Routes", `- Skill document: ${DEFAULT_SKILL_MD_ROUTE}`, `- Skill well-known alias: ${DEFAULT_SKILL_MD_WELL_KNOWN_ROUTE}`, `- Skill API format: ${DEFAULT_DOCS_API_ROUTE}?format=skill`, `- Agent discovery: ${DEFAULT_AGENT_SPEC_WELL_KNOWN_JSON_ROUTE}`, `- Agent discovery fallback: ${DEFAULT_AGENT_SPEC_WELL_KNOWN_ROUTE}`, `- Markdown root: /${normalizedEntry}.md`, `- Markdown pages: /${normalizedEntry}/{slug}.md`);
975
980
  if (robotsEnabled) lines.push(`- Robots policy: ${DEFAULT_ROBOTS_TXT_ROUTE}`);
976
- if (llms.enabled) lines.push(`- llms.txt: ${DEFAULT_LLMS_TXT_ROUTE}`, `- llms-full.txt: ${DEFAULT_LLMS_FULL_TXT_ROUTE}`, `- llms well-known aliases: ${DEFAULT_LLMS_TXT_WELL_KNOWN_ROUTE}, ${DEFAULT_LLMS_FULL_TXT_WELL_KNOWN_ROUTE}`);
981
+ if (llms.enabled) {
982
+ lines.push(`- llms.txt: ${DEFAULT_LLMS_TXT_ROUTE}`, `- llms-full.txt: ${DEFAULT_LLMS_FULL_TXT_ROUTE}`, `- llms well-known aliases: ${DEFAULT_LLMS_TXT_WELL_KNOWN_ROUTE}, ${DEFAULT_LLMS_FULL_TXT_WELL_KNOWN_ROUTE}`);
983
+ for (const section of llmsSections) {
984
+ lines.push(`- ${section.title} llms.txt: ${section.route}`);
985
+ lines.push(`- ${section.title} llms-full.txt: ${section.fullRoute}`);
986
+ }
987
+ }
977
988
  if (sitemapConfig.enabled) {
978
989
  if (sitemapConfig.xml.enabled) lines.push(`- Sitemap XML: ${sitemapConfig.xml.route}`);
979
990
  if (sitemapConfig.markdown.enabled) lines.push(`- Sitemap Markdown: ${sitemapConfig.markdown.route}`, `- Sitemap well-known alias: ${sitemapConfig.markdown.wellKnownRoute}`);
@@ -1583,27 +1594,7 @@ function readRobotsConfig(root) {
1583
1594
  }
1584
1595
  }
1585
1596
  function generateLlmsTxt(indexes, options) {
1586
- const { siteTitle = "Documentation", siteDescription, baseUrl = "" } = options;
1587
- let llmsTxt = `# ${siteTitle}\n\n`;
1588
- if (siteDescription) llmsTxt += `> ${siteDescription}\n\n`;
1589
- llmsTxt += `## Pages\n\n`;
1590
- for (const page of indexes) {
1591
- llmsTxt += `- [${page.title}](${baseUrl}${toDocsMarkdownUrl(page.url)})`;
1592
- if (page.description) llmsTxt += `: ${page.description}`;
1593
- llmsTxt += `\n`;
1594
- }
1595
- let llmsFullTxt = `# ${siteTitle}\n\n`;
1596
- if (siteDescription) llmsFullTxt += `> ${siteDescription}\n\n`;
1597
- for (const page of indexes) {
1598
- llmsFullTxt += `## ${page.title}\n\n`;
1599
- llmsFullTxt += `URL: ${baseUrl}${page.url}\n\n`;
1600
- if (page.description) llmsFullTxt += `${page.description}\n\n`;
1601
- llmsFullTxt += `${page.content}\n\n---\n\n`;
1602
- }
1603
- return {
1604
- llmsTxt,
1605
- llmsFullTxt
1606
- };
1597
+ return renderDocsLlmsTxt(indexes, options);
1607
1598
  }
1608
1599
  /**
1609
1600
  * Create a unified docs API route handler.
@@ -1758,7 +1749,9 @@ function createDocsAPI(options) {
1758
1749
  const next = generateLlmsTxt(getIndexes(ctx), {
1759
1750
  siteTitle: llmsConfig.siteTitle ?? "Documentation",
1760
1751
  siteDescription: llmsConfig.siteDescription,
1761
- baseUrl: llmsConfig.baseUrl ?? ""
1752
+ baseUrl: llmsConfig.baseUrl ?? "",
1753
+ maxChars: llmsConfig.maxChars,
1754
+ sections: llmsConfig.sections
1762
1755
  });
1763
1756
  llmsCacheByLocale.set(key, next);
1764
1757
  return next;
@@ -1921,8 +1914,8 @@ function createDocsAPI(options) {
1921
1914
  "X-Robots-Tag": "noindex"
1922
1915
  } });
1923
1916
  }
1924
- const llmsFormat = resolveLlmsTxtFormat(url);
1925
- if (llmsFormat === "llms" || llmsFormat === "llms-full") {
1917
+ const llmsRequest = resolveDocsLlmsTxtRequest(url, llmsConfig);
1918
+ if (llmsRequest) {
1926
1919
  if (!llmsConfig.enabled) return new Response("Not Found", {
1927
1920
  status: 404,
1928
1921
  headers: {
@@ -1930,31 +1923,36 @@ function createDocsAPI(options) {
1930
1923
  "X-Robots-Tag": "noindex"
1931
1924
  }
1932
1925
  });
1933
- }
1934
- if (llmsFormat === "llms") {
1935
- await emitDocsAnalyticsEvent(analytics, {
1936
- type: "llms_request",
1937
- source: "server",
1938
- url: request.url,
1939
- path: url.pathname,
1940
- locale: ctx.locale,
1941
- properties: { format: "llms" }
1926
+ const selected = selectDocsLlmsTxtContent(getLlmsContent(ctx), llmsRequest);
1927
+ if (!selected) return new Response("Not Found", {
1928
+ status: 404,
1929
+ headers: {
1930
+ "Content-Type": "text/plain; charset=utf-8",
1931
+ "X-Robots-Tag": "noindex"
1932
+ }
1942
1933
  });
1943
- return new Response(getLlmsContent(ctx).llmsTxt, { headers: {
1944
- "Content-Type": "text/plain; charset=utf-8",
1945
- "Cache-Control": "public, max-age=3600"
1946
- } });
1947
- }
1948
- if (llmsFormat === "llms-full") {
1934
+ const budgetIssue = getDocsLlmsTxtMaxCharsIssue(selected.label, selected.content, selected.maxChars);
1935
+ if (budgetIssue?.mode === "error") return new Response(budgetIssue.message, {
1936
+ status: 500,
1937
+ headers: {
1938
+ "Content-Type": "text/plain; charset=utf-8",
1939
+ "X-Robots-Tag": "noindex"
1940
+ }
1941
+ });
1942
+ if (budgetIssue?.mode === "warn") console.warn(`[docs] ${budgetIssue.message}`);
1949
1943
  await emitDocsAnalyticsEvent(analytics, {
1950
1944
  type: "llms_request",
1951
1945
  source: "server",
1952
1946
  url: request.url,
1953
1947
  path: url.pathname,
1954
1948
  locale: ctx.locale,
1955
- properties: { format: "llms-full" }
1949
+ properties: {
1950
+ format: llmsRequest.format,
1951
+ section: llmsRequest.section?.route,
1952
+ contentLength: selected.content.length
1953
+ }
1956
1954
  });
1957
- return new Response(getLlmsContent(ctx).llmsFullTxt, { headers: {
1955
+ return new Response(selected.content, { headers: {
1958
1956
  "Content-Type": "text/plain; charset=utf-8",
1959
1957
  "Cache-Control": "public, max-age=3600"
1960
1958
  } });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@farming-labs/theme",
3
- "version": "0.1.88",
3
+ "version": "0.1.90",
4
4
  "description": "Theme package for @farming-labs/docs — layout, provider, MDX components, and styles",
5
5
  "keywords": [
6
6
  "docs",
@@ -139,7 +139,7 @@
139
139
  "tsdown": "^0.20.3",
140
140
  "typescript": "^5.9.3",
141
141
  "vitest": "^3.2.4",
142
- "@farming-labs/docs": "0.1.88"
142
+ "@farming-labs/docs": "0.1.90"
143
143
  },
144
144
  "peerDependencies": {
145
145
  "@farming-labs/docs": ">=0.0.1",