@farming-labs/docs 0.2.73 → 0.2.75

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 (34) hide show
  1. package/dist/{agent-o9OTadrf.mjs → agent-BHqaZx-X.mjs} +9 -0
  2. package/dist/{agent-ClRpctMG.mjs → agent-DxTa3PLB.mjs} +2 -2
  3. package/dist/agent-cAPjC2jb.d.mts +922 -0
  4. package/dist/{agent-evals-BFHGypqh.mjs → agent-evals-21LZ_uEl.mjs} +56 -30
  5. package/dist/{agent-export-B9bah0AV.mjs → agent-export-3VheegEK.mjs} +5 -5
  6. package/dist/agent-skills-bundle.d.mts +1 -1
  7. package/dist/{agent-skills-server-DCbAx5WU.d.mts → agent-skills-server-Cix64aGB.d.mts} +2 -2
  8. package/dist/agent-skills-vite.d.mts +3 -3
  9. package/dist/{agents-CR-Uasbc.mjs → agents-ByTdP0Hl.mjs} +4 -4
  10. package/dist/cli/index.mjs +19 -15
  11. package/dist/client/react.d.mts +1 -1
  12. package/dist/{cloud-ask-ai-yR9vZmSG.d.mts → cloud-ask-ai-Bt0rzFbe.d.mts} +1 -1
  13. package/dist/docs-cloud-server.d.mts +2 -2
  14. package/dist/{doctor-BeyN3Ljh.mjs → doctor-C34VVF85.mjs} +9 -8
  15. package/dist/{golden-evaluations-CloP0pAe.mjs → golden-evaluations-D_oDJwGv.mjs} +2 -2
  16. package/dist/index.d.mts +5 -876
  17. package/dist/index.mjs +5 -5
  18. package/dist/{mcp-BLLXvEXB.mjs → mcp-Bnqfu8P5.mjs} +8 -5
  19. package/dist/mcp.d.mts +19 -4
  20. package/dist/mcp.mjs +338 -58
  21. package/dist/{prompt-references-Cz35rlOa.mjs → prompt-references-CfyYOa_W.mjs} +2 -2
  22. package/dist/{search-D1n8Sf25.d.mts → retrieval-digest-CFOcSKTo.d.mts} +49 -50
  23. package/dist/{review-DaJLdPLh.mjs → review-Dw6oCQX3.mjs} +4 -4
  24. package/dist/{robots-BcuxnZqZ.mjs → robots-DaYBoy_A.mjs} +1 -1
  25. package/dist/{robots-DI-9MZz1.mjs → robots-KWLujSLI.mjs} +2 -2
  26. package/dist/{search-RfPcG1if.mjs → search-BmC8wVr0.mjs} +1240 -136
  27. package/dist/{search-DeOJiMAy.mjs → search-DBdmbUkc.mjs} +62 -24
  28. package/dist/server.d.mts +7 -6
  29. package/dist/server.mjs +5 -5
  30. package/dist/{sitemap-BGGbX_KE.mjs → sitemap-CrzG5Wpf.mjs} +4 -4
  31. package/dist/{sitemap-server-VefDnzEB.mjs → sitemap-server-B9LZQ1FE.mjs} +1 -1
  32. package/dist/{standards-discovery-83lp1lew.d.mts → standards-discovery-DBI1PD7m.d.mts} +1 -1
  33. package/dist/{types-_HCPD4wc.d.mts → types-BDRwrExu.d.mts} +65 -1
  34. package/package.json +1 -1
package/dist/mcp.mjs CHANGED
@@ -1,8 +1,8 @@
1
1
  import { a as emitDocsAnalyticsEvent, i as emitDocsAgentTraceEvent, n as createDocsAgentTraceContext, r as createDocsAgentTraceId } from "./analytics-Bx44lg6d.mjs";
2
- import { Kt as normalizeDocsRelated, an as isDocsMcpResourcePath, cn as resolveDocsMcpProtectedResourceMetadataLocation, jt as resolveDocsAudienceMdxContent, ln as resolveDocsMcpResourceLocation, nn as isDocsMcpOAuthScopeToken, on as normalizeDocsMcpAuthorizationServerUrls, qt as renderDocsRelatedMarkdownLines, rn as isDocsMcpProtectedResourceMetadataPath, sn as normalizeDocsMcpEndpointPath } from "./agent-o9OTadrf.mjs";
2
+ import { E as DOCS_MARKDOWN_SECTION_INDEX_FORMAT, Kt as normalizeDocsRelated, P as buildDocsMarkdownSectionIndex, an as isDocsMcpResourcePath, cn as resolveDocsMcpProtectedResourceMetadataLocation, jt as resolveDocsAudienceMdxContent, ln as resolveDocsMcpResourceLocation, nn as isDocsMcpOAuthScopeToken, on as normalizeDocsMcpAuthorizationServerUrls, qt as renderDocsRelatedMarkdownLines, rn as isDocsMcpProtectedResourceMetadataPath, sn as normalizeDocsMcpEndpointPath, wt as toDocsMarkdownUrl } from "./agent-BHqaZx-X.mjs";
3
3
  import { S as upsertPageAgentContractMarkdown, _ as hasStructuredPageAgentContract, o as findDocsMarkdownSection, s as parseDocsMarkdownSections, v as normalizePageAgentFrontmatter } from "./markdown-sections-7OoA7ylx.mjs";
4
4
  import "./standards-discovery-BwL5ffGx.mjs";
