@farming-labs/docs 0.2.52 → 0.2.54

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 (51) hide show
  1. package/dist/agent-BXvi0uhS.mjs +623 -0
  2. package/dist/{agent-CaOBIVFy.mjs → agent-DXkXi-pS.mjs} +765 -22
  3. package/dist/agent-evals-BD17jOqL.mjs +1166 -0
  4. package/dist/agent-export-n-a0GbeU.mjs +854 -0
  5. package/dist/agent-scope-B8lptqCd.mjs +283 -0
  6. package/dist/agent-surface-drift-LS8zQgbq.mjs +1429 -0
  7. package/dist/{agents-DjhjZaNP.mjs → agents-BJaRQimo.mjs} +7 -5
  8. package/dist/{analytics-BZEwTK-8.mjs → analytics-Bx44lg6d.mjs} +1 -1
  9. package/dist/cli/index.mjs +43 -28
  10. package/dist/client/react.d.mts +1 -1
  11. package/dist/client/react.mjs +1 -1
  12. package/dist/{cloud-C_Ok9rC5.mjs → cloud-HWFlbfLJ.mjs} +4 -4
  13. package/dist/{cloud-ask-ai-Cl-xaV8j.mjs → cloud-ask-ai-1k0q6OAH.mjs} +1 -1
  14. package/dist/{cloud-ask-ai-DcMe6xOf.d.mts → cloud-ask-ai-466g6uAi.d.mts} +1 -1
  15. package/dist/code-blocks-C9awWzEQ.mjs +871 -0
  16. package/dist/codeblocks-BzfkREEC.mjs +250 -0
  17. package/dist/{config-tiQCZ46q.mjs → config-CydaZ5PB.mjs} +52 -11
  18. package/dist/{dev-Tm9Ss4D6.mjs → dev-BA2kRuCn.mjs} +3 -3
  19. package/dist/docs-cloud-server.d.mts +2 -2
  20. package/dist/docs-cloud-server.mjs +2 -2
  21. package/dist/{doctor-O9o9kjN8.mjs → doctor-CQpQ2zZm.mjs} +177 -47
  22. package/dist/{downgrade-CYEaOctn.mjs → downgrade-BStNhyCc.mjs} +2 -2
  23. package/dist/i18n-CAlj1ADU.mjs +40 -0
  24. package/dist/index.d.mts +158 -3
  25. package/dist/index.mjs +7 -6
  26. package/dist/{init-Ch5On0zm.mjs → init-gnHQ_Pz9.mjs} +3 -3
  27. package/dist/{mcp-DuCPNHS-.mjs → mcp-DnxZZWpY.mjs} +10 -5
  28. package/dist/mcp.d.mts +122 -6
  29. package/dist/mcp.mjs +1943 -86
  30. package/dist/{package-version-C8PigBZk.mjs → package-version-DRIc08EU.mjs} +1 -1
  31. package/dist/{reading-time-CPAy1SWO.mjs → reading-time-BrTd3DIh.mjs} +277 -33
  32. package/dist/{review-lm3dt7yy.mjs → review-B6gyEFkD.mjs} +184 -14
  33. package/dist/{robots-DV7u4Ire.mjs → robots-4BUJxlvV.mjs} +4 -4
  34. package/dist/{robots-XVPs9lVz.mjs → robots-DAptQnkx.mjs} +1 -1
  35. package/dist/{search-BWuU70B0.mjs → search-CJIC1Cqo.mjs} +173 -79
  36. package/dist/{search-B6nEkx86.mjs → search-CbPm2x5g.mjs} +6 -4
  37. package/dist/{search-DFEhf9-s.d.mts → search-CfWvmVYA.d.mts} +3 -1
  38. package/dist/server.d.mts +108 -5
  39. package/dist/server.mjs +9 -8
  40. package/dist/{sitemap-BEiKy4Iy.mjs → sitemap-D6nP3J1Q.mjs} +8 -6
  41. package/dist/{sitemap-server-xEHtDUDB.mjs → sitemap-server-wsNLyVkb.mjs} +1 -1
  42. package/dist/{templates-uaauJcTO.mjs → templates-1Cod8KrJ.mjs} +11 -5
  43. package/dist/{types-XqGLsmOD.d.mts → types-BVgucdVm.d.mts} +194 -2
  44. package/dist/{upgrade-DzQtpgJM.mjs → upgrade-CXYRNV0C.mjs} +2 -2
  45. package/package.json +1 -1
  46. package/dist/agent-DXDOMJBw.mjs +0 -9
  47. package/dist/codeblocks-z9iT794h.mjs +0 -1713
  48. package/dist/review-B7goPYUb.mjs +0 -541
  49. /package/dist/{cloud-analytics-Dlk_byos.mjs → cloud-analytics-CSyFE6SS.mjs} +0 -0
  50. /package/dist/{errors-CW1LnxaQ.mjs → errors-BFUtdZfC.mjs} +0 -0
  51. /package/dist/{utils-D-xTRNuh.mjs → utils-DBCCkkJS.mjs} +0 -0
