@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.
- package/dist/agent-BXvi0uhS.mjs +623 -0
- package/dist/{agent-CaOBIVFy.mjs → agent-DXkXi-pS.mjs} +765 -22
- package/dist/agent-evals-BD17jOqL.mjs +1166 -0
- package/dist/agent-export-n-a0GbeU.mjs +854 -0
- package/dist/agent-scope-B8lptqCd.mjs +283 -0
- package/dist/agent-surface-drift-LS8zQgbq.mjs +1429 -0
- package/dist/{agents-DjhjZaNP.mjs → agents-BJaRQimo.mjs} +7 -5
- package/dist/{analytics-BZEwTK-8.mjs → analytics-Bx44lg6d.mjs} +1 -1
- package/dist/cli/index.mjs +43 -28
- package/dist/client/react.d.mts +1 -1
- package/dist/client/react.mjs +1 -1
- package/dist/{cloud-C_Ok9rC5.mjs → cloud-HWFlbfLJ.mjs} +4 -4
- package/dist/{cloud-ask-ai-Cl-xaV8j.mjs → cloud-ask-ai-1k0q6OAH.mjs} +1 -1
- package/dist/{cloud-ask-ai-DcMe6xOf.d.mts → cloud-ask-ai-466g6uAi.d.mts} +1 -1
- package/dist/code-blocks-C9awWzEQ.mjs +871 -0
- package/dist/codeblocks-BzfkREEC.mjs +250 -0
- package/dist/{config-tiQCZ46q.mjs → config-CydaZ5PB.mjs} +52 -11
- package/dist/{dev-Tm9Ss4D6.mjs → dev-BA2kRuCn.mjs} +3 -3
- package/dist/docs-cloud-server.d.mts +2 -2
- package/dist/docs-cloud-server.mjs +2 -2
- package/dist/{doctor-O9o9kjN8.mjs → doctor-CQpQ2zZm.mjs} +177 -47
- package/dist/{downgrade-CYEaOctn.mjs → downgrade-BStNhyCc.mjs} +2 -2
- package/dist/i18n-CAlj1ADU.mjs +40 -0
- package/dist/index.d.mts +158 -3
- package/dist/index.mjs +7 -6
- package/dist/{init-Ch5On0zm.mjs → init-gnHQ_Pz9.mjs} +3 -3
- package/dist/{mcp-DuCPNHS-.mjs → mcp-DnxZZWpY.mjs} +10 -5
- package/dist/mcp.d.mts +122 -6
- package/dist/mcp.mjs +1943 -86
- package/dist/{package-version-C8PigBZk.mjs → package-version-DRIc08EU.mjs} +1 -1
- package/dist/{reading-time-CPAy1SWO.mjs → reading-time-BrTd3DIh.mjs} +277 -33
- package/dist/{review-lm3dt7yy.mjs → review-B6gyEFkD.mjs} +184 -14
- package/dist/{robots-DV7u4Ire.mjs → robots-4BUJxlvV.mjs} +4 -4
- package/dist/{robots-XVPs9lVz.mjs → robots-DAptQnkx.mjs} +1 -1
- package/dist/{search-BWuU70B0.mjs → search-CJIC1Cqo.mjs} +173 -79
- package/dist/{search-B6nEkx86.mjs → search-CbPm2x5g.mjs} +6 -4
- package/dist/{search-DFEhf9-s.d.mts → search-CfWvmVYA.d.mts} +3 -1
- package/dist/server.d.mts +108 -5
- package/dist/server.mjs +9 -8
- package/dist/{sitemap-BEiKy4Iy.mjs → sitemap-D6nP3J1Q.mjs} +8 -6
- package/dist/{sitemap-server-xEHtDUDB.mjs → sitemap-server-wsNLyVkb.mjs} +1 -1
- package/dist/{templates-uaauJcTO.mjs → templates-1Cod8KrJ.mjs} +11 -5
- package/dist/{types-XqGLsmOD.d.mts → types-BVgucdVm.d.mts} +194 -2
- package/dist/{upgrade-DzQtpgJM.mjs → upgrade-CXYRNV0C.mjs} +2 -2
- package/package.json +1 -1
- package/dist/agent-DXDOMJBw.mjs +0 -9
- package/dist/codeblocks-z9iT794h.mjs +0 -1713
- package/dist/review-B7goPYUb.mjs +0 -541
- /package/dist/{cloud-analytics-Dlk_byos.mjs → cloud-analytics-CSyFE6SS.mjs} +0 -0
- /package/dist/{errors-CW1LnxaQ.mjs → errors-BFUtdZfC.mjs} +0 -0
- /package/dist/{utils-D-xTRNuh.mjs → utils-DBCCkkJS.mjs} +0 -0
|
@@ -1,13 +1,16 @@
|
|
|
1
|
-
import "./
|
|
2
|
-
import
|
|
3
|
-
import "./
|
|
4
|
-
import
|
|
5
|
-
import "./
|
|
6
|
-
import
|
|
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
|
|
9
|
-
import { t as detectFramework } from "./utils-
|
|
10
|
-
import { n as
|
|
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
|
-
|
|
587
|
-
|
|
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
|
-
|
|
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
|
-
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
|
|
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
|
|
1298
|
-
const 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,
|
|
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
|
|
1420
|
-
const 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,
|
|
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-
|
|
2
|
-
import { a as getPackagesForFramework, c as resolveDocsPackageManager, l as validateUpgradeVersion, r as buildDocsPackageInstallCommand, s as resolveDocsPackageFramework } from "./package-version-
|
|
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 };
|