5
- import { A as stripGeneratedAgentProvenance, F as emitDocsTelemetryAgentSurfaceEvent, L as emitDocsTelemetryMcpToolEvent, M as resolvePageSidebarFolderIndexBehavior, R as emitDocsTelemetryProjectEvent, S as normalizeAgentScopeValues, b as normalizeAgentFramework, d as performDocsSearch, f as performDocsSearchWithMetadata, u as normalizeDocsSearchFilters, v as agentVersionConstraintMatches, x as normalizeAgentLocale, y as agentVersionConstraintsOverlap } from "./search-RfPcG1if.mjs";
5
+ import { C as agentVersionConstraintsOverlap, E as normalizeAgentScopeValues, I as stripGeneratedAgentProvenance, R as resolvePageSidebarFolderIndexBehavior, S as agentVersionConstraintMatches, T as normalizeAgentLocale, U as emitDocsTelemetryMcpToolEvent, V as emitDocsTelemetryAgentSurfaceEvent, W as emitDocsTelemetryProjectEvent, f as normalizeDocsSearchFilters, k as isDocsRetrievalCanonicalUrl, m as performDocsSearchWithMetadata, p as performDocsSearch, w as normalizeAgentFramework } from "./search-BmC8wVr0.mjs";
6
6
  import matter from "gray-matter";
7
7
  import fs from "node:fs";
8
8
  import path from "node:path";
@@ -1254,18 +1254,27 @@ const DOCS_CONFIG_SCHEMA_OPTIONS_TEMPLATE = [
1254
1254
  default: true,
1255
1255
  description: "Built-in simple search, Typesense, Algolia, MCP, or a custom adapter.",
1256
1256
  docs: "/docs/customization/search",
1257
- children: [{
1258
- path: "search.provider",
1259
- name: "provider",
1260
- type: "\"simple\" | \"typesense\" | \"algolia\" | \"mcp\" | \"custom\"",
1261
- default: "simple",
1262
- description: "Search backend used by the docs UI and MCP search tool."
1263
- }, {
1264
- path: "search.maxResults",
1265
- name: "maxResults",
1266
- type: "number",
1267
- description: "Maximum result count returned by search requests."
1268
- }]
1257
+ children: [
1258
+ {
1259
+ path: "search.provider",
1260
+ name: "provider",
1261
+ type: "\"simple\" | \"typesense\" | \"algolia\" | \"mcp\" | \"custom\"",
1262
+ default: "simple",
1263
+ description: "Search backend used by the docs UI and MCP search tool."
1264
+ },
1265
+ {
1266
+ path: "search.maxResults",
1267
+ name: "maxResults",
1268
+ type: "number",
1269
+ description: "Maximum result count returned by search requests."
1270
+ },
1271
+ {
1272
+ path: "search.syncNamespace",
1273
+ name: "syncNamespace",
1274
+ type: "string",
1275
+ description: "Stable ownership namespace used to isolate and safely prune this corpus in a shared hosted index."
1276
+ }
1277
+ ]
1269
1278
  },