@@ -1,13 +1,16 @@
1
- import "./reading-time-CPAy1SWO.mjs";
2
- import { Ct as DEFAULT_SITEMAP_XML_ROUTE, P as buildDocsMcpEndpointCandidates, S as DEFAULT_MCP_WELL_KNOWN_ROUTE, St as DEFAULT_SITEMAP_MD_WELL_KNOWN_ROUTE, T as DEFAULT_SKILL_MD_WELL_KNOWN_ROUTE, b as DEFAULT_MCP_PUBLIC_ROUTE, c as DEFAULT_AGENT_SPEC_WELL_KNOWN_JSON_ROUTE, h as DEFAULT_LLMS_FULL_TXT_ROUTE, i as DEFAULT_AGENT_FEEDBACK_ROUTE, kt as resolveDocsSitemapConfig, l as DEFAULT_AGENT_SPEC_WELL_KNOWN_ROUTE, n as DEFAULT_AGENTS_MD_WELL_KNOWN_ROUTE, t as DEFAULT_AGENTS_MD_ROUTE, v as DEFAULT_LLMS_TXT_ROUTE, w as DEFAULT_SKILL_MD_ROUTE, xt as DEFAULT_SITEMAP_MD_ROUTE } from "./agent-CaOBIVFy.mjs";
3
- import "./search-BWuU70B0.mjs";
4
- import { a as analyzeDocsRobotsTxt, n as DEFAULT_ROBOTS_TXT_ROUTE, u as resolveDocsRobotsConfig } from "./robots-XVPs9lVz.mjs";
5
- import "./sitemap-server-xEHtDUDB.mjs";
6
- import { createFilesystemDocsMcpSource, resolveDocsMcpConfig } from "./mcp.mjs";
1
+ import { i as scanDocsPageTargets, n as compactAgentDocs, r as inspectAgentCompactionState } from "./agent-BXvi0uhS.mjs";
2
+ import "./reading-time-BrTd3DIh.mjs";
3
+ import { Bt as PAGE_AGENT_CONTRACT_FIELDS, Dt as DEFAULT_SITEMAP_XML_ROUTE, Et as DEFAULT_SITEMAP_MD_WELL_KNOWN_ROUTE, I as buildDocsMcpEndpointCandidates, M as buildDocsAgentDiscoverySpec, Nt as resolveDocsSitemapConfig, O as DOCS_CONFIG_MAP_TOP_LEVEL_KEYS, P as buildDocsConfigMap, S as DEFAULT_MCP_WELL_KNOWN_ROUTE, T as DEFAULT_SKILL_MD_WELL_KNOWN_ROUTE, Tt as DEFAULT_SITEMAP_MD_ROUTE, b as DEFAULT_MCP_PUBLIC_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, l as DEFAULT_AGENT_SPEC_WELL_KNOWN_ROUTE, n as DEFAULT_AGENTS_MD_WELL_KNOWN_ROUTE, t as DEFAULT_AGENTS_MD_ROUTE, u as DEFAULT_DOCS_API_ROUTE, v as DEFAULT_LLMS_TXT_ROUTE, w as DEFAULT_SKILL_MD_ROUTE } from "./agent-DXkXi-pS.mjs";
4
+ import "./search-CJIC1Cqo.mjs";
5
+ import { a as analyzeDocsRobotsTxt, n as DEFAULT_ROBOTS_TXT_ROUTE, u as resolveDocsRobotsConfig } from "./robots-DAptQnkx.mjs";
6
+ import "./sitemap-server-wsNLyVkb.mjs";
7
+ import { t as runDocsGoldenTasks } from "./agent-evals-BD17jOqL.mjs";
8
+ import { createFilesystemDocsMcpSource, getDocsConfigSchema, resolveDocsMcpConfig } from "./mcp.mjs";
9
+ import "./code-blocks-C9awWzEQ.mjs";
7
10
  import "./server.mjs";
8
- import { a as loadProjectEnv, c as readNavTitle, f as readTopLevelStringProperty, i as loadDocsConfigModule, m as resolveDocsContentDir, o as readBooleanProperty, p as resolveDocsConfigPath, r as extractTopLevelConfigObject, t as extractNestedObjectLiteral } from "./config-tiQCZ46q.mjs";
9
- import { t as detectFramework } from "./utils-D-xTRNuh.mjs";
10
- import { n as inspectAgentCompactionState, o as scanDocsPageTargets, t as compactAgentDocs } from "./codeblocks-z9iT794h.mjs";
11
+ import { a as loadDocsConfigModuleResultWithProjectEnv, h as resolveDocsContentDir, l as readNavTitle, m as resolveDocsConfigPath, p as readTopLevelStringProperty, r as extractTopLevelConfigObject, s as readBooleanProperty, t as extractNestedObjectLiteral } from "./config-CydaZ5PB.mjs";
12
+ import { t as detectFramework } from "./utils-DBCCkkJS.mjs";
13
+ import { n as analyzeAgentUsefulness, r as createAgentUsefulnessPagesFromMcp, t as analyzeAgentSurfaceDrift } from "./agent-surface-drift-LS8zQgbq.mjs";
11
14
  import { existsSync, lstatSync, readFileSync, readdirSync } from "node:fs";
12
15
  import path from "node:path";
13
16
  import { LATEST_PROTOCOL_VERSION } from "@modelcontextprotocol/sdk/types.js";
@@ -583,8 +586,18 @@ function navigationScore(navigationCoverage) {
583
586
  score: 0
584
587
  };
585
588
  }
586
- function gradeForAgentScore(score) {
587
- if (score >= 90) return "Agent-optimized";
589
+ const AGENT_OPTIMIZATION_BLOCKING_CHECKS = new Set([
590
+ "surface-drift",
591
+ "agent-context-quality",
592
+ "agent-task-completeness",
593
+ "agent-applicability",
594
+ "command-health",
595
+ "related-coverage",
596
+ "golden-tasks"
597
+ ]);
598
+ function gradeForAgentScore(score, checks = []) {
599
+ const hasBlockingFailure = checks.some((check) => check.status === "fail" && AGENT_OPTIMIZATION_BLOCKING_CHECKS.has(check.id));
600
+ if (score >= 90 && !hasBlockingFailure) return "Agent-optimized";
588
601
  if (score >= 75) return "Agent-ready";
589
602
  if (score >= 60) return "Promising";
590
603
  return "Needs work";
@@ -631,6 +644,20 @@ function buildCoverage(pages) {
631
644
  }
632
645
  };
633
646
  }
647
+ function scoreUsefulnessCoverage(completed, total, maxScore) {
648
+ if (total === 0) return {
649
+ status: "warn",
650
+ score: 0,
651
+ coverage: 0
652
+ };
653
+ const coverage = Math.round(completed / total * 100);
654
+ const score = Math.round(coverage / 100 * maxScore);
655
+ return {
656
+ status: coverage >= 80 ? "pass" : coverage > 0 ? "warn" : "fail",
657
+ score,
658
+ coverage
659
+ };
660
+ }
634
661
  function buildCompactionCoverage(rootDir, contentDir, entry, pages, defaults) {
635
662
  const targets = scanDocsPageTargets(rootDir, contentDir, entry);
636
663
  const targetsBySlug = new Map(targets.map((target) => [target.slug, target]));
@@ -962,7 +989,7 @@ async function postMcpJson(baseUrl, route, body, sessionId) {
962
989
  body: JSON.stringify(body)
963
990
  });
964
991
  }
965
- async function probeMcpRoute(baseUrl, route) {
992
+ async function probeMcpRoute(baseUrl, route, expectedTools) {
966
993
  try {
967
994
  const initializeResponse = await postMcpJson(baseUrl, route, {
968
995
  jsonrpc: "2.0",
@@ -1008,15 +1035,7 @@ async function probeMcpRoute(baseUrl, route) {
1008
1035
  };
1009
1036
  const tools = toolsPayload.result?.tools;
1010
1037
  const toolNames = Array.isArray(tools) ? tools.map((tool) => tool.name).filter((name) => typeof name === "string") : [];
1011
- const missingTools = [
1012
- "list_docs",
1013
- "list_pages",
1014
- "get_navigation",
1015
- "search_docs",
1016
- "read_page",
1017
- "get_code_examples",
1018
- "get_config_schema"
1019
- ].filter((tool) => !toolNames.includes(tool));
1038
+ const missingTools = expectedTools.filter((tool) => !toolNames.includes(tool));
1020
1039
  if (missingTools.length > 0) return {
1021
1040
  ok: false,
1022
1041
  detail: `${route} connected but is missing tools: ${missingTools.join(", ")}.`
@@ -1032,10 +1051,10 @@ async function probeMcpRoute(baseUrl, route) {
1032
1051
  };
1033
1052
  }
1034
1053
  }
1035
- async function probeMcpRouteCandidates(baseUrl, routes) {
1054
+ async function probeMcpRouteCandidates(baseUrl, routes, expectedTools) {
1036
1055
  const candidates = buildDocsMcpEndpointCandidates(baseUrl, routes);
1037
1056
  const probes = await Promise.all(candidates.map(async (candidate) => {
1038
- const probe = await probeMcpRoute(candidate.baseUrl, candidate.route);
1057
+ const probe = await probeMcpRoute(candidate.baseUrl, candidate.route, expectedTools);
1039
1058
  return {
1040
1059
  ...probe,
1041
1060
  detail: `${candidate.label}: ${probe.detail}`
@@ -1049,6 +1068,44 @@ async function probeMcpRouteCandidates(baseUrl, routes) {
1049
1068
  function asRecord(value) {
1050
1069
  return value && typeof value === "object" ? value : void 0;
1051
1070
  }
1071
+ function isPlainRecord(value) {
1072
+ return Boolean(asRecord(value)) && !Array.isArray(value);
1073
+ }
1074
+ function resolveGoldenEvaluationTasks(evaluationInput) {
1075
+ if (evaluationInput === void 0 || typeof evaluationInput === "boolean") return void 0;
1076
+ if (!isPlainRecord(evaluationInput)) return { evaluationConfig: evaluationInput };
1077
+ if (evaluationInput.enabled === false) return void 0;
1078
+ if ("enabled" in evaluationInput && typeof evaluationInput.enabled !== "boolean") return evaluationInput;
1079
+ if (!("tasks" in evaluationInput)) return void 0;
1080
+ const runtimeTasks = evaluationInput.tasks;
1081
+ if (!Array.isArray(runtimeTasks)) return runtimeTasks;
1082
+ return runtimeTasks.map((task) => {
1083
+ if (!isPlainRecord(task)) return task;
1084
+ return {
1085
+ ...task,
1086
+ tokenBudget: task.tokenBudget ?? evaluationInput.tokenBudget,
1087
+ topK: task.topK ?? evaluationInput.topK
1088
+ };
1089
+ });
1090
+ }
1091
+ function isNonEmptyString(value) {
1092
+ return typeof value === "string" && value.trim().length > 0;
1093
+ }
1094
+ function isBooleanRecord(value) {
1095
+ const record = asRecord(value);
1096
+ return Boolean(record && Object.keys(record).length > 0 && Object.values(record).every((item) => typeof item === "boolean"));
1097
+ }
1098
+ function isHostedAgentDiscoveryManifest(value) {
1099
+ const root = asRecord(value);
1100
+ const site = asRecord(root?.site);
1101
+ const capabilities = asRecord(root?.capabilities);
1102
+ const api = asRecord(root?.api);
1103
+ const config = asRecord(root?.config);
1104
+ const search = asRecord(root?.search);
1105
+ const mcp = asRecord(root?.mcp);
1106
+ const agentContractFields = asRecord(asRecord(root?.agentContract)?.fields);
1107
+ return Boolean(root && isNonEmptyString(root.version) && isNonEmptyString(root.name) && isNonEmptyString(root.baseUrl) && isNonEmptyString(site?.entry) && typeof capabilities?.search === "boolean" && typeof capabilities?.mcp === "boolean" && isNonEmptyString(api?.docs) && isNonEmptyString(api?.config) && isNonEmptyString(config?.endpoint) && typeof search?.enabled === "boolean" && isNonEmptyString(search?.endpoint) && typeof mcp?.enabled === "boolean" && isNonEmptyString(mcp?.endpoint) && isBooleanRecord(mcp?.tools) && agentContractFields && Object.keys(agentContractFields).length > 0);
1108
+ }
1052
1109
  function readDiscoveryRoute(value) {
1053
1110
  return typeof value === "string" && value.startsWith("/") ? value : void 0;
1054
1111
  }
@@ -1085,6 +1142,22 @@ function hostedMcpRoutes(discoveryBody) {
1085
1142
  if (declaredRoutes.length > 0) return Array.from(new Set(declaredRoutes));
1086
1143
  return Array.from(new Set([readDiscoveryRoute(mcp?.publicEndpoint) ?? DEFAULT_MCP_PUBLIC_ROUTE, readDiscoveryRoute(mcp?.wellKnownEndpoint) ?? DEFAULT_MCP_WELL_KNOWN_ROUTE]));
1087
1144
  }
1145
+ const MCP_DISCOVERY_TOOL_NAMES = [
1146
+ ["listDocs", "list_docs"],
1147
+ ["listPages", "list_pages"],
1148
+ ["listTasks", "list_tasks"],
1149
+ ["readTask", "read_task"],
1150
+ ["getNavigation", "get_navigation"],
1151
+ ["searchDocs", "search_docs"],
1152
+ ["readPage", "read_page"],
1153
+ ["getCodeExamples", "get_code_examples"],
1154
+ ["getConfigSchema", "get_config_schema"],
1155
+ ["getContext", "get_context"]
1156
+ ];
1157
+ function hostedMcpExpectedTools(discoveryBody) {
1158
+ const tools = asRecord(asRecord(asRecord(discoveryBody)?.mcp)?.tools);
1159
+ return MCP_DISCOVERY_TOOL_NAMES.filter(([flag]) => tools?.[flag] !== false).map(([, name]) => name);
1160
+ }
1088
1161
  function hostedCapability(discoveryBody, key) {
1089
1162
  const root = asRecord(discoveryBody);
1090
1163
  const capability = asRecord(root?.capabilities)?.[key];
@@ -1181,7 +1254,8 @@ async function buildHostedAgentChecks(url, pages) {
1181
1254
  }
1182
1255
  const checks = [];
1183
1256
  const discovery = await probeJsonRoute(baseUrl, DEFAULT_AGENT_SPEC_WELL_KNOWN_JSON_ROUTE);
1184
- checks.push(makeCheck("hosted-agent-discovery", "Hosted agent discovery", discovery.ok ? "pass" : "fail", discovery.ok ? 5 : 0, 5, `${baseUrl}: ${discovery.detail}`, discovery.ok ? void 0 : `Make sure ${DEFAULT_AGENT_SPEC_WELL_KNOWN_JSON_ROUTE} is routed to the shared docs API on the deployed site.`));
1257
+ const discoveryManifestValid = discovery.ok && isHostedAgentDiscoveryManifest(discovery.body);
1258
+ checks.push(makeCheck("hosted-agent-discovery", "Hosted agent discovery", discoveryManifestValid ? "pass" : "fail", discoveryManifestValid ? 5 : 0, 5, `${baseUrl}: ${discovery.ok && !discoveryManifestValid ? `${discovery.detail} The payload is not a complete agent discovery manifest.` : discovery.detail}`, discoveryManifestValid ? void 0 : `Make sure ${DEFAULT_AGENT_SPEC_WELL_KNOWN_JSON_ROUTE} returns the complete agent discovery manifest from the shared docs API.`));
1185
1259
  const llms = await Promise.all([probeTextRoute(baseUrl, DEFAULT_LLMS_TXT_ROUTE), probeTextRoute(baseUrl, DEFAULT_LLMS_FULL_TXT_ROUTE)]);
1186
1260
  const llmsPassed = llms.filter((result) => result.ok).length;
1187
1261
  checks.push(makeCheck("hosted-llms", "Hosted llms.txt", llmsPassed === llms.length ? "pass" : llmsPassed > 0 ? "warn" : "fail", llmsPassed === llms.length ? 5 : llmsPassed > 0 ? 3 : 0, 5, llms.map((result) => result.detail).join(" "), llmsPassed === llms.length ? void 0 : "Verify deployed /llms.txt and /llms-full.txt routes return non-empty text."));
@@ -1226,27 +1300,18 @@ async function buildHostedAgentChecks(url, pages) {
1226
1300
  const markdownAlternateScore = hostedSurfaceScore(htmlPageProbes, (probe) => probe.hasMarkdownAlternate);
1227
1301
  const markdownRoutesEnabled = hostedCapability(discovery.body, "markdownRoutes");
1228
1302
  checks.push(makeCheck("hosted-markdown-alternate", "Hosted markdown alternate links", markdownRoutesEnabled === false ? "warn" : markdownAlternateScore.status, markdownRoutesEnabled === false ? 0 : markdownAlternateScore.score, 5, markdownRoutesEnabled === false ? "The hosted discovery spec reports markdown routes as disabled." : markdownAlternateScore.total > 0 ? `${markdownAlternateScore.passed}/${markdownAlternateScore.total} sampled hosted docs pages include <link rel="alternate" type="text/markdown"> pointing to .md routes.` : "No hosted docs pages were available to verify markdown alternate links.", markdownRoutesEnabled === false || markdownAlternateScore.status === "pass" ? void 0 : "Add a text/markdown alternate link in each docs page head, usually through `alternates.types['text/markdown']`, so agents can discover the page markdown URL from HTML."));
1229
- const mcp = await probeMcpRouteCandidates(baseUrl, hostedMcpRoutes(discovery.body));
1230
- const mcpPassed = mcp.probes.filter((result) => result.ok).length;
1231
- const mcpDetailProbes = mcpPassed > 0 ? mcp.probes.filter((result) => result.ok) : mcp.probes;
1232
- checks.push(makeCheck("hosted-mcp", "Hosted MCP handshake", mcpPassed > 0 ? "pass" : "fail", mcpPassed > 0 ? 10 : 0, 10, mcpDetailProbes.map((result) => result.detail).join(" "), mcpPassed > 0 ? void 0 : `Verify one of ${mcp.labels.join(" or ")} supports Streamable HTTP initialize and tools/list.`));
1303
+ if (hostedCapability(discovery.body, "mcp") === false) checks.push(makeCheck("hosted-mcp", "Hosted MCP handshake", "warn", 0, 10, "The hosted discovery spec reports MCP as disabled.", "Enable MCP when agents should use structured list/search/read tools."));
1304
+ else {
1305
+ const mcp = await probeMcpRouteCandidates(baseUrl, hostedMcpRoutes(discovery.body), hostedMcpExpectedTools(discovery.body));
1306
+ const mcpPassed = mcp.probes.filter((result) => result.ok).length;
1307
+ const mcpDetailProbes = mcpPassed > 0 ? mcp.probes.filter((result) => result.ok) : mcp.probes;
1308
+ checks.push(makeCheck("hosted-mcp", "Hosted MCP handshake", mcpPassed > 0 ? "pass" : "fail", mcpPassed > 0 ? 10 : 0, 10, mcpDetailProbes.map((result) => result.detail).join(" "), mcpPassed > 0 ? void 0 : `Verify one of ${mcp.labels.join(" or ")} supports Streamable HTTP initialize and tools/list.`));
1309
+ }
1233
1310
  return {
1234
1311
  baseUrl,
1235
1312
  checks
1236
1313
  };
1237
1314
  }
1238
- async function loadDocsConfigModuleWithProjectEnv(rootDir, explicitPath) {
1239
- const env = loadProjectEnv(rootDir);
1240
- const injectedKeys = Object.entries(env).filter(([key]) => process.env[key] === void 0).map(([key, value]) => {
1241
- process.env[key] = value;
1242
- return key;
1243
- });
1244
- try {
1245
- return await loadDocsConfigModule(rootDir, explicitPath);
1246
- } finally {
1247
- for (const key of injectedKeys) delete process.env[key];
1248
- }
1249
- }
1250
1315
  function makeCheck(id, title, status, score, maxScore, detail, recommendation) {
1251
1316
  return {
1252
1317
  id,
@@ -1294,8 +1359,8 @@ async function inspectAgentReadiness(options = {}) {
1294
1359
  };
1295
1360
  }
1296
1361
  const configContent = readFileSync(configPath, "utf-8");
1297
- const loadedConfig = await loadDocsConfigModuleWithProjectEnv(rootDir, options.configPath);
1298
- const config = loadedConfig?.config;
1362
+ const configLoad = await loadDocsConfigModuleResultWithProjectEnv(rootDir, options.configPath);
1363
+ const config = configLoad.status === "evaluated" ? configLoad.config : void 0;
1299
1364
  const entry = config?.entry ?? readTopLevelStringProperty(configContent, "entry") ?? "docs";
1300
1365
  const contentDir = config?.contentDir ?? resolveDocsContentDir(rootDir, configContent, entry);
1301
1366
  const ordering = config?.ordering === "alphabetical" || config?.ordering === "numeric" || Array.isArray(config?.ordering) ? config.ordering : void 0;
@@ -1317,11 +1382,24 @@ async function inspectAgentReadiness(options = {}) {
1317
1382
  });
1318
1383
  const pages = await Promise.resolve(source.getPages());
1319
1384
  const coverage = buildCoverage(pages);
1385
+ const usefulness = analyzeAgentUsefulness({
1386
+ rootDir,
1387
+ pages: createAgentUsefulnessPagesFromMcp(rootDir, pages),
1388
+ projectFramework: framework === "unknown" ? void 0 : framework
1389
+ });
1390
+ const evaluationInput = config?.agent?.evaluations;
1391
+ const evaluations = await runDocsGoldenTasks(pages, resolveGoldenEvaluationTasks(evaluationInput));
1320
1392
  const compactionCoverage = buildCompactionCoverage(rootDir, contentDir, entry, pages, config?.agent?.compact ?? {});
1321
1393
  coverage.compaction = compactionCoverage;
1322
1394
  const metadataCoverage = buildMetadataCoverage(pages);
1323
1395
  const metadataResult = metadataScore(metadataCoverage.descriptionCoverage, metadataCoverage.relatedCoverage);
1324
1396
  const compactionResult = compactionFreshnessScore(compactionCoverage, compactConfigured);
1397
+ const contextQualityResult = scoreUsefulnessCoverage(usefulness.metrics.agentBlocks.useful, usefulness.metrics.agentBlocks.total, 15);
1398
+ const taskCompletenessResult = scoreUsefulnessCoverage(usefulness.metrics.taskCompleteness.completePages, usefulness.metrics.actionablePages, 15);
1399
+ const applicabilityIssueCount = usefulness.metrics.applicability.conflictingPages + usefulness.metrics.applicability.ambiguousPages + usefulness.metrics.applicability.mismatchedPages;
1400
+ const applicabilityResult = scoreUsefulnessCoverage(Math.max(0, usefulness.metrics.actionablePages - applicabilityIssueCount), usefulness.metrics.actionablePages, 10);
1401
+ const commandHealthResult = scoreUsefulnessCoverage(usefulness.metrics.commands.healthy, usefulness.metrics.commands.total, 10);
1402
+ const relatedCoverageResult = scoreUsefulnessCoverage(usefulness.metrics.related.coveredActionablePages, usefulness.metrics.actionablePages, 5);
1325
1403
  const routeSurface = detectRouteSurface(rootDir, framework, staticExport, files);
1326
1404
  const mcpConfig = resolveDocsMcpConfig(config?.mcp ?? void 0, { defaultName: siteTitle });
1327
1405
  const sitemapConfig = resolveDocsSitemapConfig(config?.sitemap ?? readSitemapConfigFromStatic(configContent) ?? true);
@@ -1330,8 +1408,47 @@ async function inspectAgentReadiness(options = {}) {
1330
1408
  const robotsPath = resolveRobotsFilePath(rootDir, framework, typeof robotsInput === "object" ? robotsInput : void 0);
1331
1409
  const feedbackRoute = DEFAULT_AGENT_FEEDBACK_ROUTE;
1332
1410
  const feedbackSchemaRoute = `${feedbackRoute}/schema`;
1411
+ const discovery = buildDocsAgentDiscoverySpec({
1412
+ origin: "http://localhost",
1413
+ entry,
1414
+ search: searchEnabled,
1415
+ mcp: mcpConfig,
1416
+ feedback: {
1417
+ enabled: agentFeedbackEnabled,
1418
+ route: feedbackRoute,
1419
+ schemaRoute: feedbackSchemaRoute
1420
+ }
1421
+ });
1422
+ const configuredAgentReviewPaths = configLoad.status === "evaluated" ? Object.values(buildDocsConfigMap(configLoad.config).pointers).map((pointer) => pointer.path).filter((optionPath) => optionPath === "agent" || optionPath.startsWith("agent.") || optionPath === "review" || optionPath.startsWith("review.")) : [];
1423
+ const surfaceDrift = analyzeAgentSurfaceDrift({
1424
+ configOptionPaths: [...new Set([...DOCS_CONFIG_MAP_TOP_LEVEL_KEYS, ...configuredAgentReviewPaths])],
1425
+ schemaOptions: getDocsConfigSchema().options,
1426
+ agentContractFields: PAGE_AGENT_CONTRACT_FIELDS,
1427
+ discovery,
1428
+ expected: {
1429
+ entry,
1430
+ search: {
1431
+ enabled: searchEnabled,
1432
+ endpoint: `${DEFAULT_DOCS_API_ROUTE}?query={query}`
1433
+ },
1434
+ mcp: {
1435
+ enabled: mcpConfig.enabled,
1436
+ endpoint: mcpConfig.route,
1437
+ tools: mcpConfig.tools
1438
+ },
1439
+ routes: {
1440
+ "api.docs": DEFAULT_DOCS_API_ROUTE,
1441
+ "api.config": DEFAULT_DOCS_CONFIG_ROUTE,
1442
+ "config.endpoint": DEFAULT_DOCS_CONFIG_ROUTE
1443
+ }
1444
+ }
1445
+ });
1333
1446
  const checks = [];
1334
- checks.push(makeCheck("config", "Docs config", "pass", 10, configCheckMax, loadedConfig ? `Resolved ${path.relative(rootDir, loadedConfig.path).replace(/\\/g, "/")} and evaluated the config module.` : `Resolved ${path.relative(rootDir, configPath).replace(/\\/g, "/")} using static parsing fallback.`));
1447
+ checks.push(makeCheck("config", "Docs config", configLoad.status === "evaluated" ? "pass" : "warn", configLoad.status === "evaluated" ? 10 : 2, configCheckMax, configLoad.status === "evaluated" ? `Resolved ${path.relative(rootDir, configLoad.path).replace(/\\/g, "/")} and evaluated the config module.` : `Resolved ${path.relative(rootDir, configPath).replace(/\\/g, "/")} using static parsing fallback.`, configLoad.status === "evaluated" ? void 0 : "Fix docs.config module evaluation before relying on resolved diagnostic scores."));
1448
+ const canScoreSurfaceDrift = configLoad.status === "evaluated";
1449
+ checks.push(makeCheck("surface-drift", "Discovery/config/schema consistency", !canScoreSurfaceDrift ? "warn" : surfaceDrift.length === 0 ? "pass" : "fail", !canScoreSurfaceDrift ? 0 : surfaceDrift.length === 0 ? 10 : Math.max(0, 10 - surfaceDrift.length * 2), 10, !canScoreSurfaceDrift ? "Not scored because docs.config could not be evaluated; static parsing cannot prove discovery/config/schema consistency." : surfaceDrift.length === 0 ? "Resolved config, discovery metadata, MCP tool flags, config schema, and agent contract fields agree." : surfaceDrift.slice(0, 3).map((issue) => issue.message).join(" "), canScoreSurfaceDrift && surfaceDrift.length === 0 ? void 0 : canScoreSurfaceDrift ? "Align docs config, agent discovery, MCP tools, config schema, and the canonical page agent contract before publishing." : "Fix docs.config module evaluation so doctor can compare resolved config with discovery and schema surfaces."));
1450
+ const dynamicStaticFallback = configLoad.status === "static-fallback" && /(?:\.\.\.|process\.env|import\.meta\.env|\[[^\]]+\]\s*:|:\s*[A-Za-z_$][\w$]*\s*[,}])/u.test(configContent);
1451
+ checks.push(configLoad.status === "evaluated" ? makeCheck("config-confidence", "Config loading confidence", "pass", 5, 5, "High confidence: docs.config was evaluated with project-local environment values.") : makeCheck("config-confidence", "Config loading confidence", "warn", dynamicStaticFallback ? 1 : 2, 5, `${dynamicStaticFallback ? "Low" : "Partial"} confidence: only static config parsing succeeded. ${configLoad.error}`, "Fix docs.config module evaluation so doctor and review can inspect dynamic values, golden tasks, and resolved feature settings."));
1335
1452
  const contentDirAbs = path.resolve(rootDir, contentDir);
1336
1453
  checks.push(coverage.totalPages > 0 ? makeCheck("content", "Docs content", "pass", 10, 10, `Found ${coverage.totalPages} docs page${coverage.totalPages === 1 ? "" : "s"} in ${path.relative(rootDir, contentDirAbs).replace(/\\/g, "/")}.`) : makeCheck("content", "Docs content", "fail", 0, 10, `No folder-based docs pages were found in ${path.relative(rootDir, contentDirAbs).replace(/\\/g, "/")}.`, "Add index/page MDX files under the configured contentDir so the machine-readable surfaces have pages to serve."));
1337
1454
  checks.push(makeCheck("api-route", "Docs API route", routeSurface.apiMounted ? "pass" : "fail", routeSurface.apiMounted ? 10 : 0, 10, routeSurface.apiDetail, routeSurface.apiMounted ? void 0 : "Wire the framework docs API route so /api/docs can serve markdown, llms.txt, sitemap, AGENTS.md, skill.md, and discovery responses."));
@@ -1367,7 +1484,16 @@ async function inspectAgentReadiness(options = {}) {
1367
1484
  checks.push(makeCheck("metadata", "Page metadata", metadataResult.status, metadataResult.score, 5, coverage.totalPages > 0 ? `${metadataCoverage.describedPages}/${coverage.totalPages} pages include descriptions and ${metadataCoverage.relatedPages}/${coverage.totalPages} pages include related links (${metadataCoverage.descriptionCoverage}% described, ${metadataCoverage.relatedCoverage}% related).` : "No docs pages were available to score page metadata.", metadataCoverage.descriptionCoverage >= 75 ? void 0 : "Add page descriptions and related links to more docs pages so agent markdown output carries better context and navigation hints."));
1368
1485
  const coverageResult = coverageScore(coverage.explicitCoverage);
1369
1486
  checks.push(makeCheck("coverage", "Explicit page optimization", coverageResult.status, coverageResult.score, 10, coverage.totalPages > 0 ? `${coverage.explicitPages}/${coverage.totalPages} pages define explicit machine-only context (${coverage.pagesWithAgentFiles} agent.md, ${coverage.pagesWithAgentBlocks} Agent blocks, ${coverage.explicitCoverage}% of pages).` : "No docs pages were available to score explicit page optimization.", coverage.explicitCoverage >= 50 ? void 0 : "Add agent.md files or <Agent> blocks to more pages, or run docs agent compact to create page-level machine docs."));
1487
+ checks.push(makeCheck("agent-context-quality", "Agent context usefulness", contextQualityResult.status, contextQualityResult.score, 15, usefulness.metrics.agentBlocks.total > 0 ? `${usefulness.metrics.agentBlocks.useful}/${usefulness.metrics.agentBlocks.total} Agent blocks are specific and non-repetitive (${usefulness.metrics.agentBlocks.duplicate} duplicate, ${usefulness.metrics.agentBlocks.boilerplate} boilerplate, ${usefulness.metrics.agentBlocks.generic} generic).` : "No embedded Agent blocks were present; page contracts and sibling agent.md files remain available as alternatives.", usefulness.metrics.agentBlocks.total > 0 && usefulness.metrics.agentBlocks.useful === usefulness.metrics.agentBlocks.total ? void 0 : "Replace repeated Agent boilerplate with page-specific constraints, commands, files, expected results, and recovery guidance."));
1488
+ checks.push(makeCheck("agent-task-completeness", "Agent task completeness", taskCompletenessResult.status, taskCompletenessResult.score, 15, `${usefulness.metrics.taskCompleteness.completePages}/${usefulness.metrics.actionablePages} actionable pages include prerequisites, an expected result, and recovery guidance (${usefulness.metrics.taskCompleteness.coverage}% complete).`, usefulness.metrics.actionablePages > 0 && usefulness.metrics.taskCompleteness.coverage >= 80 ? void 0 : "Add prerequisites, observable outcomes or verification expectations, and rollback or resolved failure modes to actionable pages."));
1489
+ checks.push(makeCheck("agent-applicability", "Framework and version applicability", applicabilityResult.status, applicabilityResult.score, 10, `${usefulness.metrics.applicability.conflictingPages} conflicting, ${usefulness.metrics.applicability.ambiguousPages} ambiguous, and ${usefulness.metrics.applicability.mismatchedPages} project-mismatched actionable pages.`, usefulness.metrics.actionablePages > 0 && applicabilityIssueCount === 0 ? void 0 : "Declare consistent framework/version metadata in page frontmatter and agent.appliesTo so retrieval can select the right variant."));
1490
+ checks.push(makeCheck("command-health", "Documented command health", commandHealthResult.status, commandHealthResult.score, 10, `${usefulness.metrics.commands.healthy}/${usefulness.metrics.commands.total} statically inspected commands are healthy; ${usefulness.metrics.commands.unhealthy} are unhealthy and ${usefulness.metrics.commands.unverified} could not be verified safely.`, usefulness.metrics.commands.total > 0 && usefulness.metrics.commands.unhealthy === 0 && usefulness.metrics.commands.unverified === 0 ? void 0 : "Update broken or stale commands and make workspace selectors resolvable so scripts, working directories, package managers, and docs CLI subcommands can be verified."));
1491
+ checks.push(makeCheck("related-coverage", "Related-page task coverage", relatedCoverageResult.status, relatedCoverageResult.score, 5, `${usefulness.metrics.related.coveredActionablePages}/${usefulness.metrics.actionablePages} actionable pages link to a valid related docs route; ${usefulness.metrics.related.brokenLinks} related links are broken.`, usefulness.metrics.actionablePages > 0 && usefulness.metrics.related.coverage >= 80 && usefulness.metrics.related.brokenLinks === 0 ? void 0 : "Add and validate related routes on actionable pages so agents can expand context without guessing."));
1370
1492
  checks.push(makeCheck("compact", "Agent compaction freshness", compactionResult.status, compactionResult.score, 5, `${compactionCoverage.freshGeneratedPages} fresh, ${compactionCoverage.staleGeneratedPages} stale, ${compactionCoverage.modifiedGeneratedPages} modified, ${compactionCoverage.unknownGeneratedPages} unknown, ${compactionCoverage.tokenBudgetMissingPages} token-budget missing, and ${compactionCoverage.otherMissingPages} other missing page${compactionCoverage.otherMissingPages === 1 ? "" : "s"} across compactable docs pages.` + (compactConfigured ? " agent.compact defaults are configured." : " No agent.compact defaults were found in docs config."), compactionResult.recommendation));
1493
+ const averageMetric = (values) => values.length === 0 ? 0 : Math.round(values.reduce((total, value) => total + value, 0) / values.length * 100) / 100;
1494
+ const proportionalEvaluationScore = evaluations.score === null ? 0 : Math.round(evaluations.score / 100 * 15);
1495
+ const evaluationScore = evaluations.status === "failed" ? Math.min(14, proportionalEvaluationScore) : proportionalEvaluationScore;
1496
+ checks.push(makeCheck("golden-tasks", "Golden agent tasks", evaluations.status === "passed" ? "pass" : evaluations.status === "failed" ? "fail" : "warn", evaluationScore, 15, evaluations.status === "unmeasured" ? "No golden agent tasks are configured; retrieval usefulness is unmeasured." : `${evaluations.passedTaskCount}/${evaluations.taskCount} golden tasks passed with ${evaluations.score}/100 average score, ${averageMetric(evaluations.tasks.map((task) => task.retrieval.recallAtK))} retrieval recall, ${averageMetric(evaluations.tasks.map((task) => task.citations.recall))} citation recall, and ${evaluations.tasks.reduce((total, task) => total + task.usage.usedUtf8Bytes, 0)} UTF-8 context bytes used.`, evaluations.status === "passed" ? void 0 : evaluations.status === "unmeasured" ? "Configure agent.evaluations.tasks so doctor and review can measure retrieval, citations, framework/version selection, executable examples, and token usage." : "Inspect the failed golden task metrics and fix retrieval ranking, citations, applicability metadata, examples, or context budgets."));
1371
1497
  const hosted = options.url ? await buildHostedAgentChecks(options.url, pages) : void 0;
1372
1498
  if (hosted) checks.push(...hosted.checks);
1373
1499
  const { score, maxScore } = normalizedDoctorScore(checks.reduce((total, check) => total + check.score, 0), checks.reduce((total, check) => total + check.maxScore, 0));
@@ -1380,9 +1506,11 @@ async function inspectAgentReadiness(options = {}) {
1380
1506
  url: hosted?.baseUrl,
1381
1507
  score,
1382
1508
  maxScore,
1383
- grade: gradeForAgentScore(score),
1509
+ grade: gradeForAgentScore(score, checks),
1384
1510
  checks,
1385
1511
  coverage,
1512
+ usefulness: usefulness.metrics,
1513
+ evaluations,
1386
1514
  recommendations: checks.map((check) => check.recommendation).filter((recommendation) => Boolean(recommendation)).slice(0, 3)
1387
1515
  };
1388
1516
  }
@@ -1416,8 +1544,8 @@ async function inspectHumanReadiness(options = {}) {
1416
1544
  };
1417
1545
  }
1418
1546
  const configContent = readFileSync(configPath, "utf-8");
1419
- const loadedConfig = await loadDocsConfigModuleWithProjectEnv(rootDir, options.configPath);
1420
- const config = loadedConfig?.config;
1547
+ const configLoad = await loadDocsConfigModuleResultWithProjectEnv(rootDir, options.configPath);
1548
+ const config = configLoad.status === "evaluated" ? configLoad.config : void 0;
1421
1549
  const entry = config?.entry ?? readTopLevelStringProperty(configContent, "entry") ?? "docs";
1422
1550
  const contentDir = config?.contentDir ?? resolveDocsContentDir(rootDir, configContent, entry);
1423
1551
  const ordering = config?.ordering === "alphabetical" || config?.ordering === "numeric" || Array.isArray(config?.ordering) ? config.ordering : void 0;
@@ -1440,7 +1568,7 @@ async function inspectHumanReadiness(options = {}) {
1440
1568
  const navigationCoverage = coverage.totalPages === 0 ? 0 : Math.min(100, Math.round(coverage.navigationPages / coverage.totalPages * 100));
1441
1569
  const navigationResult = navigationScore(navigationCoverage);
1442
1570
  const checks = [];
1443
- checks.push(makeCheck("config", "Docs config", "pass", 10, 10, loadedConfig ? `Resolved ${path.relative(rootDir, loadedConfig.path).replace(/\\/g, "/")} and evaluated the config module.` : `Resolved ${path.relative(rootDir, configPath).replace(/\\/g, "/")} using static parsing fallback.`));
1571
+ checks.push(makeCheck("config", "Docs config", configLoad.status === "evaluated" ? "pass" : "warn", configLoad.status === "evaluated" ? 10 : 2, 10, configLoad.status === "evaluated" ? `Resolved ${path.relative(rootDir, configLoad.path).replace(/\\/g, "/")} and evaluated the config module.` : `Resolved ${path.relative(rootDir, configPath).replace(/\\/g, "/")} using static parsing fallback. ${configLoad.error}`, configLoad.status === "evaluated" ? void 0 : "Fix docs.config module evaluation so the site score uses resolved dynamic configuration."));
1444
1572
  const contentDirAbs = path.resolve(rootDir, contentDir);
1445
1573
  checks.push(coverage.totalPages > 0 ? makeCheck("content", "Docs content", "pass", 15, 15, `Found ${coverage.totalPages} docs page${coverage.totalPages === 1 ? "" : "s"} in ${path.relative(rootDir, contentDirAbs).replace(/\\/g, "/")}.`) : makeCheck("content", "Docs content", "fail", 0, 15, `No folder-based docs pages were found in ${path.relative(rootDir, contentDirAbs).replace(/\\/g, "/")}.`, "Add index/page MDX files under the configured contentDir so the human docs site has pages to render."));
1446
1574
  checks.push(makeCheck("navigation", "Navigation coverage", navigationResult.status, navigationResult.score, 15, coverage.totalPages > 0 ? `The generated docs navigation exposes ${coverage.navigationPages}/${coverage.totalPages} page entries (${navigationCoverage}% coverage).` : "No docs pages were available to score navigation coverage.", navigationCoverage >= 100 ? void 0 : "Make sure every important docs page is reachable from the generated navigation tree and not stranded outside the main docs flow."));
@@ -1473,6 +1601,8 @@ function printAgentDoctorReport(report) {
1473
1601
  console.log(`${pc.bold("Framework:")} ${report.framework} ${pc.dim("•")} ${pc.bold("Entry:")} ${report.entry ?? "docs"} ${pc.dim("•")} ${pc.bold("Content:")} ${report.contentDir ?? "-"}`);
1474
1602
  if (report.url) console.log(`${pc.bold("Hosted URL:")} ${report.url}`);
1475
1603
  console.log(`${pc.bold("Explicit agent-friendly pages:")} ${report.coverage.explicitPages}/${report.coverage.totalPages} pages ${pc.dim(`(${report.coverage.explicitCoverage}%)`)}`);
1604
+ if (report.usefulness) console.log(`${pc.bold("Useful Agent blocks:")} ${report.usefulness.agentBlocks.useful}/${report.usefulness.agentBlocks.total} ${pc.dim(`• ${report.usefulness.taskCompleteness.completePages}/${report.usefulness.actionablePages} actionable pages task-complete`)}`);
1605
+ if (report.evaluations) console.log(`${pc.bold("Golden tasks:")} ${report.evaluations.status === "unmeasured" ? "unmeasured" : `${report.evaluations.passedTaskCount}/${report.evaluations.taskCount} passed (${report.evaluations.score}/100)`}`);
1476
1606
  console.log(`${pc.bold("Generated agent.md freshness:")} ${report.coverage.compaction.freshGeneratedPages} fresh ${pc.dim("•")} ${report.coverage.compaction.staleGeneratedPages} stale ${pc.dim("•")} ${report.coverage.compaction.modifiedGeneratedPages} modified ${pc.dim("•")} ${report.coverage.compaction.tokenBudgetMissingPages} token-budget missing`);
1477
1607
  if (report.fixes && report.fixes.length > 0) console.log(`${pc.bold("Fixes:")} ${report.fixes.map((fix) => `${fix.status === "applied" ? "applied" : "skipped"} ${fix.title}`).join(pc.dim(" • "))}`);
1478
1608
  console.log();
@@ -1,5 +1,5 @@
1
- import { c as fileExists, o as exec, s as execOutput } from "./utils-D-xTRNuh.mjs";
2
- import { a as getPackagesForFramework, c as resolveDocsPackageManager, l as validateUpgradeVersion, r as buildDocsPackageInstallCommand, s as resolveDocsPackageFramework } from "./package-version-C8PigBZk.mjs";
1
+ import { c as fileExists, o as exec, s as execOutput } from "./utils-DBCCkkJS.mjs";
2
+ import { a as getPackagesForFramework, c as resolveDocsPackageManager, l as validateUpgradeVersion, r as buildDocsPackageInstallCommand, s as resolveDocsPackageFramework } from "./package-version-DRIc08EU.mjs";
3
3
  import fs from "node:fs";
4
4
  import path from "node:path";
5
5
  import pc from "picocolors";
@@ -0,0 +1,40 @@
1
+ //#region src/i18n.ts
2
+ function normalizeSegment(value) {
3
+ return value.replace(/^\/+|\/+$/g, "");
4
+ }
5
+ function splitSegments(value) {
6
+ const cleaned = normalizeSegment(value);
7
+ return cleaned ? cleaned.split("/").filter(Boolean) : [];
8
+ }
9
+ function resolveDocsI18n(config) {
10
+ if (!config || !Array.isArray(config.locales)) return null;
11
+ const locales = Array.from(new Set(config.locales.map((l) => l.trim()).filter(Boolean)));
12
+ if (locales.length === 0) return null;
13
+ return {
14
+ locales,
15
+ defaultLocale: config.defaultLocale && locales.includes(config.defaultLocale) ? config.defaultLocale : locales[0]
16
+ };
17
+ }
18
+ function resolveDocsLocale(searchParams, i18n) {
19
+ if (!i18n) return void 0;
20
+ const raw = searchParams.get("lang") ?? searchParams.get("locale");
21
+ if (!raw) return void 0;
22
+ if (i18n.locales.includes(raw)) return raw;
23
+ return i18n.defaultLocale;
24
+ }
25
+ function resolveDocsPath(pathname, entry) {
26
+ const entryBase = normalizeSegment(entry || "docs") || "docs";
27
+ const entryParts = splitSegments(entryBase);
28
+ const pathParts = splitSegments(pathname);
29
+ let rest = pathParts;
30
+ if (entryParts.length > 0) {
31
+ if (pathParts.slice(0, entryParts.length).join("/") === entryParts.join("/")) rest = pathParts.slice(entryParts.length);
32
+ }
33
+ return {
34
+ slug: rest.join("/"),
35
+ entryPath: entryBase
36
+ };
37
+ }
38
+
39
+ //#endregion
40
+ export { resolveDocsLocale as n, resolveDocsPath as r, resolveDocsI18n as t };