1270
1279
  {
1271
1280
  path: "cloud",
@@ -1479,6 +1488,13 @@ const DOCS_CONFIG_SCHEMA_OPTIONS_TEMPLATE = [
1479
1488
  default: true,
1480
1489
  description: "Expose the list_pages tool."
1481
1490
  },
1491
+ {
1492
+ path: "mcp.tools.listPageSections",
1493
+ name: "listPageSections",
1494
+ type: "boolean",
1495
+ default: true,
1496
+ description: "Expose the body-free list_page_sections discovery tool for page headings, anchors, hierarchy, sizes, and follow-up fetch URLs."
1497
+ },
1482
1498
  {
1483
1499
  path: "mcp.tools.listTasks",
1484
1500
  name: "listTasks",
@@ -1691,7 +1707,7 @@ const searchFilterValueSchema = z.union([z.string().trim().min(1).max(128), z.ar
1691
1707
  const searchDocsInputSchema = z.object({
1692
1708
  query: z.string().trim().min(1),
1693
1709
  limit: z.number().int().min(1).max(25).optional(),
1694
- locale: z.string().min(1).optional(),
1710
+ locale: z.string().trim().min(1).max(128).optional(),
1695
1711
  audience: z.enum(["human", "agent"]).optional(),
1696
1712
  framework: searchFilterValueSchema.optional(),
1697
1713
  version: searchFilterValueSchema.optional(),
@@ -1700,16 +1716,22 @@ const searchDocsInputSchema = z.object({
1700
1716
  });
1701
1717
  const readPageInputSchema = z.object({
1702
1718
  path: z.string().min(1),
1703
- locale: z.string().min(1).optional(),
1719
+ locale: z.string().trim().min(1).max(128).optional(),
1704
1720
  section: z.string().trim().min(1).optional(),
1705
1721
  maxChars: z.number().int().min(256).max(1e6).optional()
1706
1722
  });
1723
+ const listPageSectionsInputSchema = z.object({
1724
+ path: z.string().min(1),
1725
+ locale: z.string().trim().min(1).max(128).optional(),
1726
+ tokenBudget: z.number().int().min(1).max(1e6).optional(),
1727
+ byteBudget: z.number().int().min(1).max(1e6).optional()
1728
+ });
1707
1729
  const listTasksInputSchema = z.object({
1708
1730
  query: z.string().trim().min(1).optional(),
1709
1731
  framework: z.string().trim().min(1).optional(),
1710
1732
  version: z.string().trim().min(1).optional(),
1711
1733
  package: z.string().trim().min(1).optional(),
1712
- locale: z.string().min(1).optional()
1734
+ locale: z.string().trim().min(1).max(128).optional()
1713
1735
  });
1714
1736
  const readTaskInputSchema = readPageInputSchema;
1715
1737
  const pageAgentAppliesToOutputSchema = z.object({
@@ -1768,12 +1790,12 @@ const readTaskOutputSchema = z.object({
1768
1790
  }),
1769
1791
  contract: pageAgentContractOutputSchema
1770
1792
  });
1771
- const listPagesInputSchema = z.object({ locale: z.string().min(1).optional() });
1793
+ const listPagesInputSchema = z.object({ locale: z.string().trim().min(1).max(128).optional() });
1772
1794
  const listDocsInputSchema = z.object({
1773
1795
  section: z.string().trim().min(1).optional(),
1774
- locale: z.string().min(1).optional()
1796
+ locale: z.string().trim().min(1).max(128).optional()
1775
1797
  });
1776
- const getNavigationInputSchema = z.object({ locale: z.string().min(1).optional() });
1798
+ const getNavigationInputSchema = z.object({ locale: z.string().trim().min(1).max(128).optional() });
1777
1799
  const getConfigSchemaInputSchema = z.object({
1778
1800
  option: z.string().trim().min(1).optional(),
1779
1801
  query: z.string().trim().min(1).optional()
@@ -1786,7 +1808,7 @@ const getCodeExamplesInputSchema = z.object({
1786
1808
  language: z.string().trim().min(1).optional(),
1787
1809
  runnable: z.boolean().optional(),
1788
1810
  limit: z.number().int().min(1).max(50).optional(),
1789
- locale: z.string().min(1).optional()
1811
+ locale: z.string().trim().min(1).max(128).optional()
1790
1812
  });
1791
1813
  const getContextInputSchema = z.object({
1792
1814
  query: z.string().trim().min(1),
@@ -1794,7 +1816,7 @@ const getContextInputSchema = z.object({
1794
1816
  version: z.string().trim().min(1).optional(),
1795
1817
  package: searchFilterValueSchema.optional(),
1796
1818
  tags: searchFilterValueSchema.optional(),
1797
- locale: z.string().trim().min(1).optional(),
1819
+ locale: z.string().trim().min(1).max(128).optional(),
1798
1820
  tokenBudget: z.number().int().min(MIN_MCP_CONTEXT_TOKEN_BUDGET).max(MAX_MCP_CONTEXT_TOKEN_BUDGET).default(DEFAULT_MCP_CONTEXT_TOKEN_BUDGET)
1799
1821
  });
1800
1822
  const relatedLinkOutputSchema = z.object({ href: z.string() });
@@ -1854,6 +1876,37 @@ const navigationOutputSchema = z.object({
1854
1876
  }),
1855
1877
  markdown: z.string()
1856
1878
  });
1879
+ const retrievalSourceValueOutputSchema = z.string().max(128);
1880
+ const retrievalSourceValuesOutputSchema = z.array(retrievalSourceValueOutputSchema).max(16);
1881
+ const retrievalSourceScopeOutputSchema = z.object({
1882
+ audience: z.enum(["human", "agent"]),
1883
+ locale: retrievalSourceValuesOutputSchema.optional(),
1884
+ framework: retrievalSourceValuesOutputSchema.optional(),
1885
+ version: retrievalSourceValuesOutputSchema.optional(),
1886
+ versionGroups: z.array(retrievalSourceValuesOutputSchema).max(16).optional(),
1887
+ package: retrievalSourceValuesOutputSchema.optional(),
1888
+ tags: retrievalSourceValuesOutputSchema.optional(),
1889
+ truncated: z.array(z.enum([
1890
+ "framework",
1891
+ "version",
1892
+ "package",
1893
+ "tags"
1894
+ ])).max(4).optional(),
1895
+ conflicts: z.array(z.enum([
1896
+ "framework",
1897
+ "version",
1898
+ "package",
1899
+ "tags"
1900
+ ])).max(4).optional()
1901
+ });
1902
+ const retrievalSourceDigestOutputSchema = z.string().regex(/^sha256:[a-f\d]{64}$/iu);
1903
+ const retrievalSourceOutputSchema = z.object({
1904
+ canonicalUrl: z.string().max(4096).refine(isDocsRetrievalCanonicalUrl, "Expected a safe HTTP(S) URL or root-relative path"),
1905
+ scope: retrievalSourceScopeOutputSchema,
1906
+ lastModified: z.string().max(256).refine((value) => Number.isFinite(Date.parse(value)), "Expected a parseable modified time").optional(),
1907
+ digest: retrievalSourceDigestOutputSchema,
1908
+ indexGeneration: retrievalSourceDigestOutputSchema
1909
+ });
1857
1910
  const searchResultOutputSchema = z.object({
1858
1911
  id: z.string(),
1859
1912
  url: z.string(),
@@ -1865,7 +1918,8 @@ const searchResultOutputSchema = z.object({
1865
1918
  "text"
1866
1919
  ]),
1867
1920
  score: z.number().optional(),
1868
- section: z.string().optional()
1921
+ section: z.string().optional(),
1922
+ source: retrievalSourceOutputSchema.optional()
1869
1923
  });
1870
1924
  const searchFiltersOutputSchema = z.object({
1871
1925
  framework: z.array(z.string()).optional(),
@@ -1896,6 +1950,7 @@ const searchDocsOutputSchema = z.object({
1896
1950
  query: z.string(),
1897
1951
  audience: z.enum(["human", "agent"]),
1898
1952
  filters: searchFiltersOutputSchema,
1953
+ indexGeneration: retrievalSourceDigestOutputSchema,
1899
1954
  resultCount: z.number().int().nonnegative(),
1900
1955
  results: z.array(searchResultOutputSchema),
1901
1956
  warnings: z.array(searchWarningOutputSchema)
@@ -1971,6 +2026,34 @@ const readPageOutputSchema = z.object({
1971
2026
  totalChars: z.number().int().nonnegative(),
1972
2027
  truncated: z.boolean()
1973
2028
  });
2029
+ const pageSectionMetadataOutputSchema = z.object({
2030
+ id: z.string(),
2031
+ heading: z.string(),
2032
+ level: z.number().int().positive(),
2033
+ parentId: z.string().optional(),
2034
+ startLine: z.number().int().positive(),
2035
+ endLine: z.number().int().positive(),
2036
+ estimatedTokens: z.number().int().nonnegative(),
2037
+ utf8Bytes: z.number().int().nonnegative(),
2038
+ canonicalUrl: z.string(),
2039
+ markdownUrl: z.string()
2040
+ });
2041
+ const pageSectionIndexOutputSchema = z.object({
2042
+ schemaVersion: z.literal(2),
2043
+ format: z.literal(DOCS_MARKDOWN_SECTION_INDEX_FORMAT),
2044
+ canonicalUrl: z.string(),
2045
+ markdownUrl: z.string(),
2046
+ sectionIndexUrl: z.string(),
2047
+ lineNumbering: z.literal("body"),
2048
+ sectionCount: z.number().int().nonnegative(),
2049
+ estimatedTokens: z.number().int().nonnegative(),
2050
+ utf8Bytes: z.number().int().nonnegative(),
2051
+ fetchBudget: z.object({
2052
+ tokenBudget: z.number().int().positive().optional(),
2053
+ byteBudget: z.number().int().positive().optional()
2054
+ }).optional(),
2055
+ sections: z.array(pageSectionMetadataOutputSchema)
2056
+ });
1974
2057
  const contextSourceOutputSchema = z.object({
1975
2058
  id: z.string(),
1976
2059
  title: z.string(),
@@ -1985,6 +2068,7 @@ const contextSourceOutputSchema = z.object({
1985
2068
  version: z.string().optional(),
1986
2069
  package: z.array(z.string()).optional(),
1987
2070
  tags: z.array(z.string()).optional(),
2071
+ source: retrievalSourceOutputSchema.optional(),
1988
2072
  score: z.number().optional(),
1989
2073
  content: z.string(),
1990
2074
  chars: z.number().int().nonnegative(),
@@ -2026,6 +2110,7 @@ function resolveDocsMcpConfig(mcp, defaults = {}) {
2026
2110
  tools: {
2027
2111
  listDocs: true,
2028
2112
  listPages: true,
2113
+ listPageSections: true,
2029
2114
  readPage: true,
2030
2115
  listTasks: true,
2031
2116
  readTask: true,
@@ -2046,6 +2131,7 @@ function resolveDocsMcpConfig(mcp, defaults = {}) {
2046
2131
  tools: {
2047
2132
  listDocs: config.tools?.listDocs ?? true,
2048
2133
  listPages: config.tools?.listPages ?? true,
2134
+ listPageSections: config.tools?.listPageSections ?? true,
2049
2135
  readPage: config.tools?.readPage ?? true,
2050
2136
  listTasks: config.tools?.listTasks ?? true,
2051
2137
  readTask: config.tools?.readTask ?? true,
@@ -2156,6 +2242,8 @@ function createFilesystemDocsMcpSource(options = {}) {
2156
2242
  return {
2157
2243
  entry,
2158
2244
  siteTitle: options.siteTitle ?? "Documentation",
2245
+ baseUrl: options.baseUrl,
2246
+ resolveLocale: () => void 0,
2159
2247
  getPages,
2160
2248
  getNavigation
2161
2249
  };
@@ -2192,10 +2280,13 @@ async function createDocsMcpServer(options) {
2192
2280
  };
2193
2281
  const telemetryFramework = options.telemetryFramework ?? "mcp";
2194
2282
  function getSourcePages(locale) {
2195
- return options.source.getPages(locale, options.requestContext);
2283
+ return options.source.getPages(resolveSourceLocale(locale), options.requestContext);
2196
2284
  }
2197
2285
  function getSourceNavigation(locale) {
2198
- return options.source.getNavigation(locale, options.requestContext);
2286
+ return options.source.getNavigation(resolveSourceLocale(locale), options.requestContext);
2287
+ }
2288
+ function resolveSourceLocale(locale) {
2289
+ return options.source.resolveLocale ? options.source.resolveLocale(locale, options.requestContext) : locale;
2199
2290
  }
2200
2291
  function getSourceSkills() {
2201
2292
  return options.source.getSkills?.(options.requestContext) ?? [];
@@ -2811,6 +2902,7 @@ async function createDocsMcpServer(options) {
2811
2902
  const startedAt = nowMs();
2812
2903
  const resolvedLimit = limit ?? 10;
2813
2904
  const resolvedAudience = audience ?? "agent";
2905
+ const resolvedLocale = resolveSourceLocale(locale);
2814
2906
  const filters = {
2815
2907
  framework,
2816
2908
  version,
@@ -2839,13 +2931,15 @@ async function createDocsMcpServer(options) {
2839
2931
  });
2840
2932
  try {
2841
2933
  const searchResponse = await performDocsSearchWithMetadata({
2842
- pages: toSearchSourcePages(dedupePages(await getSourcePages(locale))),
2934
+ pages: toSearchSourcePages(dedupePages(await options.source.getPages(resolvedLocale, options.requestContext))),
2843
2935
  query,
2844
2936
  search: toolSearchConfig ?? true,
2845
2937
  audience: resolvedAudience,
2846
2938
  filters,
2847
- locale,
2939
+ locale: resolvedLocale,
2848
2940
  siteTitle: options.source.siteTitle,
2941
+ baseUrl: options.source.baseUrl ?? (options.requestContext?.request ? new URL(options.requestContext.request.url).origin : void 0),
2942
+ syncBaseUrl: options.source.baseUrl ?? null,
2849
2943
  limit: resolvedLimit
2850
2944
  });
2851
2945
  const elapsed = durationMs(startedAt);
@@ -3012,6 +3106,7 @@ async function createDocsMcpServer(options) {
3012
3106
  annotations: { readOnlyHint: true }
3013
3107
  }, async ({ query, framework, version, package: packageName, tags, locale, tokenBudget }) => {
3014
3108
  const startedAt = nowMs();
3109
+ const resolvedLocale = resolveSourceLocale(locale);
3015
3110
  const trace = createDocsAgentTraceContext("mcp.tool.get_context");
3016
3111
  const callSpanId = createDocsAgentTraceId("span");
3017
3112
  await emitDocsAgentTraceEvent(options.observability, {
@@ -3036,16 +3131,17 @@ async function createDocsMcpServer(options) {
3036
3131
  });
3037
3132
  try {
3038
3133
  const result = await buildDocsMcpContext({
3039
- pages: dedupePages(await getSourcePages(locale)),
3134
+ pages: dedupePages(await options.source.getPages(resolvedLocale, options.requestContext)),
3040
3135
  query,
3041
3136
  framework,
3042
3137
  version,
3043
3138
  package: packageName,
3044
3139
  tags,
3045
- locale,
3140
+ locale: resolvedLocale,
3046
3141
  tokenBudget,
3047
3142
  entry: options.source.entry,
3048
- siteTitle: options.source.siteTitle
3143
+ siteTitle: options.source.siteTitle,
3144
+ baseUrl: options.source.baseUrl ?? (options.requestContext?.request ? new URL(options.requestContext.request.url).origin : void 0)
3049
3145
  });
3050
3146
  const elapsed = durationMs(startedAt);
3051
3147
  await emitDocsAnalyticsEvent(options.analytics, {
@@ -3112,6 +3208,154 @@ async function createDocsMcpServer(options) {
3112
3208
  throw error;
3113
3209
  }
3114
3210
  });
3211
+ if (resolved.tools.listPageSections !== false) server.registerTool("list_page_sections", {
3212
+ title: "List sections in a docs page",
3213
+ description: "Discover a page's canonical headings, anchors, hierarchy, line ranges, size estimates, and budget-aware fetch URLs without returning the page body.",
3214
+ inputSchema: listPageSectionsInputSchema,
3215
+ outputSchema: pageSectionIndexOutputSchema,
3216
+ annotations: { readOnlyHint: true }
3217
+ }, async ({ path: requestedPath, locale, tokenBudget, byteBudget }) => {
3218
+ const startedAt = nowMs();
3219
+ const resolvedLocale = resolveSourceLocale(locale);
3220
+ const trace = createDocsAgentTraceContext("mcp.tool.list_page_sections");
3221
+ const callSpanId = createDocsAgentTraceId("span");
3222
+ await emitDocsAgentTraceEvent(options.observability, {
3223
+ type: "tool.call",
3224
+ source: "mcp",
3225
+ traceId: trace.traceId,
3226
+ spanId: callSpanId,
3227
+ name: "list_page_sections",
3228
+ startedAt: trace.startedAt,
3229
+ status: "started",
3230
+ locale: resolvedLocale,
3231
+ inputPreview: {
3232
+ path: requestedPath,
3233
+ locale,
3234
+ resolvedLocale,
3235
+ tokenBudget,
3236
+ byteBudget
3237
+ },
3238
+ metadata: { tool: "list_page_sections" }
3239
+ });
3240
+ try {
3241
+ const page = findDocsPage(dedupePages(await options.source.getPages(resolvedLocale, options.requestContext)), requestedPath, options.source.entry);
3242
+ if (!page) {
3243
+ const elapsed = durationMs(startedAt);
3244
+ await emitDocsAnalyticsEvent(options.analytics, {
3245
+ type: "mcp_tool",
3246
+ source: "mcp",
3247
+ locale: resolvedLocale,
3248
+ properties: {
3249
+ tool: "list_page_sections",
3250
+ requestedPath,
3251
+ found: false,
3252
+ durationMs: elapsed
3253
+ }
3254
+ });
3255
+ trackMcpTool("list_page_sections", {
3256
+ locale: resolvedLocale,
3257
+ resultCount: 0
3258
+ });
3259
+ await emitDocsAgentTraceEvent(options.observability, {
3260
+ type: "tool.error",
3261
+ source: "mcp",
3262
+ traceId: trace.traceId,
3263
+ parentSpanId: callSpanId,
3264
+ name: "list_page_sections",
3265
+ startedAt: trace.startedAt,
3266
+ endedAt: (/* @__PURE__ */ new Date()).toISOString(),
3267
+ durationMs: elapsed,
3268
+ status: "error",
3269
+ locale: resolvedLocale,
3270
+ outputPreview: {
3271
+ found: false,
3272
+ path: requestedPath
3273
+ },
3274
+ metadata: {
3275
+ tool: "list_page_sections",
3276
+ reason: "not_found"
3277
+ }
3278
+ });
3279
+ return {
3280
+ content: [{
3281
+ type: "text",
3282
+ text: JSON.stringify({ error: `No docs page matched "${requestedPath}".` }, null, 2)
3283
+ }],
3284
+ isError: true
3285
+ };
3286
+ }
3287
+ const document = upsertPageAgentContractMarkdown(getDocsMcpSourceMarkdown(page), page.agent);
3288
+ const publicBaseUrl = options.source.baseUrl ?? (options.requestContext?.request ? new URL(options.requestContext.request.url).origin : void 0);
3289
+ const sectionIndex = buildDocsMarkdownSectionIndex(document, {
3290
+ canonicalUrl: resolveDocsMcpPublicUrl(withDocsMcpUrlLocale(page.url, resolvedLocale), publicBaseUrl),
3291
+ markdownUrl: resolveDocsMcpPublicUrl(toDocsMcpPageMarkdownUrl(page.url, resolvedLocale), publicBaseUrl),
3292
+ tokenBudget,
3293
+ byteBudget
3294
+ });
3295
+ const elapsed = durationMs(startedAt);
3296
+ await emitDocsAnalyticsEvent(options.analytics, {
3297
+ type: "mcp_tool",
3298
+ source: "mcp",
3299
+ locale: resolvedLocale,
3300
+ path: page.url,
3301
+ properties: {
3302
+ tool: "list_page_sections",
3303
+ requestedPath,
3304
+ slug: page.slug,
3305
+ found: true,
3306
+ sectionCount: sectionIndex.sectionCount,
3307
+ estimatedTokens: sectionIndex.estimatedTokens,
3308
+ utf8Bytes: sectionIndex.utf8Bytes,
3309
+ tokenBudget,
3310
+ byteBudget,
3311
+ durationMs: elapsed
3312
+ }
3313
+ });
3314
+ trackMcpTool("list_page_sections", {
3315
+ locale: resolvedLocale,
3316
+ resultCount: sectionIndex.sectionCount
3317
+ });
3318
+ await emitDocsAgentTraceEvent(options.observability, {
3319
+ type: "tool.result",
3320
+ source: "mcp",
3321
+ traceId: trace.traceId,
3322
+ parentSpanId: callSpanId,
3323
+ name: "list_page_sections",
3324
+ startedAt: trace.startedAt,
3325
+ endedAt: (/* @__PURE__ */ new Date()).toISOString(),
3326
+ durationMs: elapsed,
3327
+ status: "success",
3328
+ locale: resolvedLocale,
3329
+ path: page.url,
3330
+ outputPreview: {
3331
+ found: true,
3332
+ slug: page.slug,
3333
+ sectionCount: sectionIndex.sectionCount,
3334
+ estimatedTokens: sectionIndex.estimatedTokens,
3335
+ utf8Bytes: sectionIndex.utf8Bytes
3336
+ },
3337
+ metadata: { tool: "list_page_sections" }
3338
+ });
3339
+ return createStructuredTextResult(sectionIndex);
3340
+ } catch (error) {
3341
+ const elapsed = durationMs(startedAt);
3342
+ await emitDocsAgentTraceEvent(options.observability, {
3343
+ type: "tool.error",
3344
+ source: "mcp",
3345
+ traceId: trace.traceId,
3346
+ parentSpanId: callSpanId,
3347
+ name: "list_page_sections",
3348
+ startedAt: trace.startedAt,
3349
+ endedAt: (/* @__PURE__ */ new Date()).toISOString(),
3350
+ durationMs: elapsed,
3351
+ status: "error",
3352
+ locale: resolvedLocale,
3353
+ outputPreview: { message: error instanceof Error ? error.message : "Unknown error" },
3354
+ metadata: { tool: "list_page_sections" }
3355
+ });
3356
+ throw error;
3357
+ }
3358
+ });
3115
3359
  if (resolved.tools.readPage) server.registerTool("read_page", {
3116
3360
  title: "Read a docs page",
3117
3361
  description: "Read a documentation page by slug or URL path, optionally selecting one heading and limiting returned characters.",
@@ -3831,6 +4075,10 @@ function hasVisibleDescendantFilesystemDocsPage(dir) {
3831
4075
  }
3832
4076
  return false;
3833
4077
  }
4078
+ function normalizeFrontmatterLastmod(value) {
4079
+ if (typeof value === "string") return value;
4080
+ return value instanceof Date && Number.isFinite(value.getTime()) ? value.toISOString() : void 0;
4081
+ }
3834
4082
  function scanFilesystemDocsPages(contentDirAbs, entry, rootDir) {
3835
4083
  const pages = [];
3836
4084
  function scan(dir, slugParts) {
@@ -3865,6 +4113,7 @@ function scanFilesystemDocsPages(contentDirAbs, entry, rootDir) {
3865
4113
  agent: normalizePageAgentFrontmatter(data.agent),
3866
4114
  icon: data.icon,
3867
4115
  sourcePath: path.relative(rootDir, full).replace(/\\/g, "/"),
4116
+ lastmod: normalizeFrontmatterLastmod(data.lastmod),
3868
4117
  lastModified: stat.mtime.toISOString(),
3869
4118
  locale: typeof data.locale === "string" ? data.locale : void 0,
3870
4119
  framework: typeof data.framework === "string" ? data.framework : void 0,
@@ -3889,7 +4138,8 @@ function readFilesystemAgentDoc(dir) {
3889
4138
  const agentContent = resolveDocsAudienceMdxContent(content, "agent");
3890
4139
  return {
3891
4140
  agentContent: stripMarkdownForMcp(agentContent),
3892
- agentRawContent: agentContent
4141
+ agentRawContent: agentContent,
4142
+ agentLastModified: fs.statSync(agentPath).mtime.toISOString()
3893
4143
  };
3894
4144
  }
3895
4145
  function resolveRelatedForMcpPages(pages) {
@@ -4005,25 +4255,7 @@ function dedupePages(pages) {
4005
4255
  return [...seen.values()];
4006
4256
  }
4007
4257
  function toSearchSourcePages(pages) {
4008
- return pages.map((page) => ({
4009
- title: page.title,
4010
- url: page.url,
4011
- content: page.content,
4012
- rawContent: page.rawContent,
4013
- sourcePath: page.sourcePath,
4014
- lastModified: page.lastModified,
4015
- locale: page.locale,
4016
- framework: page.framework,
4017
- version: page.version,
4018
- tags: page.tags,
4019
- agentContent: page.agentContent,
4020
- agentRawContent: page.agentRawContent,
4021
- agentFallbackContent: page.agentFallbackContent,
4022
- agentFallbackRawContent: page.agentFallbackRawContent,
4023
- description: page.description,
4024
- related: page.related,
4025
- agent: page.agent
4026
- }));
4258
+ return pages;
4027
4259
  }
4028
4260
  function getDocsConfigSchema(filters = {}) {
4029
4261
  const option = filters.option?.trim();
@@ -4570,6 +4802,35 @@ function toStructuredDocsMcpPage(page) {
4570
4802
  tags: page.tags
4571
4803
  };
4572
4804
  }
4805
+ function withDocsMcpUrlLocale(value, locale) {
4806
+ if (!locale) return value;
4807
+ const absolute = /^[a-z][a-z\d+.-]*:/iu.test(value);
4808
+ try {
4809
+ const url = new URL(value, "https://docs.invalid");
4810
+ if (!url.searchParams.has("lang")) url.searchParams.set("lang", locale);
4811
+ return absolute ? url.toString() : `${url.pathname}${url.search}${url.hash}`;
4812
+ } catch {
4813
+ return value;
4814
+ }
4815
+ }
4816
+ function toDocsMcpPageMarkdownUrl(value, locale) {
4817
+ const absolute = /^[a-z][a-z\d+.-]*:/iu.test(value);
4818
+ try {
4819
+ const url = new URL(value, "https://docs.invalid");
4820
+ const markdownPath = toDocsMarkdownUrl(`${url.pathname}${url.search}${url.hash}`, { locale });
4821
+ return absolute ? new URL(markdownPath, url.origin).toString() : markdownPath;
4822
+ } catch {
4823
+ return toDocsMarkdownUrl(value, { locale });
4824
+ }
4825
+ }
4826
+ function resolveDocsMcpPublicUrl(value, baseUrl) {
4827
+ if (!baseUrl || /^[a-z][a-z\d+.-]*:/iu.test(value)) return value;
4828
+ try {
4829
+ return new URL(value, `${baseUrl.replace(/\/+$/u, "")}/`).toString();
4830
+ } catch {
4831
+ return value;
4832
+ }
4833
+ }
4573
4834
  function getDocsMcpSourceMarkdown(page) {
4574
4835
  return page.agentRawContent ?? page.agentFallbackRawContent ?? page.agentContent ?? page.agentFallbackContent ?? page.rawContent ?? page.content;
4575
4836
  }
@@ -4637,10 +4898,13 @@ async function buildDocsMcpContext(options) {
4637
4898
  }] : [];
4638
4899
  });
4639
4900
  const scopedPages = scopedPageEntries.map(({ page }) => page);
4901
+ const allSearchPages = toSearchSourcePages([...options.pages]);
4902
+ const searchPageBySource = new Map(options.pages.map((page, index) => [page, allSearchPages[index]]));
4640
4903
  const scopeByPage = new Map(scopedPageEntries.map(({ page, scope }) => [page, scope]));
4641
4904
  const maxResults = typeof options.maxResults === "number" && Number.isFinite(options.maxResults) ? Math.max(1, Math.min(50, Math.floor(options.maxResults))) : 50;
4642
4905
  const orderedResults = [...await performDocsSearch({
4643
- pages: toSearchSourcePages(scopedPages),
4906
+ pages: scopedPages.map((page) => searchPageBySource.get(page)),
4907
+ generationPages: allSearchPages,
4644
4908
  query: options.query,
4645
4909
  search: {
4646
4910
  enabled: true,
@@ -4651,6 +4915,7 @@ async function buildDocsMcpContext(options) {
4651
4915
  audience: "agent",
4652
4916
  locale: options.locale,
4653
4917
  siteTitle: options.siteTitle,
4918
+ baseUrl: options.baseUrl,
4654
4919
  limit: 50
4655
4920
  })].sort((left, right) => {
4656
4921
  const scoreDelta = (right.score ?? 0) - (left.score ?? 0);
@@ -4696,7 +4961,7 @@ async function buildDocsMcpContext(options) {
4696
4961
  let usedUtf8Bytes = 0;
4697
4962
  for (const { result, page, scope, selectedSection, rawContent } of resolvedCandidates) {
4698
4963
  const anchor = selectedSection?.anchor;
4699
- const sourceUrl = anchor ? `${page.url.split("#", 1)[0]}#${encodeURIComponent(anchor)}` : page.url;
4964
+ const sourceUrl = result.source?.canonicalUrl ?? (anchor ? `${page.url.split("#", 1)[0]}#${encodeURIComponent(anchor)}` : page.url);
4700
4965
  const headerLines = [`## ${page.title}`, `Source: ${sourceUrl}`];
4701
4966
  if (selectedSection?.title) headerLines.push(`Section: ${selectedSection.title}`);
4702
4967
  if (scope.framework) headerLines.push(`Framework: ${scope.framework}`);
@@ -4723,12 +4988,13 @@ async function buildDocsMcpContext(options) {
4723
4988
  section: selectedSection?.title,
4724
4989
  anchor,
4725
4990
  sourcePath: page.sourcePath,
4726
- lastModified: page.lastModified,
4991
+ lastModified: result.source?.lastModified ?? page.lastModified,
4727
4992
  locale: scope.locale,
4728
4993
  framework: scope.framework,
4729
4994
  version: scope.version,
4730
4995
  package: scope.package.length > 0 ? [...scope.package] : void 0,
4731
4996
  tags: scope.tags.length > 0 ? [...scope.tags] : void 0,
4997
+ source: result.source,
4732
4998
  score: result.score,
4733
4999
  content: limited.text,
4734
5000
  chars: limited.text.length,
@@ -4770,11 +5036,25 @@ async function buildDocsMcpContext(options) {
4770
5036
  };
4771
5037
  }
4772
5038
  function findDocsPage(pages, requestedPath, entry) {
4773
- const normalizedRequest = normalizeRequestedPath(requestedPath, entry);
4774
- for (const page of pages) if (normalizeUrlPath(page.url) === normalizedRequest) return page;
4775
- const normalizedSlug = normalizePathSegment(requestedPath.replace(/^\//, ""));
4776
- for (const page of pages) if (normalizePathSegment(page.slug) === normalizedSlug) return page;
4777
- return null;
5039
+ const normalizedRequest = normalizeDocsMcpPageIdentity(requestedPath, entry, true);
5040
+ for (const page of pages) if (normalizeDocsMcpPageIdentity(page.url, entry, true) === normalizedRequest) return page;
5041
+ const normalizedRequestPath = normalizeDocsMcpPageIdentity(requestedPath, entry, false);
5042
+ const pathMatches = pages.filter((page) => normalizeDocsMcpPageIdentity(page.url, entry, false) === normalizedRequestPath);
5043
+ if (pathMatches.length === 1) return pathMatches[0];
5044
+ if (pathMatches.length > 1) return null;
5045
+ const normalizedSlug = normalizePathSegment(normalizeDocsMcpPageIdentity(requestedPath, void 0, false).replace(/^\//u, ""));
5046
+ const slugMatches = pages.filter((page) => normalizePathSegment(page.slug) === normalizedSlug);
5047
+ return slugMatches.length === 1 ? slugMatches[0] : null;
5048
+ }
5049
+ function normalizeDocsMcpPageIdentity(value, entry, includeSearch) {
5050
+ try {
5051
+ const url = new URL(value, "https://docs.local");
5052
+ if (includeSearch) url.searchParams.sort();
5053
+ return `${normalizeRequestedPath(url.pathname, entry)}${includeSearch ? url.search : ""}`;
5054
+ } catch {
5055
+ const [pathname = value, search = ""] = value.split("?", 2);
5056
+ return `${normalizeRequestedPath(pathname, entry)}${includeSearch && search ? `?${search}` : ""}`;
5057
+ }
4778
5058
  }
4779
5059
  function normalizeRequestedPath(requestedPath, entry) {
4780
5060
  const trimmed = requestedPath.trim();
@@ -1,7 +1,7 @@
1
- import { It as DEFAULT_SITEMAP_XML_ROUTE, Pt as DEFAULT_SITEMAP_MD_ROUTE, Zt as DEFAULT_MCP_WELL_KNOWN_ROUTE, c as DEFAULT_AGENT_SPEC_WELL_KNOWN_JSON_ROUTE, f as DEFAULT_DOCS_CONFIG_ROUTE, h as DEFAULT_LLMS_FULL_TXT_ROUTE, i as DEFAULT_AGENT_FEEDBACK_ROUTE, m as DEFAULT_DOCS_DIAGNOSTICS_ROUTE, t as DEFAULT_AGENTS_MD_ROUTE, v as DEFAULT_LLMS_TXT_ROUTE, x as DEFAULT_SKILL_MD_ROUTE } from "./agent-o9OTadrf.mjs";
1
+ import { It as DEFAULT_SITEMAP_XML_ROUTE, Pt as DEFAULT_SITEMAP_MD_ROUTE, Zt as DEFAULT_MCP_WELL_KNOWN_ROUTE, c as DEFAULT_AGENT_SPEC_WELL_KNOWN_JSON_ROUTE, f as DEFAULT_DOCS_CONFIG_ROUTE, h as DEFAULT_LLMS_FULL_TXT_ROUTE, i as DEFAULT_AGENT_FEEDBACK_ROUTE, m as DEFAULT_DOCS_DIAGNOSTICS_ROUTE, t as DEFAULT_AGENTS_MD_ROUTE, v as DEFAULT_LLMS_TXT_ROUTE, x as DEFAULT_SKILL_MD_ROUTE } from "./agent-BHqaZx-X.mjs";
2
2
  import { isDocsAgentSkillName, validateDocsAgentSkillFrontmatter } from "./agent-skills-spec.mjs";
3
3
  import { C as DOCS_AGENT_MANIFEST_SCHEMA_MEDIA_TYPE, S as DOCS_AGENT_MANIFEST_FORMAT, T as DOCS_AGENT_MANIFEST_VERSION, f as DEFAULT_AGENT_SKILLS_ROUTE_PREFIX, n as API_CATALOG_MEDIA_TYPE, r as API_CATALOG_PROFILE_URI, t as AGENT_SKILLS_DISCOVERY_SCHEMA_URI, u as DEFAULT_AGENT_SKILLS_INDEX_ROUTE, v as DEFAULT_API_CATALOG_ROUTE, w as DOCS_AGENT_MANIFEST_SCHEMA_URI } from "./standards-discovery-BwL5ffGx.mjs";
4
- import { n as DEFAULT_ROBOTS_TXT_ROUTE } from "./robots-BcuxnZqZ.mjs";
4
+ import { n as DEFAULT_ROBOTS_TXT_ROUTE } from "./robots-DaYBoy_A.mjs";
5
5
  import matter from "gray-matter";
6
6
 
7
7
  //#region src/define-docs.ts